]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-106701: Move the hand-written Tier 2 uops to bytecodes.c (#106702)
authorGuido van Rossum <guido@python.org>
Thu, 13 Jul 2023 19:14:51 +0000 (12:14 -0700)
committerGitHub <noreply@github.com>
Thu, 13 Jul 2023 19:14:51 +0000 (12:14 -0700)
This moves EXIT_TRACE, SAVE_IP, JUMP_TO_TOP, and
_POP_JUMP_IF_{FALSE,TRUE} from ceval.c to bytecodes.c.

They are no less special than before, but this way
they are discoverable o the copy-and-patch tooling.

Include/internal/pycore_opcode_metadata.h
Python/bytecodes.c
Python/ceval.c
Python/executor_cases.c.h
Tools/cases_generator/generate_cases.py

index 79bbe9a916f5963fe6ba743aac93bba4f7469932..c88640777e3fb0a8e23b5c137315f6312a49ad0b 100644 (file)
 
 #define EXIT_TRACE 300
 #define SAVE_IP 301
-#define _POP_JUMP_IF_FALSE 302
-#define _POP_JUMP_IF_TRUE 303
-#define JUMP_TO_TOP 304
-#define _GUARD_BOTH_INT 305
-#define _BINARY_OP_MULTIPLY_INT 306
-#define _BINARY_OP_ADD_INT 307
-#define _BINARY_OP_SUBTRACT_INT 308
-#define _GUARD_BOTH_FLOAT 309
-#define _BINARY_OP_MULTIPLY_FLOAT 310
-#define _BINARY_OP_ADD_FLOAT 311
-#define _BINARY_OP_SUBTRACT_FLOAT 312
-#define _GUARD_BOTH_UNICODE 313
-#define _BINARY_OP_ADD_UNICODE 314
-#define _LOAD_LOCALS 315
-#define _LOAD_FROM_DICT_OR_GLOBALS 316
-#define _SKIP_CACHE 317
-#define _GUARD_GLOBALS_VERSION 318
-#define _GUARD_BUILTINS_VERSION 319
-#define _GUARD_TYPE_VERSION 320
-#define _CHECK_MANAGED_OBJECT_HAS_VALUES 321
-#define IS_NONE 322
-#define _ITER_CHECK_RANGE 323
-#define _ITER_EXHAUSTED_RANGE 324
-#define _ITER_NEXT_RANGE 325
+#define _GUARD_BOTH_INT 302
+#define _BINARY_OP_MULTIPLY_INT 303
+#define _BINARY_OP_ADD_INT 304
+#define _BINARY_OP_SUBTRACT_INT 305
+#define _GUARD_BOTH_FLOAT 306
+#define _BINARY_OP_MULTIPLY_FLOAT 307
+#define _BINARY_OP_ADD_FLOAT 308
+#define _BINARY_OP_SUBTRACT_FLOAT 309
+#define _GUARD_BOTH_UNICODE 310
+#define _BINARY_OP_ADD_UNICODE 311
+#define _LOAD_LOCALS 312
+#define _LOAD_FROM_DICT_OR_GLOBALS 313
+#define _SKIP_CACHE 314
+#define _GUARD_GLOBALS_VERSION 315
+#define _GUARD_BUILTINS_VERSION 316
+#define _GUARD_TYPE_VERSION 317
+#define _CHECK_MANAGED_OBJECT_HAS_VALUES 318
+#define IS_NONE 319
+#define _ITER_CHECK_RANGE 320
+#define _ITER_EXHAUSTED_RANGE 321
+#define _ITER_NEXT_RANGE 322
+#define _POP_JUMP_IF_FALSE 323
+#define _POP_JUMP_IF_TRUE 324
+#define JUMP_TO_TOP 325
 
 #ifndef NEED_OPCODE_METADATA
 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
@@ -1303,31 +1303,31 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = {
     [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } },
 };
 const char * const _PyOpcode_uop_name[512] = {
-    [300] = "EXIT_TRACE",
-    [301] = "SAVE_IP",
-    [302] = "_POP_JUMP_IF_FALSE",
-    [303] = "_POP_JUMP_IF_TRUE",
-    [304] = "JUMP_TO_TOP",
-    [305] = "_GUARD_BOTH_INT",
-    [306] = "_BINARY_OP_MULTIPLY_INT",
-    [307] = "_BINARY_OP_ADD_INT",
-    [308] = "_BINARY_OP_SUBTRACT_INT",
-    [309] = "_GUARD_BOTH_FLOAT",
-    [310] = "_BINARY_OP_MULTIPLY_FLOAT",
-    [311] = "_BINARY_OP_ADD_FLOAT",
-    [312] = "_BINARY_OP_SUBTRACT_FLOAT",
-    [313] = "_GUARD_BOTH_UNICODE",
-    [314] = "_BINARY_OP_ADD_UNICODE",
-    [315] = "_LOAD_LOCALS",
-    [316] = "_LOAD_FROM_DICT_OR_GLOBALS",
-    [317] = "_SKIP_CACHE",
-    [318] = "_GUARD_GLOBALS_VERSION",
-    [319] = "_GUARD_BUILTINS_VERSION",
-    [320] = "_GUARD_TYPE_VERSION",
-    [321] = "_CHECK_MANAGED_OBJECT_HAS_VALUES",
-    [322] = "IS_NONE",
-    [323] = "_ITER_CHECK_RANGE",
-    [324] = "_ITER_EXHAUSTED_RANGE",
-    [325] = "_ITER_NEXT_RANGE",
+    [EXIT_TRACE] = "EXIT_TRACE",
+    [SAVE_IP] = "SAVE_IP",
+    [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT",
+    [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT",
+    [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT",
+    [_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT",
+    [_GUARD_BOTH_FLOAT] = "_GUARD_BOTH_FLOAT",
+    [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT",
+    [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT",
+    [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT",
+    [_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE",
+    [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE",
+    [_LOAD_LOCALS] = "_LOAD_LOCALS",
+    [_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS",
+    [_SKIP_CACHE] = "_SKIP_CACHE",
+    [_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION",
+    [_GUARD_BUILTINS_VERSION] = "_GUARD_BUILTINS_VERSION",
+    [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION",
+    [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES",
+    [IS_NONE] = "IS_NONE",
+    [_ITER_CHECK_RANGE] = "_ITER_CHECK_RANGE",
+    [_ITER_EXHAUSTED_RANGE] = "_ITER_EXHAUSTED_RANGE",
+    [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE",
+    [_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE",
+    [_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE",
+    [JUMP_TO_TOP] = "JUMP_TO_TOP",
 };
 #endif // NEED_OPCODE_METADATA
index 176dbb584d0987095f3aa3daccabc86bfd969456..1fe9970e53cdfe3bb7adb2b283ca2de0cda12255 100644 (file)
@@ -3654,6 +3654,36 @@ dummy_func(
             Py_UNREACHABLE();
         }
 
+        ///////// Tier-2 only opcodes /////////
+
+        op(_POP_JUMP_IF_FALSE, (flag -- )) {
+            if (Py_IsFalse(flag)) {
+                pc = oparg;
+            }
+        }
+
+        op(_POP_JUMP_IF_TRUE, (flag -- )) {
+            if (Py_IsTrue(flag)) {
+                pc = oparg;
+            }
+        }
+
+        op(JUMP_TO_TOP, (--)) {
+            pc = 0;
+            CHECK_EVAL_BREAKER();
+        }
+
+        op(SAVE_IP, (--)) {
+            frame->prev_instr = ip_offset + oparg;
+        }
+
+        op(EXIT_TRACE, (--)) {
+            frame->prev_instr--;  // Back up to just before destination
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            Py_DECREF(self);
+            return frame;
+        }
+
 
 // END BYTECODES //
 
index de44085d732cfa4a9de1316749865dbc1a30ce32..d6c72fa3ff386cb88b613aa94a7ba077b0144adc 100644 (file)
@@ -2764,46 +2764,6 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
 #define ENABLE_SPECIALIZATION 0
 #include "executor_cases.c.h"
 
-            // NOTE: These pop-jumps move the uop pc, not the bytecode ip
-            case _POP_JUMP_IF_FALSE:
-            {
-                if (Py_IsFalse(stack_pointer[-1])) {
-                    pc = oparg;
-                }
-                stack_pointer--;
-                break;
-            }
-
-            case _POP_JUMP_IF_TRUE:
-            {
-                if (Py_IsTrue(stack_pointer[-1])) {
-                    pc = oparg;
-                }
-                stack_pointer--;
-                break;
-            }
-
-            case JUMP_TO_TOP:
-            {
-                pc = 0;
-                CHECK_EVAL_BREAKER();
-                break;
-            }
-
-            case SAVE_IP:
-            {
-                frame->prev_instr = ip_offset + oparg;
-                break;
-            }
-
-            case EXIT_TRACE:
-            {
-                frame->prev_instr--;  // Back up to just before destination
-                _PyFrame_SetStackPointer(frame, stack_pointer);
-                Py_DECREF(self);
-                return frame;
-            }
-
             default:
             {
                 fprintf(stderr, "Unknown uop %d, operand %" PRIu64 "\n", opcode, operand);
index 805ea06e0721671a2e153553c98e80f8fccfae21..ce54755d5d25f10b799eb6a9da18a704d114c617 100644 (file)
             stack_pointer[-(2 + (oparg-2))] = top;
             break;
         }
+
+        case _POP_JUMP_IF_FALSE: {
+            PyObject *flag = stack_pointer[-1];
+            if (Py_IsFalse(flag)) {
+                pc = oparg;
+            }
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case _POP_JUMP_IF_TRUE: {
+            PyObject *flag = stack_pointer[-1];
+            if (Py_IsTrue(flag)) {
+                pc = oparg;
+            }
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case JUMP_TO_TOP: {
+            pc = 0;
+            break;
+        }
+
+        case SAVE_IP: {
+            frame->prev_instr = ip_offset + oparg;
+            break;
+        }
+
+        case EXIT_TRACE: {
+            frame->prev_instr--;  // Back up to just before destination
+            _PyFrame_SetStackPointer(frame, stack_pointer);
+            Py_DECREF(self);
+            return frame;
+            break;
+        }
index ba4ef1ee97693e4b5bb5e847adebdfb8f8edf62f..ce16271097b955a8620124014829ee006a1e8ddb 100644 (file)
@@ -410,6 +410,8 @@ class Instruction:
 
     def is_viable_uop(self) -> bool:
         """Whether this instruction is viable as a uop."""
+        if self.name == "EXIT_TRACE":
+            return True  # This has 'return frame' but it's okay
         if self.always_exits:
             # print(f"Skipping {self.name} because it always exits")
             return False
@@ -1278,7 +1280,7 @@ class Analyzer:
                             typing.assert_never(thing)
 
             with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"):
-                self.write_uop_items(lambda name, counter: f"[{counter}] = \"{name}\",")
+                self.write_uop_items(lambda name, counter: f"[{name}] = \"{name}\",")
 
             self.out.emit("#endif // NEED_OPCODE_METADATA")
 
@@ -1324,17 +1326,19 @@ class Analyzer:
     def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None:
         """Write '#define XXX NNN' for each uop"""
         counter = 300  # TODO: Avoid collision with pseudo instructions
+        seen = set()
 
         def add(name: str) -> None:
+            if name in seen:
+                return
             nonlocal counter
             self.out.emit(make_text(name, counter))
             counter += 1
+            seen.add(name)
 
+        # These two are first by convention
         add("EXIT_TRACE")
         add("SAVE_IP")
-        add("_POP_JUMP_IF_FALSE")
-        add("_POP_JUMP_IF_TRUE")
-        add("JUMP_TO_TOP")
 
         for instr in self.instrs.values():
             if instr.kind == "op" and instr.is_viable_uop():