diff --git a/Include/opcode.h b/Include/opcode.h index 50b783289590da..3334242e7e4d40 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -153,6 +153,11 @@ extern "C" { #define STORE_ATTR_SPLIT_KEYS 45 #define STORE_ATTR_SLOT 46 #define STORE_ATTR_WITH_HINT 47 +#define LOAD_FAST__LOAD_FAST 48 +#define STORE_FAST__LOAD_FAST 58 +#define LOAD_FAST__LOAD_CONST 80 +#define LOAD_CONST__LOAD_FAST 81 +#define STORE_FAST__STORE_FAST 87 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { 0U, diff --git a/Lib/opcode.py b/Lib/opcode.py index 061506d0b88bd9..53cdc4aa0d549d 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -237,8 +237,13 @@ def jabs_op(name, op): "STORE_ATTR_SPLIT_KEYS", "STORE_ATTR_SLOT", "STORE_ATTR_WITH_HINT", + # Super instructions + "LOAD_FAST__LOAD_FAST", + "STORE_FAST__LOAD_FAST", + "LOAD_FAST__LOAD_CONST", + "LOAD_CONST__LOAD_FAST", + "STORE_FAST__STORE_FAST", ] - _specialization_stats = [ "specialization_success", "specialization_failure", diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-12-14-00-57.bpo-44900.w2gpwy.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-12-14-00-57.bpo-44900.w2gpwy.rst new file mode 100644 index 00000000000000..8d94d6aed80ead --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-12-14-00-57.bpo-44900.w2gpwy.rst @@ -0,0 +1,7 @@ +Add five superinstructions for PEP 659 quickening: + +* LOAD_FAST LOAD_FAST +* STORE_FAST LOAD_FAST +* LOAD_FAST LOAD_CONST +* LOAD_CONST LOAD_FAST +* STORE_FAST STORE_FAST diff --git a/Python/ceval.c b/Python/ceval.c index f494e8477fac71..ce370f65664189 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1266,16 +1266,21 @@ eval_frame_handle_pending(PyThreadState *tstate) #define PRE_DISPATCH_GOTO() do { LLTRACE_INSTR(); RECORD_DXPROFILE(); } while (0) #endif +#define NOTRACE_DISPATCH() \ + { \ + frame->f_lasti = INSTR_OFFSET(); \ + NEXTOPARG(); \ + PRE_DISPATCH_GOTO(); \ + DISPATCH_GOTO(); \ + } + /* Do interpreter dispatch accounting for tracing and instrumentation */ #define DISPATCH() \ { \ if (cframe.use_tracing OR_DTRACE_LINE) { \ goto tracing_dispatch; \ } \ - frame->f_lasti = INSTR_OFFSET(); \ - NEXTOPARG(); \ - PRE_DISPATCH_GOTO(); \ - DISPATCH_GOTO(); \ + NOTRACE_DISPATCH(); \ } #define CHECK_EVAL_BREAKER() \ @@ -1682,11 +1687,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr TARGET(LOAD_FAST): { PyObject *value = GETLOCAL(oparg); if (value == NULL) { - format_exc_check_arg(tstate, PyExc_UnboundLocalError, - UNBOUNDLOCAL_ERROR_MSG, - PyTuple_GetItem(co->co_localsplusnames, - oparg)); - goto error; + goto unbound_local_error; } Py_INCREF(value); PUSH(value); @@ -1708,6 +1709,73 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr DISPATCH(); } + TARGET(LOAD_FAST__LOAD_FAST): { + PyObject *value = GETLOCAL(oparg); + if (value == NULL) { + goto unbound_local_error; + } + NEXTOPARG(); + Py_INCREF(value); + PUSH(value); + value = GETLOCAL(oparg); + if (value == NULL) { + goto unbound_local_error; + } + Py_INCREF(value); + PUSH(value); + NOTRACE_DISPATCH(); + } + + TARGET(LOAD_FAST__LOAD_CONST): { + PyObject *value = GETLOCAL(oparg); + if (value == NULL) { + goto unbound_local_error; + } + NEXTOPARG(); + Py_INCREF(value); + PUSH(value); + value = GETITEM(consts, oparg); + Py_INCREF(value); + PUSH(value); + NOTRACE_DISPATCH(); + } + + TARGET(STORE_FAST__LOAD_FAST): { + PyObject *value = POP(); + SETLOCAL(oparg, value); + NEXTOPARG(); + value = GETLOCAL(oparg); + if (value == NULL) { + goto unbound_local_error; + } + Py_INCREF(value); + PUSH(value); + NOTRACE_DISPATCH(); + } + + TARGET(STORE_FAST__STORE_FAST): { + PyObject *value = POP(); + SETLOCAL(oparg, value); + NEXTOPARG(); + value = POP(); + SETLOCAL(oparg, value); + NOTRACE_DISPATCH(); + } + + TARGET(LOAD_CONST__LOAD_FAST): { + PyObject *value = GETITEM(consts, oparg); + NEXTOPARG(); + Py_INCREF(value); + PUSH(value); + value = GETLOCAL(oparg); + if (value == NULL) { + goto unbound_local_error; + } + Py_INCREF(value); + PUSH(value); + NOTRACE_DISPATCH(); + } + TARGET(POP_TOP): { PyObject *value = POP(); Py_DECREF(value); @@ -4592,6 +4660,15 @@ MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR) goto error; } +unbound_local_error: + { + format_exc_check_arg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(co->co_localsplusnames, oparg) + ); + goto error; + } + error: /* Double-check exception status. */ #ifdef NDEBUG diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 24ee44f2d08c07..c8036a63f22011 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -47,7 +47,7 @@ static void *opcode_targets[256] = { &&TARGET_STORE_ATTR_SPLIT_KEYS, &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, - &&_unknown_opcode, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -57,7 +57,7 @@ static void *opcode_targets[256] = { &&TARGET_INPLACE_ADD, &&TARGET_INPLACE_SUBTRACT, &&TARGET_INPLACE_MULTIPLY, - &&_unknown_opcode, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_INPLACE_MODULO, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, @@ -79,14 +79,14 @@ static void *opcode_targets[256] = { &&TARGET_INPLACE_AND, &&TARGET_INPLACE_XOR, &&TARGET_INPLACE_OR, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, &&TARGET_YIELD_VALUE, - &&_unknown_opcode, + &&TARGET_STORE_FAST__STORE_FAST, &&_unknown_opcode, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, diff --git a/Python/specialize.c b/Python/specialize.c index f0d68f027d6464..988e42d78a792f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -303,6 +303,7 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) _Py_CODEUNIT *instructions = first_instruction(quickened); int cache_offset = 0; int previous_opcode = -1; + int previous_oparg = 0; for(int i = 0; i < len; i++) { int opcode = _Py_OPCODE(instructions[i]); int oparg = _Py_OPARG(instructions[i]); @@ -338,14 +339,32 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) case JUMP_ABSOLUTE: instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg); break; - /* Insert superinstructions here - E.g. case LOAD_FAST: - if (previous_opcode == LOAD_FAST) - instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, oparg); - */ + switch(previous_opcode) { + case LOAD_FAST: + instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, previous_oparg); + break; + case STORE_FAST: + instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__LOAD_FAST, previous_oparg); + break; + case LOAD_CONST: + instructions[i-1] = _Py_MAKECODEUNIT(LOAD_CONST__LOAD_FAST, previous_oparg); + break; + } + break; + case STORE_FAST: + if (previous_opcode == STORE_FAST) { + instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__STORE_FAST, previous_oparg); + } + break; + case LOAD_CONST: + if (previous_opcode == LOAD_FAST) { + instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_CONST, previous_oparg); + } + break; } previous_opcode = opcode; + previous_oparg = oparg; } } assert(cache_offset+1 == get_cache_count(quickened));