gh-106706: Streamline family syntax in cases generator DSL (#106716)

From `family(opname, STRUCTSIZE) = OPNAME + SPEC1 + ... +  SPECn;`
to `family(OPNAME, STRUCTSIZE) = SPEC1 + ... + SPECn;`
This commit is contained in:
Kevin Diem 2023-07-16 11:16:34 -04:00 committed by GitHub
parent e58960160f
commit cc25ca16ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 42 deletions

View File

@ -0,0 +1,3 @@
Change bytecode syntax for families
to remove redundant name matching
pseudo syntax.

View File

@ -284,8 +284,7 @@ dummy_func(
res = Py_IsFalse(value) ? Py_True : Py_False; res = Py_IsFalse(value) ? Py_True : Py_False;
} }
family(to_bool, INLINE_CACHE_ENTRIES_TO_BOOL) = { family(TO_BOOL, INLINE_CACHE_ENTRIES_TO_BOOL) = {
TO_BOOL,
TO_BOOL_ALWAYS_TRUE, TO_BOOL_ALWAYS_TRUE,
TO_BOOL_BOOL, TO_BOOL_BOOL,
TO_BOOL_INT, TO_BOOL_INT,
@ -372,8 +371,7 @@ dummy_func(
ERROR_IF(res == NULL, error); ERROR_IF(res == NULL, error);
} }
family(binary_op, INLINE_CACHE_ENTRIES_BINARY_OP) = { family(BINARY_OP, INLINE_CACHE_ENTRIES_BINARY_OP) = {
BINARY_OP,
BINARY_OP_MULTIPLY_INT, BINARY_OP_MULTIPLY_INT,
BINARY_OP_ADD_INT, BINARY_OP_ADD_INT,
BINARY_OP_SUBTRACT_INT, BINARY_OP_SUBTRACT_INT,
@ -507,8 +505,7 @@ dummy_func(
macro(BINARY_OP_INPLACE_ADD_UNICODE) = macro(BINARY_OP_INPLACE_ADD_UNICODE) =
_GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE; _GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE;
family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = {
BINARY_SUBSCR,
BINARY_SUBSCR_DICT, BINARY_SUBSCR_DICT,
BINARY_SUBSCR_GETITEM, BINARY_SUBSCR_GETITEM,
BINARY_SUBSCR_LIST_INT, BINARY_SUBSCR_LIST_INT,
@ -643,8 +640,7 @@ dummy_func(
ERROR_IF(err, error); ERROR_IF(err, error);
} }
family(store_subscr, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = { family(STORE_SUBSCR, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = {
STORE_SUBSCR,
STORE_SUBSCR_DICT, STORE_SUBSCR_DICT,
STORE_SUBSCR_LIST_INT, STORE_SUBSCR_LIST_INT,
}; };
@ -921,8 +917,7 @@ dummy_func(
ERROR_IF(iter == NULL, error); ERROR_IF(iter == NULL, error);
} }
family(send, INLINE_CACHE_ENTRIES_SEND) = { family(SEND, INLINE_CACHE_ENTRIES_SEND) = {
SEND,
SEND_GEN, SEND_GEN,
}; };
@ -1134,8 +1129,7 @@ dummy_func(
} }
} }
family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { family(UNPACK_SEQUENCE, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = {
UNPACK_SEQUENCE,
UNPACK_SEQUENCE_TWO_TUPLE, UNPACK_SEQUENCE_TWO_TUPLE,
UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_TUPLE,
UNPACK_SEQUENCE_LIST, UNPACK_SEQUENCE_LIST,
@ -1198,8 +1192,7 @@ dummy_func(
ERROR_IF(res == 0, error); ERROR_IF(res == 0, error);
} }
family(store_attr, INLINE_CACHE_ENTRIES_STORE_ATTR) = { family(STORE_ATTR, INLINE_CACHE_ENTRIES_STORE_ATTR) = {
STORE_ATTR,
STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_INSTANCE_VALUE,
STORE_ATTR_SLOT, STORE_ATTR_SLOT,
STORE_ATTR_WITH_HINT, STORE_ATTR_WITH_HINT,
@ -1298,8 +1291,7 @@ dummy_func(
macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS; macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS;
family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { family(LOAD_GLOBAL, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = {
LOAD_GLOBAL,
LOAD_GLOBAL_MODULE, LOAD_GLOBAL_MODULE,
LOAD_GLOBAL_BUILTIN, LOAD_GLOBAL_BUILTIN,
}; };
@ -1647,8 +1639,7 @@ dummy_func(
GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR);
} }
family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { family(LOAD_SUPER_ATTR, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = {
LOAD_SUPER_ATTR,
LOAD_SUPER_ATTR_ATTR, LOAD_SUPER_ATTR_ATTR,
LOAD_SUPER_ATTR_METHOD, LOAD_SUPER_ATTR_METHOD,
}; };
@ -1750,8 +1741,7 @@ dummy_func(
} }
} }
family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { family(LOAD_ATTR, INLINE_CACHE_ENTRIES_LOAD_ATTR) = {
LOAD_ATTR,
LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_INSTANCE_VALUE,
LOAD_ATTR_MODULE, LOAD_ATTR_MODULE,
LOAD_ATTR_WITH_HINT, LOAD_ATTR_WITH_HINT,
@ -2048,8 +2038,7 @@ dummy_func(
Py_DECREF(owner); Py_DECREF(owner);
} }
family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = {
COMPARE_OP,
COMPARE_OP_FLOAT, COMPARE_OP_FLOAT,
COMPARE_OP_INT, COMPARE_OP_INT,
COMPARE_OP_STR, COMPARE_OP_STR,
@ -2350,8 +2339,7 @@ dummy_func(
// This is optimized by skipping that instruction and combining // This is optimized by skipping that instruction and combining
// its effect (popping 'iter' instead of pushing 'next'.) // its effect (popping 'iter' instead of pushing 'next'.)
family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { family(FOR_ITER, INLINE_CACHE_ENTRIES_FOR_ITER) = {
FOR_ITER,
FOR_ITER_LIST, FOR_ITER_LIST,
FOR_ITER_TUPLE, FOR_ITER_TUPLE,
FOR_ITER_RANGE, FOR_ITER_RANGE,
@ -2810,8 +2798,7 @@ dummy_func(
// Cache layout: counter/1, func_version/2 // Cache layout: counter/1, func_version/2
// Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members!
family(call, INLINE_CACHE_ENTRIES_CALL) = { family(CALL, INLINE_CACHE_ENTRIES_CALL) = {
CALL,
CALL_BOUND_METHOD_EXACT_ARGS, CALL_BOUND_METHOD_EXACT_ARGS,
CALL_PY_EXACT_ARGS, CALL_PY_EXACT_ARGS,
CALL_PY_WITH_DEFAULTS, CALL_PY_WITH_DEFAULTS,

View File

@ -438,7 +438,7 @@ def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None:
"""Write one instruction, sans prologue and epilogue.""" """Write one instruction, sans prologue and epilogue."""
# Write a static assertion that a family's cache size is correct # Write a static assertion that a family's cache size is correct
if family := self.family: if family := self.family:
if self.name == family.members[0]: if self.name == family.name:
if cache_size := family.size: if cache_size := family.size:
out.emit( out.emit(
f"static_assert({cache_size} == " f"static_assert({cache_size} == "
@ -831,7 +831,7 @@ def find_predictions(self) -> None:
def map_families(self) -> None: def map_families(self) -> None:
"""Link instruction names back to their family, if they have one.""" """Link instruction names back to their family, if they have one."""
for family in self.families.values(): for family in self.families.values():
for member in family.members: for member in [family.name] + family.members:
if member_instr := self.instrs.get(member): if member_instr := self.instrs.get(member):
if member_instr.family not in (family, None): if member_instr.family not in (family, None):
self.error( self.error(
@ -855,8 +855,11 @@ def check_families(self) -> None:
- All members must have the same cache, input and output effects - All members must have the same cache, input and output effects
""" """
for family in self.families.values(): for family in self.families.values():
if len(family.members) < 2: if family.name not in self.macro_instrs and family.name not in self.instrs:
self.error(f"Family {family.name!r} has insufficient members", family) self.error(
f"Family {family.name!r} has unknown instruction {family.name!r}",
family,
)
members = [ members = [
member member
for member in family.members for member in family.members
@ -867,10 +870,8 @@ def check_families(self) -> None:
self.error( self.error(
f"Family {family.name!r} has unknown members: {unknown}", family f"Family {family.name!r} has unknown members: {unknown}", family
) )
if len(members) < 2: expected_effects = self.effect_counts(family.name)
continue for member in members:
expected_effects = self.effect_counts(members[0])
for member in members[1:]:
member_effects = self.effect_counts(member) member_effects = self.effect_counts(member)
if member_effects != expected_effects: if member_effects != expected_effects:
self.error( self.error(
@ -1311,11 +1312,10 @@ def write_metadata(self) -> None:
self.out.emit("") self.out.emit("")
self.out.emit("_specializations = {") self.out.emit("_specializations = {")
for name, family in self.families.items(): for name, family in self.families.items():
assert len(family.members) > 1
with self.out.indent(): with self.out.indent():
self.out.emit(f"\"{family.members[0]}\": [") self.out.emit(f"\"{family.name}\": [")
with self.out.indent(): with self.out.indent():
for m in family.members[1:]: for m in family.members:
self.out.emit(f"\"{m}\",") self.out.emit(f"\"{m}\",")
self.out.emit(f"],") self.out.emit(f"],")
self.out.emit("}") self.out.emit("}")
@ -1551,9 +1551,8 @@ def write_macro(self, mac: MacroInstruction) -> None:
self.out.emit(f"next_instr += {cache_adjust};") self.out.emit(f"next_instr += {cache_adjust};")
if ( if (
last_instr (family := self.families.get(mac.name))
and (family := last_instr.family) and mac.name == family.name
and mac.name == family.members[0]
and (cache_size := family.size) and (cache_size := family.size)
): ):
self.out.emit( self.out.emit(

View File

@ -347,7 +347,7 @@ ### More examples
### Defining an instruction family ### Defining an instruction family
A _family_ represents a specializable instruction and its specializations. A _family_ maps a specializable instruction to its specializations.
Example: These opcodes all share the same instruction format): Example: These opcodes all share the same instruction format):
```C ```C

View File

@ -287,7 +287,7 @@ def test_macro_instruction():
inst(OP3, (unused/5, arg2, left, right -- res)) { inst(OP3, (unused/5, arg2, left, right -- res)) {
res = op3(arg2, left, right); res = op3(arg2, left, right);
} }
family(op, INLINE_CACHE_ENTRIES_OP) = { OP, OP3 }; family(OP, INLINE_CACHE_ENTRIES_OP) = { OP3 };
""" """
output = """ output = """
TARGET(OP1) { TARGET(OP1) {