summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_opcode_metadata.h100
-rw-r--r--Python/bytecodes.c30
-rw-r--r--Python/ceval.c40
-rw-r--r--Python/executor_cases.c.h36
-rw-r--r--Tools/cases_generator/generate_cases.py12
5 files changed, 124 insertions, 94 deletions
diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h
index 79bbe9a..c886407 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 176dbb5..1fe9970 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 de44085..d6c72fa 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 805ea06..ce54755 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 ba4ef1e..ce16271 100644
--- a/Tools/cases_generator/generate_cases.py
+++ b/Tools/cases_generator/generate_cases.py
@@ -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():