diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst new file mode 100644 index 00000000000000..bbd8e8eddda607 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst @@ -0,0 +1,3 @@ +Change bytecode syntax for families +to remove redundant name matching +pseudo syntax. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 15b48ae9d82672..ec99213987840b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -284,8 +284,7 @@ dummy_func( res = Py_IsFalse(value) ? Py_True : Py_False; } - family(to_bool, INLINE_CACHE_ENTRIES_TO_BOOL) = { - TO_BOOL, + family(TO_BOOL, INLINE_CACHE_ENTRIES_TO_BOOL) = { TO_BOOL_ALWAYS_TRUE, TO_BOOL_BOOL, TO_BOOL_INT, @@ -372,8 +371,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - family(binary_op, INLINE_CACHE_ENTRIES_BINARY_OP) = { - BINARY_OP, + family(BINARY_OP, INLINE_CACHE_ENTRIES_BINARY_OP) = { BINARY_OP_MULTIPLY_INT, BINARY_OP_ADD_INT, BINARY_OP_SUBTRACT_INT, @@ -507,8 +505,7 @@ dummy_func( macro(BINARY_OP_INPLACE_ADD_UNICODE) = _GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE; - family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { - BINARY_SUBSCR, + family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR_DICT, BINARY_SUBSCR_GETITEM, BINARY_SUBSCR_LIST_INT, @@ -643,8 +640,7 @@ dummy_func( ERROR_IF(err, error); } - family(store_subscr, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = { - STORE_SUBSCR, + family(STORE_SUBSCR, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = { STORE_SUBSCR_DICT, STORE_SUBSCR_LIST_INT, }; @@ -921,8 +917,7 @@ dummy_func( ERROR_IF(iter == NULL, error); } - family(send, INLINE_CACHE_ENTRIES_SEND) = { - SEND, + family(SEND, INLINE_CACHE_ENTRIES_SEND) = { SEND_GEN, }; @@ -1134,8 +1129,7 @@ dummy_func( } } - family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { - UNPACK_SEQUENCE, + family(UNPACK_SEQUENCE, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { UNPACK_SEQUENCE_TWO_TUPLE, UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_LIST, @@ -1198,8 +1192,7 @@ dummy_func( ERROR_IF(res == 0, error); } - family(store_attr, INLINE_CACHE_ENTRIES_STORE_ATTR) = { - STORE_ATTR, + family(STORE_ATTR, INLINE_CACHE_ENTRIES_STORE_ATTR) = { STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_SLOT, STORE_ATTR_WITH_HINT, @@ -1298,8 +1291,7 @@ dummy_func( macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS; - family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { - LOAD_GLOBAL, + family(LOAD_GLOBAL, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { LOAD_GLOBAL_MODULE, LOAD_GLOBAL_BUILTIN, }; @@ -1647,8 +1639,7 @@ dummy_func( GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); } - family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { - LOAD_SUPER_ATTR, + family(LOAD_SUPER_ATTR, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { LOAD_SUPER_ATTR_ATTR, LOAD_SUPER_ATTR_METHOD, }; @@ -1750,8 +1741,7 @@ dummy_func( } } - family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { - LOAD_ATTR, + family(LOAD_ATTR, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_MODULE, LOAD_ATTR_WITH_HINT, @@ -2048,8 +2038,7 @@ dummy_func( Py_DECREF(owner); } - family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { - COMPARE_OP, + family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = { COMPARE_OP_FLOAT, COMPARE_OP_INT, COMPARE_OP_STR, @@ -2350,8 +2339,7 @@ dummy_func( // This is optimized by skipping that instruction and combining // its effect (popping 'iter' instead of pushing 'next'.) - family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { - FOR_ITER, + family(FOR_ITER, INLINE_CACHE_ENTRIES_FOR_ITER) = { FOR_ITER_LIST, FOR_ITER_TUPLE, FOR_ITER_RANGE, @@ -2800,8 +2788,7 @@ dummy_func( // Cache layout: counter/1, func_version/2 // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! - family(call, INLINE_CACHE_ENTRIES_CALL) = { - CALL, + family(CALL, INLINE_CACHE_ENTRIES_CALL) = { CALL_BOUND_METHOD_EXACT_ARGS, CALL_PY_EXACT_ARGS, CALL_PY_WITH_DEFAULTS, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ce16271097b955..af8beb383e7178 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -438,7 +438,7 @@ def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct if family := self.family: - if self.name == family.members[0]: + if self.name == family.name: if cache_size := family.size: out.emit( f"static_assert({cache_size} == " @@ -831,7 +831,7 @@ def find_predictions(self) -> None: def map_families(self) -> None: """Link instruction names back to their family, if they have one.""" 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.family not in (family, None): self.error( @@ -855,8 +855,11 @@ def check_families(self) -> None: - All members must have the same cache, input and output effects """ for family in self.families.values(): - if len(family.members) < 2: - self.error(f"Family {family.name!r} has insufficient members", family) + if family.name not in self.macro_instrs and family.name not in self.instrs: + self.error( + f"Family {family.name!r} has unknown instruction {family.name!r}", + family, + ) members = [ member for member in family.members @@ -867,10 +870,8 @@ def check_families(self) -> None: self.error( f"Family {family.name!r} has unknown members: {unknown}", family ) - if len(members) < 2: - continue - expected_effects = self.effect_counts(members[0]) - for member in members[1:]: + expected_effects = self.effect_counts(family.name) + for member in members: member_effects = self.effect_counts(member) if member_effects != expected_effects: self.error( @@ -1293,11 +1294,10 @@ def write_metadata(self) -> None: self.out.emit("") self.out.emit("_specializations = {") for name, family in self.families.items(): - assert len(family.members) > 1 with self.out.indent(): - self.out.emit(f"\"{family.members[0]}\": [") + self.out.emit(f"\"{family.name}\": [") with self.out.indent(): - for m in family.members[1:]: + for m in family.members: self.out.emit(f"\"{m}\",") self.out.emit(f"],") self.out.emit("}") @@ -1533,9 +1533,8 @@ def write_macro(self, mac: MacroInstruction) -> None: self.out.emit(f"next_instr += {cache_adjust};") if ( - last_instr - and (family := last_instr.family) - and mac.name == family.members[0] + (family := self.families.get(mac.name)) + and mac.name == family.name and (cache_size := family.size) ): self.out.emit( diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index c03870ef59eb49..f141848631d04a 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -347,7 +347,7 @@ For explanations see "Generating the interpreter" below.) ### 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): ```C diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py index e374ac41e6a94d..e44273429b7405 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Tools/cases_generator/test_generator.py @@ -287,7 +287,7 @@ def test_macro_instruction(): inst(OP3, (unused/5, arg2, left, right -- res)) { res = op3(arg2, left, right); } - family(op, INLINE_CACHE_ENTRIES_OP) = { OP, OP3 }; + family(OP, INLINE_CACHE_ENTRIES_OP) = { OP3 }; """ output = """ TARGET(OP1) {