]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
rework ad-hoc generation of guards
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Thu, 6 Nov 2025 08:29:11 +0000 (08:29 +0000)
committerKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Thu, 6 Nov 2025 08:29:11 +0000 (08:29 +0000)
Python/bytecodes.c
Python/executor_cases.c.h
Tools/cases_generator/tier2_generator.py

index b57824af37559ac06cef6512a56ddfd98d9a8d3b..318443daebc89cc9c606bf09fe2df7a1bb0b9a56 100644 (file)
@@ -5489,23 +5489,35 @@ dummy_func(
         }
 
         tier2 op(_GUARD_IP__PUSH_FRAME, (ip/4 --)) {
-            // Implementation automatically inserted by Tools/cases/tier2_generator.py
-            EXIT_IF(true);
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
+                EXIT_IF(true);
+            }
         }
 
         tier2 op(_GUARD_IP_YIELD_VALUE, (ip/4 --)) {
-            // Implementation automatically inserted by Tools/cases/tier2_generator.py
-            EXIT_IF(true);
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
+                EXIT_IF(true);
+            }
         }
 
         tier2 op(_GUARD_IP_RETURN_VALUE, (ip/4 --)) {
-            // Implementation automatically inserted by Tools/cases/tier2_generator.py
-            EXIT_IF(true);
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
+                EXIT_IF(true);
+            }
         }
 
         tier2 op(_GUARD_IP_RETURN_GENERATOR, (ip/4 --)) {
-            // Implementation automatically inserted by Tools/cases/tier2_generator.py
-            EXIT_IF(true);
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
+                EXIT_IF(true);
+            }
         }
 
         label(pop_2_error) {
index ada9a486d024d452cfe624dd5846601c61bef061..e9f101c8c3a4a355adab951ea78f6a24c0eafb85 100644 (file)
@@ -8,6 +8,11 @@
 #endif
 #define TIER_TWO 2
 
+        #define OFFSET_OF_RETURN_VALUE ((frame->return_offset))
+        #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND))
+        #define OFFSET_OF__PUSH_FRAME ((0))
+        #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset))
+
         case _NOP: {
             break;
         }
             break;
         }
 
