From 345ba3f080c140dee3102f472bc166c2db191bcc Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 18 Nov 2021 18:19:58 +0900 Subject: [PATCH] bpo-45510: Specialize BINARY_SUBTRACT (GH-29523) --- Include/internal/pycore_long.h | 1 + Include/opcode.h | 68 +++++++++++++++++----------------- Lib/opcode.py | 2 + Objects/longobject.c | 14 ++++--- Python/ceval.c | 35 +++++++++++++++++ Python/opcode_targets.h | 24 ++++++------ Python/specialize.c | 13 +++++++ 7 files changed, 107 insertions(+), 50 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 2f786083e45..b9f926996d8 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -23,6 +23,7 @@ static inline PyObject* _PyLong_GetOne(void) PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); +PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right); /* Used by Python/mystrtoul.c, _PyBytes_FromHex(), _PyBytes_DecodeEscape(), etc. */ diff --git a/Include/opcode.h b/Include/opcode.h index c7354de9a06..ca20ccda119 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -118,39 +118,41 @@ extern "C" { #define BINARY_OP_INPLACE_ADD_UNICODE 16 #define BINARY_OP_MULTIPLY_INT 17 #define BINARY_OP_MULTIPLY_FLOAT 18 -#define BINARY_SUBSCR_ADAPTIVE 19 -#define BINARY_SUBSCR_LIST_INT 20 -#define BINARY_SUBSCR_TUPLE_INT 21 -#define BINARY_SUBSCR_DICT 22 -#define CALL_FUNCTION_ADAPTIVE 23 -#define CALL_FUNCTION_BUILTIN_O 24 -#define CALL_FUNCTION_BUILTIN_FAST 26 -#define CALL_FUNCTION_LEN 27 -#define CALL_FUNCTION_ISINSTANCE 28 -#define CALL_FUNCTION_PY_SIMPLE 29 -#define JUMP_ABSOLUTE_QUICK 34 -#define LOAD_ATTR_ADAPTIVE 36 -#define LOAD_ATTR_INSTANCE_VALUE 38 -#define LOAD_ATTR_WITH_HINT 39 -#define LOAD_ATTR_SLOT 40 -#define LOAD_ATTR_MODULE 41 -#define LOAD_GLOBAL_ADAPTIVE 42 -#define LOAD_GLOBAL_MODULE 43 -#define LOAD_GLOBAL_BUILTIN 44 -#define LOAD_METHOD_ADAPTIVE 45 -#define LOAD_METHOD_CACHED 46 -#define LOAD_METHOD_CLASS 47 -#define LOAD_METHOD_MODULE 48 -#define LOAD_METHOD_NO_DICT 55 -#define STORE_ATTR_ADAPTIVE 56 -#define STORE_ATTR_INSTANCE_VALUE 57 -#define STORE_ATTR_SLOT 58 -#define STORE_ATTR_WITH_HINT 59 -#define LOAD_FAST__LOAD_FAST 62 -#define STORE_FAST__LOAD_FAST 63 -#define LOAD_FAST__LOAD_CONST 64 -#define LOAD_CONST__LOAD_FAST 65 -#define STORE_FAST__STORE_FAST 66 +#define BINARY_OP_SUBTRACT_INT 19 +#define BINARY_OP_SUBTRACT_FLOAT 20 +#define BINARY_SUBSCR_ADAPTIVE 21 +#define BINARY_SUBSCR_LIST_INT 22 +#define BINARY_SUBSCR_TUPLE_INT 23 +#define BINARY_SUBSCR_DICT 24 +#define CALL_FUNCTION_ADAPTIVE 26 +#define CALL_FUNCTION_BUILTIN_O 27 +#define CALL_FUNCTION_BUILTIN_FAST 28 +#define CALL_FUNCTION_LEN 29 +#define CALL_FUNCTION_ISINSTANCE 34 +#define CALL_FUNCTION_PY_SIMPLE 36 +#define JUMP_ABSOLUTE_QUICK 38 +#define LOAD_ATTR_ADAPTIVE 39 +#define LOAD_ATTR_INSTANCE_VALUE 40 +#define LOAD_ATTR_WITH_HINT 41 +#define LOAD_ATTR_SLOT 42 +#define LOAD_ATTR_MODULE 43 +#define LOAD_GLOBAL_ADAPTIVE 44 +#define LOAD_GLOBAL_MODULE 45 +#define LOAD_GLOBAL_BUILTIN 46 +#define LOAD_METHOD_ADAPTIVE 47 +#define LOAD_METHOD_CACHED 48 +#define LOAD_METHOD_CLASS 55 +#define LOAD_METHOD_MODULE 56 +#define LOAD_METHOD_NO_DICT 57 +#define STORE_ATTR_ADAPTIVE 58 +#define STORE_ATTR_INSTANCE_VALUE 59 +#define STORE_ATTR_SLOT 62 +#define STORE_ATTR_WITH_HINT 63 +#define LOAD_FAST__LOAD_FAST 64 +#define STORE_FAST__LOAD_FAST 65 +#define LOAD_FAST__LOAD_CONST 66 +#define LOAD_CONST__LOAD_FAST 67 +#define STORE_FAST__STORE_FAST 75 #define DO_TRACING 255 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { diff --git a/Lib/opcode.py b/Lib/opcode.py index 940e169d559..4abe99fcbec 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -231,6 +231,8 @@ _specialized_instructions = [ "BINARY_OP_INPLACE_ADD_UNICODE", "BINARY_OP_MULTIPLY_INT", "BINARY_OP_MULTIPLY_FLOAT", + "BINARY_OP_SUBTRACT_INT", + "BINARY_OP_SUBTRACT_FLOAT", "BINARY_SUBSCR_ADAPTIVE", "BINARY_SUBSCR_LIST_INT", "BINARY_SUBSCR_TUPLE_INT", diff --git a/Objects/longobject.c b/Objects/longobject.c index a4d90b17043..ce4f0d72540 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3155,14 +3155,11 @@ long_add(PyLongObject *a, PyLongObject *b) return _PyLong_Add(a, b); } - -static PyObject * -long_sub(PyLongObject *a, PyLongObject *b) +PyObject * +_PyLong_Subtract(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - CHECK_BINOP(a, b); - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } @@ -3187,6 +3184,13 @@ long_sub(PyLongObject *a, PyLongObject *b) return (PyObject *)z; } +static PyObject * +long_sub(PyLongObject *a, PyLongObject *b) +{ + CHECK_BINOP(a, b); + return _PyLong_Subtract(a, b); +} + /* Grade school multiplication, ignoring the signs. * Returns the absolute value of the product, or NULL if error. */ diff --git a/Python/ceval.c b/Python/ceval.c index c02e3517d44..e579edefdb7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2009,6 +2009,41 @@ check_eval_breaker: DISPATCH(); } + TARGET(BINARY_OP_SUBTRACT_INT) { + PyObject *left = SECOND(); + PyObject *right = TOP(); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + STAT_INC(BINARY_OP, hit); + PyObject *sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); + SET_SECOND(sub); + Py_DECREF(right); + Py_DECREF(left); + STACK_SHRINK(1); + if (sub == NULL) { + goto error; + } + DISPATCH(); + } + + TARGET(BINARY_OP_SUBTRACT_FLOAT) { + PyObject *left = SECOND(); + PyObject *right = TOP(); + DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + STAT_INC(BINARY_OP, hit); + double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; + PyObject *sub = PyFloat_FromDouble(dsub); + SET_SECOND(sub); + Py_DECREF(right); + Py_DECREF(left); + STACK_SHRINK(1); + if (sub == NULL) { + goto error; + } + DISPATCH(); + } + TARGET(BINARY_OP_ADD_UNICODE) { PyObject *left = SECOND(); PyObject *right = TOP(); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index a57617e022e..07852d167c7 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -18,25 +18,27 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_BINARY_OP_SUBTRACT_INT, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_BINARY_SUBSCR_ADAPTIVE, &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_BINARY_SUBSCR_DICT, + &&TARGET_BINARY_SUBSCR, &&TARGET_CALL_FUNCTION_ADAPTIVE, &&TARGET_CALL_FUNCTION_BUILTIN_O, - &&TARGET_BINARY_SUBSCR, &&TARGET_CALL_FUNCTION_BUILTIN_FAST, &&TARGET_CALL_FUNCTION_LEN, - &&TARGET_CALL_FUNCTION_ISINSTANCE, - &&TARGET_CALL_FUNCTION_PY_SIMPLE, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_JUMP_ABSOLUTE_QUICK, + &&TARGET_CALL_FUNCTION_ISINSTANCE, &&TARGET_PUSH_EXC_INFO, - &&TARGET_LOAD_ATTR_ADAPTIVE, + &&TARGET_CALL_FUNCTION_PY_SIMPLE, &&TARGET_POP_EXCEPT_AND_RERAISE, + &&TARGET_JUMP_ABSOLUTE_QUICK, + &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_SLOT, @@ -46,27 +48,25 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_LOAD_METHOD_CACHED, - &&TARGET_LOAD_METHOD_CLASS, - &&TARGET_LOAD_METHOD_MODULE, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, + &&TARGET_LOAD_METHOD_CLASS, + &&TARGET_LOAD_METHOD_MODULE, &&TARGET_LOAD_METHOD_NO_DICT, &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_CONST__LOAD_FAST, - &&TARGET_STORE_FAST__STORE_FAST, - &&_unknown_opcode, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, @@ -74,7 +74,7 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_FROM, &&TARGET_GET_AWAITABLE, &&TARGET_LOAD_ASSERTION_ERROR, - &&_unknown_opcode, + &&TARGET_STORE_FAST__STORE_FAST, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index cfc21bf70ad..dd15de72d27 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1424,6 +1424,19 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, goto success; } break; + case NB_SUBTRACT: + case NB_INPLACE_SUBTRACT: + if (PyLong_CheckExact(lhs)) { + *instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_INT, + _Py_OPARG(*instr)); + goto success; + } + if (PyFloat_CheckExact(lhs)) { + *instr = _Py_MAKECODEUNIT(BINARY_OP_SUBTRACT_FLOAT, + _Py_OPARG(*instr)); + goto success; + } + break; default: // These operators don't have any available specializations. Rather // than repeatedly attempting to specialize them, just convert them