Skip to content

Commit 4f51fa9

Browse files
authored
bpo-44900: Add five superinstructions. (GH-27741)
* LOAD_FAST LOAD_FAST * STORE_FAST LOAD_FAST * LOAD_FAST LOAD_CONST * LOAD_CONST LOAD_FAST * STORE_FAST STORE_FAST
1 parent 1a511dc commit 4f51fa9

File tree

6 files changed

+133
-20
lines changed

6 files changed

+133
-20
lines changed

Include/opcode.h

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,13 @@ def jabs_op(name, op):
237237
"STORE_ATTR_SPLIT_KEYS",
238238
"STORE_ATTR_SLOT",
239239
"STORE_ATTR_WITH_HINT",
240+
# Super instructions
241+
"LOAD_FAST__LOAD_FAST",
242+
"STORE_FAST__LOAD_FAST",
243+
"LOAD_FAST__LOAD_CONST",
244+
"LOAD_CONST__LOAD_FAST",
245+
"STORE_FAST__STORE_FAST",
240246
]
241-
242247
_specialization_stats = [
243248
"specialization_success",
244249
"specialization_failure",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Add five superinstructions for PEP 659 quickening:
2+
3+
* LOAD_FAST LOAD_FAST
4+
* STORE_FAST LOAD_FAST
5+
* LOAD_FAST LOAD_CONST
6+
* LOAD_CONST LOAD_FAST
7+
* STORE_FAST STORE_FAST

Python/ceval.c

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,16 +1266,21 @@ eval_frame_handle_pending(PyThreadState *tstate)
12661266
#define PRE_DISPATCH_GOTO() do { LLTRACE_INSTR(); RECORD_DXPROFILE(); } while (0)
12671267
#endif
12681268

1269+
#define NOTRACE_DISPATCH() \
1270+
{ \
1271+
frame->f_lasti = INSTR_OFFSET(); \
1272+
NEXTOPARG(); \
1273+
PRE_DISPATCH_GOTO(); \
1274+
DISPATCH_GOTO(); \
1275+
}
1276+
12691277
/* Do interpreter dispatch accounting for tracing and instrumentation */
12701278
#define DISPATCH() \
12711279
{ \
12721280
if (cframe.use_tracing OR_DTRACE_LINE) { \
12731281
goto tracing_dispatch; \
12741282
} \
1275-
frame->f_lasti = INSTR_OFFSET(); \
1276-
NEXTOPARG(); \
1277-
PRE_DISPATCH_GOTO(); \
1278-
DISPATCH_GOTO(); \
1283+
NOTRACE_DISPATCH(); \
12791284
}
12801285

12811286
#define CHECK_EVAL_BREAKER() \
@@ -1682,11 +1687,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
16821687
TARGET(LOAD_FAST): {
16831688
PyObject *value = GETLOCAL(oparg);
16841689
if (value == NULL) {
1685-
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
1686-
UNBOUNDLOCAL_ERROR_MSG,
1687-
PyTuple_GetItem(co->co_localsplusnames,
1688-
oparg));
1689-
goto error;
1690+
goto unbound_local_error;
16901691
}
16911692
Py_INCREF(value);
16921693
PUSH(value);
@@ -1708,6 +1709,73 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
17081709
DISPATCH();
17091710
}
17101711