-        case _GUARD_IP_RETURN_VALUE: {
+        case _GUARD_IP__PUSH_FRAME: {
             PyObject *ip = (PyObject *)CURRENT_OPERAND0();
-            if (frame->instr_ptr + (frame->return_offset) != (_Py_CODEUNIT *)ip) {
-                frame->instr_ptr += (frame->return_offset);
-                UOP_STAT_INC(uopcode, miss);
-                JUMP_TO_JUMP_TARGET();
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF__PUSH_FRAME;
+                if (true) {
+                    UOP_STAT_INC(uopcode, miss);
+                    JUMP_TO_JUMP_TARGET();
+                }
             }
             break;
         }
 
         case _GUARD_IP_YIELD_VALUE: {
             PyObject *ip = (PyObject *)CURRENT_OPERAND0();
-            if (frame->instr_ptr + (1+INLINE_CACHE_ENTRIES_SEND) != (_Py_CODEUNIT *)ip) {
-                frame->instr_ptr += (1+INLINE_CACHE_ENTRIES_SEND);
-                UOP_STAT_INC(uopcode, miss);
-                JUMP_TO_JUMP_TARGET();
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_YIELD_VALUE;
+                if (true) {
+                    UOP_STAT_INC(uopcode, miss);
+                    JUMP_TO_JUMP_TARGET();
+                }
             }
             break;
         }
 
-        case _GUARD_IP__PUSH_FRAME: {
+        case _GUARD_IP_RETURN_VALUE: {
             PyObject *ip = (PyObject *)CURRENT_OPERAND0();
-            if (frame->instr_ptr + (0) != (_Py_CODEUNIT *)ip) {
-                frame->instr_ptr += (0);
-                UOP_STAT_INC(uopcode, miss);
-                JUMP_TO_JUMP_TARGET();
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_RETURN_VALUE;
+                if (true) {
+                    UOP_STAT_INC(uopcode, miss);
+                    JUMP_TO_JUMP_TARGET();
+                }
             }
             break;
         }
 
         case _GUARD_IP_RETURN_GENERATOR: {
             PyObject *ip = (PyObject *)CURRENT_OPERAND0();
-            if (frame->instr_ptr + (frame->return_offset) != (_Py_CODEUNIT *)ip) {
-                frame->instr_ptr += (frame->return_offset);
-                UOP_STAT_INC(uopcode, miss);
-                JUMP_TO_JUMP_TARGET();
+            _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR;
+            if (target != (_Py_CODEUNIT *)ip) {
+                frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR;
+                if (true) {
+                    UOP_STAT_INC(uopcode, miss);
+                    JUMP_TO_JUMP_TARGET();
+                }
             }
             break;
         }
 
+        #undef OFFSET_OFRETURN_VALUE
+        #undef OFFSET_OFYIELD_VALUE
+        #undef OFFSET_OF_PUSH_FRAME
+        #undef OFFSET_OFRETURN_GENERATOR
+
 #undef TIER_TWO
index 8a9db068382a4f1a4eabdd3b94446eaa5288dc68..ab37c4898249279bf7848398f209cf9b26edd22c 100644 (file)
@@ -63,6 +63,7 @@ class Tier2Emitter(Emitter):
     def __init__(self, out: CWriter, labels: dict[str, Label]):
         super().__init__(out, labels)
         self._replacers["oparg"] = self.oparg
+        self._replacers["OFFSET_OF_CORRESPONDING_UOP"] = self.offset_of_corresponding_uop
 
     def goto_error(self, offset: int, storage: Storage) -> str:
         # To do: Add jump targets for popping values.
@@ -134,6 +135,19 @@ class Tier2Emitter(Emitter):
         self.out.emit_at(uop.name[-1], tkn)
         return True
 
+    def offset_of_corresponding_uop(
+        self,
+        tkn: Token,
+        tkn_iter: TokenIterator,
+        uop: CodeSection,
+        storage: Storage,
+        inst: Instruction | None,
+    ) -> bool:
+        assert uop.name.startswith("_GUARD_IP")
+        rest = uop.name[len("_GUARD_IP"):]
+        self.emit(f" OFFSET_OF{rest};\n")
+        next(tkn_iter)
+        return True
 
 def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack:
     locals: dict[str, Local] = {}
@@ -165,33 +179,6 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack:
 SKIPS = ("_EXTENDED_ARG",)
 
 
-def generate_guard_ips(
-    analysis: Analysis,
-    emitter: Tier2Emitter,
-) -> None:
-    for name, uop in analysis.uops.items():
-        for stmt in uop.body.body:
-            tkn_iter = iter(stmt.tokens())
-            for token in tkn_iter:
-                if token.kind == "IDENTIFIER" and token.text == "LOAD_IP":
-                    offset = []
-                    while token.kind != "SEMI":
-                        offset.append(token.text)
-                        token = next(tkn_iter)
-                    # 1: to remove the LOAD_IP text
-                    offset_str = "".join(offset[1:])
-                    emitter.emit(f"case _GUARD_IP_{name}: {{\n")
-                    emitter.emit("PyObject *ip = (PyObject *)CURRENT_OPERAND0();\n")
-                    emitter.emit(f"if (frame->instr_ptr + {offset_str} != (_Py_CODEUNIT *)ip) {{\n")
-                    emitter.emit(f"frame->instr_ptr += {offset_str};\n")
-                    emitter.emit(f"UOP_STAT_INC(uopcode, miss);\n")
-                    emitter.emit("JUMP_TO_JUMP_TARGET();\n")
-                    emitter.emit("}\n")
-                    emitter.emit("break;\n")
-                    emitter.emit("}\n")
-                    emitter.emit("\n")
-
-
 def generate_tier2(
     filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool
 ) -> None:
@@ -207,13 +194,35 @@ def generate_tier2(
     out = CWriter(outfile, 2, lines)
     emitter = Tier2Emitter(out, analysis.labels)
     out.emit("\n")
+    offset_strs: list[tuple[str, str]] = []
+    for name, uop in analysis.uops.items():
+        if not f"_GUARD_IP_{name}" in analysis.uops:
+            continue
+        tkn_iter = uop.body.tokens()
+        found = False
+        offset_str = ""
+        for token in tkn_iter:
+            if token.kind == "IDENTIFIER" and token.text == "LOAD_IP":
+                if found:
+                    raise analysis_error("Cannot have two LOAD_IP in a guarded single uop.", uop.body.open)
+                offset = []
+                while token.kind != "SEMI":
+                    offset.append(token.text)
+                    token = next(tkn_iter)
+                # 1: to remove the LOAD_IP text
+                offset_str = "".join(offset[1:])
+                found = True
+        assert offset_str
+        out.emit(f"#define OFFSET_OF_{name} ({offset_str})\n")
+        offset_strs.append((name, offset_str))
+
+    out.emit("\n")
+
     for name, uop in analysis.uops.items():
         if uop.properties.tier == 1:
             continue
         if uop.is_super():
             continue
-        if name.startswith("_GUARD_IP"):
-            continue
         why_not_viable = uop.why_not_viable()
         if why_not_viable is not None:
             out.emit(
@@ -231,7 +240,9 @@ def generate_tier2(
         out.emit("}")
         out.emit("\n\n")
 
-    generate_guard_ips(analysis, emitter)
+    for name, offset_str in offset_strs:
+        out.emit(f"#undef OFFSET_OF{name}\n")
+    out.emit("\n")
     outfile.write("#undef TIER_TWO\n")