diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 79bbe9a916f596..c88640777e3fb0 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -21,30 +21,30 @@ #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 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 176dbb584d0987..1fe9970e53cdfe 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -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 // diff --git a/Python/ceval.c b/Python/ceval.c index de44085d732cfa..d6c72fa3ff386c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 805ea06e072167..ce54755d5d25f1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1987,3 +1987,39 @@ 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; + } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ba4ef1ee97693e..ce16271097b955 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -410,6 +410,8 @@ def __init__(self, inst: parser.InstDef): 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 @@ def write_metadata(self) -> None: 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 @@ def write_pseudo_instrs(self) -> None: 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():