From 0c109e0c2d0af5adeed47eefe3701ac1d84c3877 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 26 Apr 2025 03:39:05 +0800 Subject: [PATCH 1/6] Add type attributes to the optimizer DSL --- Python/optimizer_bytecodes.c | 48 +++++++------------- Python/optimizer_cases.c.h | 3 +- Tools/cases_generator/analyzer.py | 7 +-- Tools/cases_generator/optimizer_generator.py | 18 ++++++++ Tools/cases_generator/parser.py | 2 + Tools/cases_generator/parsing.py | 41 +++++++++++++++-- 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 040e54479b722a..50ccd42c4af381 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -104,18 +104,16 @@ dummy_func(void) { res = sym_new_null(ctx); } - op(_GUARD_TOS_INT, (tos -- tos)) { + op(_GUARD_TOS_INT, (tos -- type(&PyLong_Type) tos)) { if (sym_matches_type(tos, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyLong_Type); } - op(_GUARD_NOS_INT, (nos, unused -- nos, unused)) { + op(_GUARD_NOS_INT, (nos, unused -- type(&PyLong_Type) nos, unused)) { if (sym_matches_type(nos, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyLong_Type); } op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { @@ -141,18 +139,16 @@ dummy_func(void) { } } - op(_GUARD_TOS_FLOAT, (tos -- tos)) { + op(_GUARD_TOS_FLOAT, (tos -- type(&PyFloat_Type) tos)) { if (sym_matches_type(tos, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyFloat_Type); } - op(_GUARD_NOS_FLOAT, (nos, unused -- nos, unused)) { + op(_GUARD_NOS_FLOAT, (nos, unused -- type(&PyFloat_Type) nos, unused)) { if (sym_matches_type(nos, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyFloat_Type); } op(_BINARY_OP, (left, right -- res)) { @@ -408,18 +404,16 @@ dummy_func(void) { } } - op(_GUARD_NOS_UNICODE, (nos, unused -- nos, unused)) { + op(_GUARD_NOS_UNICODE, (nos, unused -- type(&PyUnicode_Type) nos, unused)) { if (sym_matches_type(nos, &PyUnicode_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyUnicode_Type); } - op(_GUARD_TOS_UNICODE, (value -- value)) { + op(_GUARD_TOS_UNICODE, (value -- type(&PyUnicode_Type) value)) { if (sym_matches_type(value, &PyUnicode_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(value, &PyUnicode_Type); } op(_TO_BOOL_STR, (value -- res)) { @@ -429,8 +423,7 @@ dummy_func(void) { } } - op(_UNARY_NOT, (value -- res)) { - sym_set_type(value, &PyBool_Type); + op(_UNARY_NOT, (type(&PyBool_Type) value -- res)) { res = sym_new_truthiness(ctx, value, false); } @@ -631,13 +624,12 @@ dummy_func(void) { self_or_null = sym_new_not_null(ctx); } - op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { + op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- type(&PyFunction_Type) callable, self_or_null, unused[oparg])) { if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) { assert(PyFunction_Check(sym_get_const(ctx, callable))); REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version); this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable); } - sym_set_type(callable, &PyFunction_Type); } op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { @@ -653,9 +645,9 @@ dummy_func(void) { } } - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- type(&PyMethod_Type) callable, null, unused[oparg])) { sym_set_null(null); - sym_set_type(callable, &PyMethod_Type); + (void)callable; } op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { @@ -977,46 +969,40 @@ dummy_func(void) { } } - op(_GUARD_TOS_LIST, (tos -- tos)) { + op(_GUARD_TOS_LIST, (tos -- type(&PyList_Type) tos)) { if (sym_matches_type(tos, &PyList_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyList_Type); } - op(_GUARD_NOS_LIST, (nos, unused -- nos, unused)) { + op(_GUARD_NOS_LIST, (nos, unused -- type(&PyList_Type) nos, unused)) { if (sym_matches_type(nos, &PyList_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyList_Type); } - op(_GUARD_TOS_TUPLE, (tos -- tos)) { + op(_GUARD_TOS_TUPLE, (tos -- type(&PyTuple_Type) tos)) { if (sym_matches_type(tos, &PyTuple_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyTuple_Type); } - op(_GUARD_NOS_TUPLE, (nos, unused -- nos, unused)) { + op(_GUARD_NOS_TUPLE, (nos, unused -- type(&PyTuple_Type) nos, unused)) { if (sym_matches_type(nos, &PyTuple_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyTuple_Type); } - op(_GUARD_TOS_DICT, (tos -- tos)) { + op(_GUARD_TOS_DICT, (tos -- type(&PyDict_Type) tos)) { if (sym_matches_type(tos, &PyDict_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyDict_Type); } - op(_GUARD_NOS_DICT, (nos, unused -- nos, unused)) { + op(_GUARD_NOS_DICT, (nos, unused -- type(&PyDict_Type) nos, unused)) { if (sym_matches_type(nos, &PyDict_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyDict_Type); } op(_GUARD_TOS_ANY_SET, (tos -- tos)) { @@ -1055,7 +1041,7 @@ dummy_func(void) { sym_set_const(callable, (PyObject *)&PyUnicode_Type); } - op(_CALL_LEN, (callable[1], self_or_null[1], args[oparg] -- res)) { + op(_CALL_LEN, (callable[1], self_or_null[1], args[oparg] -- type(res)) { res = sym_new_type(ctx, &PyLong_Type); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 9a5a362ec199a9..2a931cd12e42a1 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -151,8 +151,8 @@ JitOptSymbol *value; JitOptSymbol *res; value = stack_pointer[-1]; - sym_set_type(value, &PyBool_Type); res = sym_new_truthiness(ctx, value, false); + sym_set_type(value, &PyBool_Type); stack_pointer[-1] = res; break; } @@ -1746,6 +1746,7 @@ null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; sym_set_null(null); + (void)callable; sym_set_type(callable, &PyMethod_Type); break; } diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index a217d7136a5401..ad496af20845c4 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -5,7 +5,7 @@ import re from typing import Optional, Callable -from parser import Stmt, SimpleStmt, BlockStmt, IfStmt, WhileStmt +from parser import Stmt, SimpleStmt, BlockStmt, IfStmt, WhileStmt, StackAttribute @dataclass class EscapingCall: @@ -137,13 +137,14 @@ class StackItem: name: str type: str | None size: str + attributes: list[StackAttribute] peek: bool = False used: bool = False def __str__(self) -> str: size = f"[{self.size}]" if self.size else "" type = "" if self.type is None else f"{self.type} " - return f"{type}{self.name}{size} {self.peek}" + return f"{self.attributes} {type}{self.name}{size} {self.peek}" def is_array(self) -> bool: return self.size != "" @@ -345,7 +346,7 @@ def override_error( def convert_stack_item( item: parser.StackEffect, replace_op_arg_1: str | None ) -> StackItem: - return StackItem(item.name, item.type, item.size) + return StackItem(item.name, item.type, item.size, item.attributes) def check_unused(stack: list[StackItem], input_names: dict[str, lexer.Token]) -> None: "Unused items cannot be on the stack above used, non-peek items" diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py index 7a32275347e896..ae5498b9cf5f21 100644 --- a/Tools/cases_generator/optimizer_generator.py +++ b/Tools/cases_generator/optimizer_generator.py @@ -24,6 +24,7 @@ from typing import TextIO from lexer import Token from stack import Local, Stack, StackError, Storage +from parser import TYPE DEFAULT_OUTPUT = ROOT / "Python/optimizer_cases.c.h" DEFAULT_ABSTRACT_INPUT = (ROOT / "Python/optimizer_bytecodes.c").absolute().as_posix() @@ -111,6 +112,19 @@ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None: self.out.emit(goto) self.out.emit(label) +def get_type(item: StackItem) -> str | None: + for attribute in item.attributes: + if attribute.ident == TYPE: + return attribute.expr + return None + +def emit_sym_set_type_for_stack_effect(emitter: Emitter, items: list[StackItem]) -> None: + for var in items: + typ = get_type(var) + if typ is not None: + emitter.emit(f"sym_set_type({var.name}, {typ});\n") + + def write_uop( override: Uop | None, uop: Uop, @@ -146,6 +160,10 @@ def write_uop( for var in storage.inputs: # type: ignore[possibly-undefined] var.in_local = False _, storage = emitter.emit_tokens(override, storage, None, False) + # Emit type effects. + out.start_line() + emit_sym_set_type_for_stack_effect(emitter, override.stack.inputs) + emit_sym_set_type_for_stack_effect(emitter, override.stack.outputs) out.start_line() storage.flush(out) else: diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 4ec46d8cac6e4b..38853f6c592166 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -18,6 +18,8 @@ WhileStmt, BlockStmt, MacroIfStmt, + StackAttribute, + TYPE, ) import pprint diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py index 9c9b0053a5928b..411ed17f7e5715 100644 --- a/Tools/cases_generator/parsing.py +++ b/Tools/cases_generator/parsing.py @@ -244,15 +244,24 @@ def accept(self, visitor: Visitor) -> None: __hash__ = object.__hash__ +@dataclass +class StackAttribute(Node): + ident: str + expr: str + + def __str__(self): + return f"{self.ident}({self.expr})" + @dataclass class StackEffect(Node): name: str = field(compare=False) # __eq__ only uses type, cond, size + attributes: list[StackAttribute] = field(compare=False) type: str = "" # Optional `:type` size: str = "" # Optional `[size]` # Note: size cannot be combined with type or cond def __repr__(self) -> str: - items = [self.name, self.type, self.size] + items = [self.attributes, self.name, self.type, self.size] while items and items[-1] == "": del items[-1] return f"StackEffect({', '.join(repr(item) for item in items)})" @@ -274,6 +283,14 @@ class OpName(Node): name: str +TYPE = "type" +# We have to do this at the parsing stage and not +# lexing stage as we want to allow this to be used as +# a normal identifier in C code. +STACK_ATTRIBUTES = { + TYPE, +} + InputEffect = StackEffect | CacheEffect OutputEffect = StackEffect UOp = OpName | CacheEffect @@ -458,10 +475,26 @@ def cache_effect(self) -> CacheEffect | None: return CacheEffect(tkn.text, size) return None + def stack_attributes(self) -> list[StackAttribute]: + # IDENTIFIER '(' expression ')' + res = [] + while tkn := self.expect(lx.IDENTIFIER): + if self.expect(lx.LPAREN): + if tkn.text not in STACK_ATTRIBUTES: + raise self.make_syntax_error(f"Stack attribute {tkn.text} is not recognized.") + expr = self.expression() + self.require(lx.RPAREN) + res.append(StackAttribute(tkn.text.strip(), expr.text.strip())) + else: + self.backup() + break + return res + @contextual def stack_effect(self) -> StackEffect | None: - # IDENTIFIER [':' IDENTIFIER [TIMES]] ['if' '(' expression ')'] - # | IDENTIFIER '[' expression ']' + # stack_attributes IDENTIFIER [':' IDENTIFIER [TIMES]] ['if' '(' expression ')'] + # | stack_attributes IDENTIFIER '[' expression ']' + stack_attributes = self.stack_attributes() if tkn := self.expect(lx.IDENTIFIER): type_text = "" if self.expect(lx.COLON): @@ -476,7 +509,7 @@ def stack_effect(self) -> StackEffect | None: raise self.make_syntax_error("Expected expression") self.require(lx.RBRACKET) size_text = size.text.strip() - return StackEffect(tkn.text, type_text, size_text) + return StackEffect(tkn.text, stack_attributes, type_text, size_text) return None @contextual From e5e1bc7a11ccdb319aa763c2827a62c5987125df Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 11 May 2025 12:05:36 +0800 Subject: [PATCH 2/6] Revert changes to optimizer_bytecodes --- Python/optimizer_bytecodes.c | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 50ccd42c4af381..040e54479b722a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -104,16 +104,18 @@ dummy_func(void) { res = sym_new_null(ctx); } - op(_GUARD_TOS_INT, (tos -- type(&PyLong_Type) tos)) { + op(_GUARD_TOS_INT, (tos -- tos)) { if (sym_matches_type(tos, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(tos, &PyLong_Type); } - op(_GUARD_NOS_INT, (nos, unused -- type(&PyLong_Type) nos, unused)) { + op(_GUARD_NOS_INT, (nos, unused -- nos, unused)) { if (sym_matches_type(nos, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(nos, &PyLong_Type); } op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { @@ -139,16 +141,18 @@ dummy_func(void) { } } - op(_GUARD_TOS_FLOAT, (tos -- type(&PyFloat_Type) tos)) { + op(_GUARD_TOS_FLOAT, (tos -- tos)) { if (sym_matches_type(tos, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(tos, &PyFloat_Type); } - op(_GUARD_NOS_FLOAT, (nos, unused -- type(&PyFloat_Type) nos, unused)) { + op(_GUARD_NOS_FLOAT, (nos, unused -- nos, unused)) { if (sym_matches_type(nos, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(nos, &PyFloat_Type); } op(_BINARY_OP, (left, right -- res)) { @@ -404,16 +408,18 @@ dummy_func(void) { } } - op(_GUARD_NOS_UNICODE, (nos, unused -- type(&PyUnicode_Type) nos, unused)) { + op(_GUARD_NOS_UNICODE, (nos, unused -- nos, unused)) { if (sym_matches_type(nos, &PyUnicode_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(nos, &PyUnicode_Type); } - op(_GUARD_TOS_UNICODE, (value -- type(&PyUnicode_Type) value)) { + op(_GUARD_TOS_UNICODE, (value -- value)) { if (sym_matches_type(value, &PyUnicode_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(value, &PyUnicode_Type); } op(_TO_BOOL_STR, (value -- res)) { @@ -423,7 +429,8 @@ dummy_func(void) { } } - op(_UNARY_NOT, (type(&PyBool_Type) value -- res)) { + op(_UNARY_NOT, (value -- res)) { + sym_set_type(value, &PyBool_Type); res = sym_new_truthiness(ctx, value, false); } @@ -624,12 +631,13 @@ dummy_func(void) { self_or_null = sym_new_not_null(ctx); } - op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- type(&PyFunction_Type) callable, self_or_null, unused[oparg])) { + op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) { assert(PyFunction_Check(sym_get_const(ctx, callable))); REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version); this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable); } + sym_set_type(callable, &PyFunction_Type); } op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { @@ -645,9 +653,9 @@ dummy_func(void) { } } - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- type(&PyMethod_Type) callable, null, unused[oparg])) { + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { sym_set_null(null); - (void)callable; + sym_set_type(callable, &PyMethod_Type); } op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { @@ -969,40 +977,46 @@ dummy_func(void) { } } - op(_GUARD_TOS_LIST, (tos -- type(&PyList_Type) tos)) { + op(_GUARD_TOS_LIST, (tos -- tos)) { if (sym_matches_type(tos, &PyList_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(tos, &PyList_Type); } - op(_GUARD_NOS_LIST, (nos, unused -- type(&PyList_Type) nos, unused)) { + op(_GUARD_NOS_LIST, (nos, unused -- nos, unused)) { if (sym_matches_type(nos, &PyList_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(nos, &PyList_Type); } - op(_GUARD_TOS_TUPLE, (tos -- type(&PyTuple_Type) tos)) { + op(_GUARD_TOS_TUPLE, (tos -- tos)) { if (sym_matches_type(tos, &PyTuple_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(tos, &PyTuple_Type); } - op(_GUARD_NOS_TUPLE, (nos, unused -- type(&PyTuple_Type) nos, unused)) { + op(_GUARD_NOS_TUPLE, (nos, unused -- nos, unused)) { if (sym_matches_type(nos, &PyTuple_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(nos, &PyTuple_Type); } - op(_GUARD_TOS_DICT, (tos -- type(&PyDict_Type) tos)) { + op(_GUARD_TOS_DICT, (tos -- tos)) { if (sym_matches_type(tos, &PyDict_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(tos, &PyDict_Type); } - op(_GUARD_NOS_DICT, (nos, unused -- type(&PyDict_Type) nos, unused)) { + op(_GUARD_NOS_DICT, (nos, unused -- nos, unused)) { if (sym_matches_type(nos, &PyDict_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } + sym_set_type(nos, &PyDict_Type); } op(_GUARD_TOS_ANY_SET, (tos -- tos)) { @@ -1041,7 +1055,7 @@ dummy_func(void) { sym_set_const(callable, (PyObject *)&PyUnicode_Type); } - op(_CALL_LEN, (callable[1], self_or_null[1], args[oparg] -- type(res)) { + op(_CALL_LEN, (callable[1], self_or_null[1], args[oparg] -- res)) { res = sym_new_type(ctx, &PyLong_Type); } From e3660f35f08ed91b6e4afb3dfc75d90a1e6199e0 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 11 May 2025 12:07:14 +0800 Subject: [PATCH 3/6] Update optimizer_cases.c.h --- Python/optimizer_cases.c.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 7831046baf7394..deb912662e4b0b 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -151,8 +151,8 @@ JitOptSymbol *value; JitOptSymbol *res; value = stack_pointer[-1]; - res = sym_new_truthiness(ctx, value, false); sym_set_type(value, &PyBool_Type); + res = sym_new_truthiness(ctx, value, false); stack_pointer[-1] = res; break; } @@ -1811,7 +1811,6 @@ null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; sym_set_null(null); - (void)callable; sym_set_type(callable, &PyMethod_Type); break; } From e9a14efda56210d30a42359848f89cd2f0e45258 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 11 May 2025 12:12:42 +0800 Subject: [PATCH 4/6] Add test --- Lib/test/test_generated_cases.py | 35 ++++++++++++++++---- Tools/cases_generator/optimizer_generator.py | 12 +++---- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index a71ddc01d1c045..ae4503fb56221f 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -59,14 +59,14 @@ class TestEffects(unittest.TestCase): def test_effect_sizes(self): stack = Stack() inputs = [ - x := StackItem("x", None, "1"), - y := StackItem("y", None, "oparg"), - z := StackItem("z", None, "oparg*2"), + x := StackItem("x", None, "1", []), + y := StackItem("y", None, "oparg", []), + z := StackItem("z", None, "oparg*2", []), ] outputs = [ - StackItem("x", None, "1"), - StackItem("b", None, "oparg*4"), - StackItem("c", None, "1"), + StackItem("x", None, "1", []), + StackItem("b", None, "oparg*4", []), + StackItem("c", None, "1", []), ] null = CWriter.null() stack.pop(z, null) @@ -2253,5 +2253,28 @@ def test_validate_uop_unused_size_mismatch(self): "Inputs must have equal sizes"): self.run_cases_test(input, input2, output) + def test_uop_type_attribute_input(self): + input = """ + op(OP, (foo -- )) { + } + """ + input2 = """ + op(OP, (type(&PyLong_Type) foo -- )) { + (void)foo; + } + """ + output = """ + case OP: { + JitOptSymbol *foo; + foo = stack_pointer[-1]; + (void)foo; + assert(sym_matches_type(foo, &PyLong_Type)); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + """ + self.run_cases_test(input, input2, output) + if __name__ == "__main__": unittest.main() diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py index 4f25f46ced6a3e..dd1d539c7bf954 100644 --- a/Tools/cases_generator/optimizer_generator.py +++ b/Tools/cases_generator/optimizer_generator.py @@ -154,11 +154,6 @@ def get_type(item: StackItem) -> str | None: return attribute.expr return None -def emit_sym_set_type_for_stack_effect(emitter: Emitter, items: list[StackItem]) -> None: - for var in items: - typ = get_type(var) - if typ is not None: - emitter.emit(f"sym_set_type({var.name}, {typ});\n") def write_uop( @@ -198,9 +193,10 @@ def write_uop( _, storage = emitter.emit_tokens(override, storage, None, False) # Emit type effects. out.start_line() - emit_sym_set_type_for_stack_effect(emitter, override.stack.inputs) - emit_sym_set_type_for_stack_effect(emitter, override.stack.outputs) - out.start_line() + for var in override.stack.inputs: + typ = get_type(var) + if typ is not None: + emitter.emit(f"assert(sym_matches_type({var.name}, {typ}));\n") storage.flush(out) else: emit_default(out, uop, stack) From cb508b482dcd973eba33b7ab4ec34b64f072bcdd Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 11 May 2025 14:24:36 +0800 Subject: [PATCH 5/6] Fix mypy problems --- Tools/cases_generator/optimizer_generator.py | 6 +++--- Tools/cases_generator/parsing.py | 5 +++-- Tools/cases_generator/stack.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py index dd1d539c7bf954..351c830ce259d7 100644 --- a/Tools/cases_generator/optimizer_generator.py +++ b/Tools/cases_generator/optimizer_generator.py @@ -193,10 +193,10 @@ def write_uop( _, storage = emitter.emit_tokens(override, storage, None, False) # Emit type effects. out.start_line() - for var in override.stack.inputs: - typ = get_type(var) + for input_ in override.stack.inputs: + typ = get_type(input_) if typ is not None: - emitter.emit(f"assert(sym_matches_type({var.name}, {typ}));\n") + emitter.emit(f"assert(sym_matches_type({input_.name}, {typ}));\n") storage.flush(out) else: emit_default(out, uop, stack) diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py index 411ed17f7e5715..8694eb91b7403d 100644 --- a/Tools/cases_generator/parsing.py +++ b/Tools/cases_generator/parsing.py @@ -249,7 +249,7 @@ class StackAttribute(Node): ident: str expr: str - def __str__(self): + def __repr__(self) -> str: return f"{self.ident}({self.expr})" @dataclass @@ -483,8 +483,9 @@ def stack_attributes(self) -> list[StackAttribute]: if tkn.text not in STACK_ATTRIBUTES: raise self.make_syntax_error(f"Stack attribute {tkn.text} is not recognized.") expr = self.expression() + assert expr is not None self.require(lx.RPAREN) - res.append(StackAttribute(tkn.text.strip(), expr.text.strip())) + res.append(StackAttribute(tkn.text.strip(), expr.size.strip())) else: self.backup() break diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index 6b681775f48c81..97aeb18b14c39a 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -168,7 +168,7 @@ def from_memory(defn: StackItem, offset: PointerOffset) -> "Local": @staticmethod def register(name: str) -> "Local": - item = StackItem(name, None, "", False, True) + item = StackItem(name, None, "", [], False, True) return Local(item, None, True) def kill(self) -> None: From 821c6980d91a624e0f8c0ff5b190a35bd8510aaa Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 06:25:30 +0000 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-05-11-06-25-26.gh-issue-132967.AwR3m5.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-06-25-26.gh-issue-132967.AwR3m5.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-06-25-26.gh-issue-132967.AwR3m5.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-06-25-26.gh-issue-132967.AwR3m5.rst new file mode 100644 index 00000000000000..ce2233e8276c91 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-11-06-25-26.gh-issue-132967.AwR3m5.rst @@ -0,0 +1 @@ +Add support for attributes to the bytecodes DSL.