Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Perform the inplace checks when specializing
  • Loading branch information
brandtbucher committed Jan 19, 2022
commit d6a69d583422a7e9b38d6e5b893572b22c9245fb
62 changes: 29 additions & 33 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -857,11 +857,6 @@ static const binaryfunc binary_ops[] = {
[NB_INPLACE_XOR] = PyNumber_InPlaceXor,
};

#define NEXT_OP_STORES(O) \
((_Py_OPCODE(*next_instr) == STORE_FAST || \
_Py_OPCODE(*next_instr) == STORE_FAST__LOAD_FAST) && \
GETLOCAL(_Py_OPARG(*next_instr)) == (O)) \

#define BINARY_OP_FAST_INT(OP) \
do { \
PyObject *lhs = SECOND(); \
Expand All @@ -885,13 +880,13 @@ static const binaryfunc binary_ops[] = {
SET_TOP((PyObject *)res); \
DISPATCH(); \
} \
bool inplace = NEXT_OP_STORES(lhs); \
uint16_t maybe_store = GET_CACHE()->adaptive.index; \
bool inplace = maybe_store && GETLOCAL(maybe_store - 1) == lhs; \
if (Py_ABS(i) < PyLong_BASE && Py_REFCNT(lhs) == inplace + 1) { \
/* If this assert fails, it's probably one of two things: */ \
/* - If lhs lives in _PyLong_SMALL_INTS, its refcount is wrong. */ \
/* - Otherwise, whatever created lhs should have used */ \
/* _PyLong_SMALL_INTS, but didn't (see bpo-46361 for an */ \
/* example of this.) */ \
/* - Whatever created lhs should have used _PyLong_SMALL_INTS, */ \
/* but didn't. Examples of this can be found in bpo-46361. */ \
assert(l < -_PY_NSMALLNEGINTS || _PY_NSMALLPOSINTS <= l); \
lhs_long->ob_digit[0] = (digit)Py_ABS(i); \
Py_SET_SIZE(lhs, i < 0 ? -1 : 1); \
Expand All @@ -906,30 +901,31 @@ static const binaryfunc binary_ops[] = {
DISPATCH(); \
} while (0)

#define BINARY_OP_FAST_FLOAT(OP) \
do { \
PyObject *lhs = SECOND(); \
PyObject *rhs = TOP(); \
DEOPT_IF(!PyFloat_CheckExact(lhs), BINARY_OP); \
DEOPT_IF(!PyFloat_CheckExact(rhs), BINARY_OP); \
STAT_INC(BINARY_OP, hit); \
double l = PyFloat_AS_DOUBLE(lhs); \
double r = PyFloat_AS_DOUBLE(rhs); \
double d = l OP r; \
Py_DECREF(rhs); \
STACK_SHRINK(1); \
bool inplace = NEXT_OP_STORES(lhs); \
if (Py_REFCNT(lhs) == inplace + 1) { \
PyFloat_AS_DOUBLE(lhs) = d; \
DISPATCH(); \
} \
Py_DECREF(lhs); \
PyObject *res = PyFloat_FromDouble(d); \
SET_TOP(res); \
if (res == NULL) { \
goto error; \
} \
DISPATCH(); \
#define BINARY_OP_FAST_FLOAT(OP) \
do { \
PyObject *lhs = SECOND(); \
PyObject *rhs = TOP(); \
DEOPT_IF(!PyFloat_CheckExact(lhs), BINARY_OP); \
DEOPT_IF(!PyFloat_CheckExact(rhs), BINARY_OP); \
STAT_INC(BINARY_OP, hit); \
double l = PyFloat_AS_DOUBLE(lhs); \
double r = PyFloat_AS_DOUBLE(rhs); \
double d = l OP r; \
Py_DECREF(rhs); \
STACK_SHRINK(1); \
uint16_t maybe_store = GET_CACHE()->adaptive.index; \
bool inplace = maybe_store && GETLOCAL(maybe_store - 1) == lhs; \
if (Py_REFCNT(lhs) == inplace + 1) { \
PyFloat_AS_DOUBLE(lhs) = d; \
DISPATCH(); \
} \
Py_DECREF(lhs); \
PyObject *res = PyFloat_FromDouble(d); \
SET_TOP(res); \
if (res == NULL) { \
goto error; \
} \
DISPATCH(); \
} while (0)

// PEP 634: Structural Pattern Matching
Expand Down
30 changes: 24 additions & 6 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -1624,13 +1624,19 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
if (PyLong_CheckExact(lhs) &&
Py_ABS(Py_SIZE(lhs)) < 2 && Py_ABS(Py_SIZE(rhs)) < 2)
{
int next_opcode = _Py_OPCODE(instr[1]);
Comment thread
brandtbucher marked this conversation as resolved.
Outdated
if (next_opcode == STORE_FAST ||
next_opcode == STORE_FAST__LOAD_FAST)
{
adaptive->index = _Py_OPARG(instr[1]) + 1;
}
*instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_INT, _Py_OPARG(*instr));
goto success;
goto success_set_index;
}
if (PyFloat_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_ADD_FLOAT,
_Py_OPARG(*instr));
goto success;
goto success_set_index;
}
break;
case NB_MULTIPLY:
Expand All @@ -1644,12 +1650,12 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
{
*instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_INT,
_Py_OPARG(*instr));
goto success;
goto success_set_index;
}
if (PyFloat_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_MULTIPLY_FLOAT,
_Py_OPARG(*instr));
goto success;
goto success_set_index;
}
break;
case NB_SUBTRACT:
Expand All @@ -1663,12 +1669,12 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
{
*instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_INT,
_Py_OPARG(*instr));
goto success;
goto success_set_index;
}
if (PyFloat_CheckExact(lhs)) {
*instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_FLOAT,
_Py_OPARG(*instr));
goto success;
goto success_set_index;
}
break;
default:
Expand All @@ -1682,6 +1688,18 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
STAT_INC(BINARY_OP, failure);
cache_backoff(adaptive);
return;
success_set_index:
; // The technology just isn't there yet...
int next_opcode = _Py_OPCODE(instr[1]);
int next_oparg = _Py_OPARG(instr[1]);
if ((next_opcode == STORE_FAST || next_opcode == STORE_FAST__LOAD_FAST) &&
next_oparg < UINT16_MAX)
{
adaptive->index = next_oparg + 1;
}
else {
adaptive->index = 0;
}
success:
STAT_INC(BINARY_OP, success);
adaptive->counter = initial_counter_value();
Expand Down