Skip to content

Commit 74ceb37

Browse files
committed
Initial implementation of INPLACE_MULTIPLY specialization
1 parent 9ce9cfe commit 74ceb37

File tree

6 files changed

+216
-67
lines changed

6 files changed

+216
-67
lines changed

Include/internal/pycore_code.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNI
308308
int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
309309
int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr);
310310
int _Py_Specialize_BinaryAdd(PyObject *left, PyObject *right, _Py_CODEUNIT *instr);
311+
int _Py_Specialize_InplaceAdd(PyObject *left, PyObject *right, _Py_CODEUNIT *instr);
311312
int _Py_Specialize_BinaryMultiply(PyObject *left, PyObject *right, _Py_CODEUNIT *instr);
312313

313314
#define PRINT_SPECIALIZATION_STATS 0

Include/opcode.h

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

Lib/opcode.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ def jabs_op(name, op):
225225
"BINARY_ADD_FLOAT",
226226
"BINARY_ADD_UNICODE",
227227
"BINARY_ADD_UNICODE_INPLACE_FAST",
228+
"INPLACE_ADD_ADAPTIVE",
229+
"INPLACE_ADD_INT",
230+
"INPLACE_ADD_FLOAT",
231+
"INPLACE_ADD_UNICODE",
232+
"INPLACE_ADD_UNICODE_FAST",
228233
"BINARY_MULTIPLY_ADAPTIVE",
229234
"BINARY_MULTIPLY_INT",
230235
"BINARY_MULTIPLY_FLOAT",

Python/ceval.c

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,21 +2446,113 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
24462446
}
24472447

24482448
TARGET(INPLACE_ADD) {
2449+
PREDICTED(INPLACE_ADD);
2450+
STAT_INC(INPLACE_ADD, unquickened);
24492451
PyObject *right = POP();
24502452
PyObject *left = TOP();
2451-
PyObject *sum;
2452-
if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) {
2453-
sum = unicode_concatenate(tstate, left, right, frame, next_instr);
2454-
/* unicode_concatenate consumed the ref to left */
2453+
PyObject *sum = PyNumber_InPlaceAdd(left, right);
2454+
Py_DECREF(left);
2455+
Py_DECREF(right);
2456+
SET_TOP(sum);
2457+
if (sum == NULL)
2458+
goto error;
2459+
DISPATCH();
2460+
}
2461+
2462+
TARGET(INPLACE_ADD_ADAPTIVE) {
2463+
if (oparg == 0) {
2464+
PyObject *left = SECOND();
2465+
PyObject *right = TOP();
2466+
next_instr--;
2467+
if (_Py_Specialize_InplaceAdd(left, right, next_instr) < 0) {
2468+
goto error;
2469+
}
2470+
DISPATCH();
24552471
}
24562472
else {
2457-
sum = PyNumber_InPlaceAdd(left, right);
2458-
Py_DECREF(left);
2473+
STAT_INC(INPLACE_ADD, deferred);
2474+
UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
2475+
STAT_DEC(INPLACE_ADD, unquickened);
2476+
JUMP_TO_INSTRUCTION(INPLACE_ADD);
24592477
}
2478+
}
2479+
2480+
TARGET(INPLACE_ADD_INT) {
2481+
PyObject *left = SECOND();
2482+
PyObject *right = TOP();
2483+
DEOPT_IF(!PyLong_CheckExact(left), INPLACE_ADD);
2484+
DEOPT_IF(!PyLong_CheckExact(right), INPLACE_ADD);
2485+
STAT_INC(INPLACE_ADD, hit);
2486+
record_hit_inline(next_instr, oparg);
2487+
PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
2488+
SET_SECOND(sum);
2489+
Py_DECREF(left);
24602490
Py_DECREF(right);
2461-
SET_TOP(sum);
2462-
if (sum == NULL)
2491+
STACK_SHRINK(1);
2492+
if (sum == NULL) {
24632493
goto error;
2494+
}
2495+
DISPATCH();
2496+
}
2497+
2498+
TARGET(INPLACE_ADD_FLOAT) {
2499+
PyObject *left = SECOND();
2500+
PyObject *right = TOP();
2501+
DEOPT_IF(!PyFloat_CheckExact(left), INPLACE_ADD);
2502+
DEOPT_IF(!PyFloat_CheckExact(right), INPLACE_ADD);
2503+
STAT_INC(INPLACE_ADD, hit);
2504+
record_hit_inline(next_instr, oparg);
2505+
double dsum = ((PyFloatObject *)left)->ob_fval +
2506+
((PyFloatObject *)right)->ob_fval;
2507+
PyObject *sum = PyFloat_FromDouble(dsum);
2508+
SET_SECOND(sum);
2509+
Py_DECREF(left);
2510+
Py_DECREF(right);
2511+
STACK_SHRINK(1);
2512+
if (sum == NULL) {
2513+
goto error;
2514+
}
2515+
DISPATCH();
2516+
}
2517+
2518+
TARGET(INPLACE_ADD_UNICODE) {
2519+
PyObject *left = SECOND();
2520+
PyObject *right = TOP();
2521+
DEOPT_IF(!PyUnicode_CheckExact(left), INPLACE_ADD);
2522+
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), INPLACE_ADD);
2523+
STAT_INC(BINARY_ADD, hit);
2524+
record_hit_inline(next_instr, oparg);
2525+
PyObject *res = PyUnicode_Concat(left, right);
2526+
STACK_SHRINK(1);
2527+
SET_TOP(res);
2528+
Py_DECREF(left);
2529+
Py_DECREF(right);
2530+
if (TOP() == NULL) {
2531+
goto error;
2532+
}
2533+
DISPATCH();
2534+
}
2535+
2536+
TARGET(INPLACE_ADD_UNICODE_FAST) {
2537+
PyObject *left = SECOND();
2538+
PyObject *right = TOP();
2539+
DEOPT_IF(!PyUnicode_CheckExact(left), INPLACE_ADD);
2540+
DEOPT_IF(!PyUnicode_CheckExact(right), INPLACE_ADD);
2541+
DEOPT_IF(Py_REFCNT(left) != 2, INPLACE_ADD);
2542+
int next_oparg = _Py_OPARG(*next_instr);
2543+
assert(_Py_OPCODE(*next_instr) == STORE_FAST);
2544+
PyObject *var = GETLOCAL(next_oparg);
2545+
DEOPT_IF(var != left, INPLACE_ADD);
2546+
STAT_INC(INPLACE_ADD, hit);
2547+
record_hit_inline(next_instr, oparg);
2548+
GETLOCAL(next_oparg) = NULL;
2549+
Py_DECREF(left);
2550+
STACK_SHRINK(1);
2551+
PyUnicode_Append(&TOP(), right);
2552+
Py_DECREF(right);
2553+
if (TOP() == NULL) {
2554+
goto error;
2555+
}
24642556
DISPATCH();
24652557
}
24662558

@@ -5013,6 +5105,7 @@ MISS_WITH_CACHE(LOAD_GLOBAL)
50135105
MISS_WITH_CACHE(LOAD_METHOD)
50145106
MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR)
50155107
MISS_WITH_OPARG_COUNTER(BINARY_ADD)
5108+
MISS_WITH_OPARG_COUNTER(INPLACE_ADD)
50165109
MISS_WITH_OPARG_COUNTER(BINARY_MULTIPLY)
50175110

50185111
binary_subscr_dict_error:

Python/opcode_targets.h

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

0 commit comments

Comments
 (0)