diff options
-rw-r--r-- | Doc/library/dis.rst | 14 | ||||
-rw-r--r-- | Doc/whatsnew/3.11.rst | 3 | ||||
-rw-r--r-- | Include/opcode.h | 12 | ||||
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 3 | ||||
-rw-r--r-- | Lib/opcode.py | 4 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst | 1 | ||||
-rw-r--r-- | Python/ceval.c | 24 | ||||
-rw-r--r-- | Python/compile.c | 27 | ||||
-rw-r--r-- | Python/opcode_targets.h | 12 |
9 files changed, 86 insertions, 14 deletions
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 8490a09..7afa62f 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -896,6 +896,20 @@ All of the following opcodes use their arguments. .. versionadded:: 3.11 +.. opcode:: POP_JUMP_IF_NOT_NONE (target) + + If TOS is not none, sets the bytecode counter to *target*. TOS is popped. + + .. versionadded:: 3.11 + + +.. opcode:: POP_JUMP_IF_NONE (target) + + If TOS is none, sets the bytecode counter to *target*. TOS is popped. + + .. versionadded:: 3.11 + + .. opcode:: PREP_RERAISE_STAR Combines the raised and reraised exceptions list from TOS, into an exception diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 6794e82..98ff2d4 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -398,6 +398,9 @@ CPython bytecode changes * Added :opcode:`COPY`, which pushes the *i*-th item to the top of the stack. The item is not removed from its original location. +* Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to + speed up conditional jumps. + * :opcode:`JUMP_IF_NOT_EXC_MATCH` no longer pops the active exception. diff --git a/Include/opcode.h b/Include/opcode.h index 1af5494..e4deeec 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -84,6 +84,8 @@ extern "C" { #define STORE_FAST 125 #define DELETE_FAST 126 #define JUMP_IF_NOT_EG_MATCH 127 +#define POP_JUMP_IF_NOT_NONE 128 +#define POP_JUMP_IF_NONE 129 #define RAISE_VARARGS 130 #define MAKE_FUNCTION 132 #define BUILD_SLICE 133 @@ -162,10 +164,10 @@ extern "C" { #define STORE_ATTR_SLOT 80 #define STORE_ATTR_WITH_HINT 81 #define LOAD_FAST__LOAD_FAST 87 -#define STORE_FAST__LOAD_FAST 128 -#define LOAD_FAST__LOAD_CONST 129 -#define LOAD_CONST__LOAD_FAST 131 -#define STORE_FAST__STORE_FAST 134 +#define STORE_FAST__LOAD_FAST 131 +#define LOAD_FAST__LOAD_CONST 134 +#define LOAD_CONST__LOAD_FAST 140 +#define STORE_FAST__STORE_FAST 141 #define DO_TRACING 255 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { @@ -183,7 +185,7 @@ static uint32_t _PyOpcode_Jump[8] = { 0U, 536870912U, 2316288000U, - 0U, + 3U, 0U, 0U, 0U, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 872d6d9..8e21be5 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -378,6 +378,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.11a4 3470 (bpo-46221: PREP_RERAISE_STAR no longer pushes lasti) # Python 3.11a4 3471 (bpo-46202: remove pop POP_EXCEPT_AND_RERAISE) # Python 3.11a4 3472 (bpo-46009: replace GEN_START with POP_TOP) +# Python 3.11a4 3473 (Add POP_JUMP_IF_NOT_NONE/POP_JUMP_IF_NONE opcodes) # # MAGIC must change whenever the bytecode emitted by the compiler may no @@ -387,7 +388,7 @@ _code_type = type(_write_atomic.__code__) # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3472).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3473).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index f99e20a..6030743 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -148,9 +148,9 @@ def_op('STORE_FAST', 125) # Local variable number haslocal.append(125) def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) - jabs_op('JUMP_IF_NOT_EG_MATCH', 127) - +jabs_op('POP_JUMP_IF_NOT_NONE', 128) +jabs_op('POP_JUMP_IF_NONE', 129) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('MAKE_FUNCTION', 132) # Flags diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst new file mode 100644 index 0000000..65c8b38 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst @@ -0,0 +1 @@ +Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to speed up conditional jumps.
\ No newline at end of file diff --git a/Python/ceval.c b/Python/ceval.c index b4ac9ec..86d834c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4049,6 +4049,30 @@ check_eval_breaker: DISPATCH(); } + TARGET(POP_JUMP_IF_NOT_NONE) { + PyObject *value = POP(); + if (!Py_IsNone(value)) { + Py_DECREF(value); + JUMPTO(oparg); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + Py_DECREF(value); + DISPATCH(); + } + + TARGET(POP_JUMP_IF_NONE) { + PyObject *value = POP(); + if (Py_IsNone(value)) { + Py_DECREF(value); + JUMPTO(oparg); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + Py_DECREF(value); + DISPATCH(); + } + TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = TOP(); int err; diff --git a/Python/compile.c b/Python/compile.c index 3a39075..625a07b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1110,6 +1110,8 @@ stack_effect(int opcode, int oparg, int jump) case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: + case POP_JUMP_IF_NONE: + case POP_JUMP_IF_NOT_NONE: return -1; case LOAD_GLOBAL: @@ -8519,6 +8521,21 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) bb->b_instr[i+1].i_opcode = NOP; } break; + case IS_OP: + cnt = get_const_value(inst->i_opcode, oparg, consts); + if (cnt == NULL) { + goto error; + } + int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0; + if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) { + unsigned char nextarg = bb->b_instr[i+1].i_oparg; + inst->i_opcode = NOP; + bb->b_instr[i+1].i_opcode = NOP; + bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ? + POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE; + } + Py_DECREF(cnt); + break; } break; } @@ -8611,6 +8628,14 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) break; } break; + case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_NONE: + switch (target->i_opcode) { + case JUMP_ABSOLUTE: + case JUMP_FORWARD: + i -= jump_thread(inst, target, inst->i_opcode); + } + break; case POP_JUMP_IF_FALSE: switch (target->i_opcode) { case JUMP_ABSOLUTE: @@ -8766,6 +8791,8 @@ normalize_basic_block(basicblock *bb) { case JUMP_FORWARD: bb->b_nofallthrough = 1; /* fall through */ + case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_NONE: case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case JUMP_IF_FALSE_OR_POP: diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index e9f1a48..7ba4566 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -127,20 +127,20 @@ static void *opcode_targets[256] = { &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, &&TARGET_JUMP_IF_NOT_EG_MATCH, - &&TARGET_STORE_FAST__LOAD_FAST, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_POP_JUMP_IF_NOT_NONE, + &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, - &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, - &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_MAKE_CELL, &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_CALL_FUNCTION_EX, &&_unknown_opcode, &&TARGET_EXTENDED_ARG, |