1712+
TARGET(LOAD_FAST__LOAD_FAST): {
1713+
PyObject *value = GETLOCAL(oparg);
1714+
if (value == NULL) {
1715+
goto unbound_local_error;
1716+
}
1717+
NEXTOPARG();
1718+
Py_INCREF(value);
1719+
PUSH(value);
1720+
value = GETLOCAL(oparg);
1721+
if (value == NULL) {
1722+
goto unbound_local_error;
1723+
}
1724+
Py_INCREF(value);
1725+
PUSH(value);
1726+
NOTRACE_DISPATCH();
1727+
}
1728+
1729+
TARGET(LOAD_FAST__LOAD_CONST): {
1730+
PyObject *value = GETLOCAL(oparg);
1731+
if (value == NULL) {
1732+
goto unbound_local_error;
1733+
}
1734+
NEXTOPARG();
1735+
Py_INCREF(value);
1736+
PUSH(value);
1737+
value = GETITEM(consts, oparg);
1738+
Py_INCREF(value);
1739+
PUSH(value);
1740+
NOTRACE_DISPATCH();
1741+
}
1742+
1743+
TARGET(STORE_FAST__LOAD_FAST): {
1744+
PyObject *value = POP();
1745+
SETLOCAL(oparg, value);
1746+
NEXTOPARG();
1747+
value = GETLOCAL(oparg);
1748+
if (value == NULL) {
1749+
goto unbound_local_error;
1750+
}
1751+
Py_INCREF(value);
1752+
PUSH(value);
1753+
NOTRACE_DISPATCH();
1754+
}
1755+
1756+
TARGET(STORE_FAST__STORE_FAST): {
1757+
PyObject *value = POP();
1758+
SETLOCAL(oparg, value);
1759+
NEXTOPARG();
1760+
value = POP();
1761+
SETLOCAL(oparg, value);
1762+
NOTRACE_DISPATCH();
1763+
}
1764+
1765+
TARGET(LOAD_CONST__LOAD_FAST): {
1766+
PyObject *value = GETITEM(consts, oparg);
1767+
NEXTOPARG();
1768+
Py_INCREF(value);
1769+
PUSH(value);
1770+
value = GETLOCAL(oparg);
1771+
if (value == NULL) {
1772+
goto unbound_local_error;
1773+
}
1774+
Py_INCREF(value);
1775+
PUSH(value);
1776+
NOTRACE_DISPATCH();
1777+
}
1778+
17111779
TARGET(POP_TOP): {
17121780
PyObject *value = POP();
17131781
Py_DECREF(value);
@@ -4592,6 +4660,15 @@ MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR)
45924660
goto error;
45934661
}
45944662

4663+
unbound_local_error:
4664+
{
4665+
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
4666+
UNBOUNDLOCAL_ERROR_MSG,
4667+
PyTuple_GetItem(co->co_localsplusnames, oparg)
4668+
);
4669+
goto error;
4670+
}
4671+
45954672
error:
45964673
/* Double-check exception status. */
45974674
#ifdef NDEBUG

Python/opcode_targets.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ optimize(SpecializedCacheOrInstruction *quickened, int len)
303303
_Py_CODEUNIT *instructions = first_instruction(quickened);
304304
int cache_offset = 0;
305305
int previous_opcode = -1;
306+
int previous_oparg = 0;
306307
for(int i = 0; i < len; i++) {
307308
int opcode = _Py_OPCODE(instructions[i]);
308309
int oparg = _Py_OPARG(instructions[i]);
@@ -338,14 +339,32 @@ optimize(SpecializedCacheOrInstruction *quickened, int len)
338339
case JUMP_ABSOLUTE:
339340
instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg);
340341
break;
341-
/* Insert superinstructions here
342-
E.g.
343342
case LOAD_FAST:
344-
if (previous_opcode == LOAD_FAST)
345-
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, oparg);
346-
*/
343+
switch(previous_opcode) {
344+
case LOAD_FAST:
345+
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_FAST, previous_oparg);
346+
break;
347+
case STORE_FAST:
348+
instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__LOAD_FAST, previous_oparg);
349+
break;
350+
case LOAD_CONST:
351+
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_CONST__LOAD_FAST, previous_oparg);
352+
break;
353+
}
354+
break;
355+
case STORE_FAST:
356+
if (previous_opcode == STORE_FAST) {
357+
instructions[i-1] = _Py_MAKECODEUNIT(STORE_FAST__STORE_FAST, previous_oparg);
358+
}
359+
break;
360+
case LOAD_CONST:
361+
if (previous_opcode == LOAD_FAST) {
362+
instructions[i-1] = _Py_MAKECODEUNIT(LOAD_FAST__LOAD_CONST, previous_oparg);
363+
}
364+
break;
347365
}
348366
previous_opcode = opcode;
367+
previous_oparg = oparg;
349368
}
350369
}
351370
assert(cache_offset+1 == get_cache_count(quickened));

0 commit comments

Comments
 (0)