mirror of
https://github.com/python/cpython.git
synced 2026-04-20 02:40:59 +00:00
gh-100239: Specialize more binary operations using BINARY_OP_EXTEND (GH-128956)
This commit is contained in:
parent
9d38143088
commit
1f6a09fb36
21 changed files with 1850 additions and 1224 deletions
|
|
@ -1008,14 +1008,32 @@ dummy_func(
|
|||
res = PyStackRef_FromPyObjectSteal(temp);
|
||||
}
|
||||
|
||||
tier2 op(_GUARD_BINARY_OP_EXTEND_LHS, (descr/4, left, right -- left, right)) {
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->lhs_type != NULL);
|
||||
EXIT_IF(Py_TYPE(left_o) != d->lhs_type);
|
||||
}
|
||||
|
||||
tier2 op(_GUARD_BINARY_OP_EXTEND_RHS, (descr/4, left, right -- left, right)) {
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->rhs_type != NULL);
|
||||
EXIT_IF(Py_TYPE(right_o) != d->rhs_type);
|
||||
}
|
||||
|
||||
op(_GUARD_BINARY_OP_EXTEND, (descr/4, left, right -- left, right)) {
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard);
|
||||
int res = d->guard(left_o, right_o);
|
||||
EXIT_IF(!res);
|
||||
assert(d != NULL);
|
||||
int match = (d->guard != NULL)
|
||||
? d->guard(left_o, right_o)
|
||||
: (Py_TYPE(left_o) == d->lhs_type && Py_TYPE(right_o) == d->rhs_type);
|
||||
EXIT_IF(!match);
|
||||
}
|
||||
|
||||
op(_BINARY_OP_EXTEND, (descr/4, left, right -- res, l, r)) {
|
||||
|
|
@ -1030,11 +1048,14 @@ dummy_func(
|
|||
if (res_o == NULL) {
|
||||
ERROR_NO_POP();
|
||||
}
|
||||
assert(d->result_type == NULL || Py_TYPE(res_o) == d->result_type);
|
||||
assert(!d->result_unique || Py_REFCNT(res_o) == 1 || _Py_IsImmortal(res_o));
|
||||
// The JIT and tier 2 optimizer assume that float results from
|
||||
// binary operations are always uniquely referenced (refcount == 1).
|
||||
// If this assertion fails, update the optimizer to stop marking
|
||||
// float results as unique in optimizer_bytecodes.c.
|
||||
assert(!PyFloat_CheckExact(res_o) || Py_REFCNT(res_o) == 1);
|
||||
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
l = left;
|
||||
r = right;
|
||||
|
|
|
|||
220
Python/executor_cases.c.h
generated
220
Python/executor_cases.c.h
generated
|
|
@ -6395,6 +6395,216 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_LHS_r02: {
|
||||
CHECK_CURRENT_CACHED_VALUES(0);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef left;
|
||||
left = stack_pointer[-2];
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->lhs_type != NULL);
|
||||
if (Py_TYPE(left_o) != d->lhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
SET_CURRENT_CACHED_VALUES(0);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = stack_pointer[-1];
|
||||
_tos_cache0 = left;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
stack_pointer += -2;
|
||||
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_LHS_r12: {
|
||||
CHECK_CURRENT_CACHED_VALUES(1);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef left;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
left = stack_pointer[-1];
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->lhs_type != NULL);
|
||||
if (Py_TYPE(left_o) != d->lhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(1);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = _stack_item_0;
|
||||
_tos_cache0 = left;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
stack_pointer += -1;
|
||||
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_LHS_r22: {
|
||||
CHECK_CURRENT_CACHED_VALUES(2);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef left;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
_PyStackRef _stack_item_1 = _tos_cache1;
|
||||
left = _stack_item_0;
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->lhs_type != NULL);
|
||||
if (Py_TYPE(left_o) != d->lhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache1 = _stack_item_1;
|
||||
_tos_cache0 = left;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = _stack_item_1;
|
||||
_tos_cache0 = left;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_LHS_r33: {
|
||||
CHECK_CURRENT_CACHED_VALUES(3);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef left;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
_PyStackRef _stack_item_1 = _tos_cache1;
|
||||
_PyStackRef _stack_item_2 = _tos_cache2;
|
||||
left = _stack_item_1;
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->lhs_type != NULL);
|
||||
if (Py_TYPE(left_o) != d->lhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache2 = _stack_item_2;
|
||||
_tos_cache1 = left;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(3);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache2 = _stack_item_2;
|
||||
_tos_cache1 = left;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(3);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_RHS_r02: {
|
||||
CHECK_CURRENT_CACHED_VALUES(0);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef right;
|
||||
right = stack_pointer[-1];
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->rhs_type != NULL);
|
||||
if (Py_TYPE(right_o) != d->rhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
SET_CURRENT_CACHED_VALUES(0);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = right;
|
||||
_tos_cache0 = stack_pointer[-2];
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
stack_pointer += -2;
|
||||
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_RHS_r12: {
|
||||
CHECK_CURRENT_CACHED_VALUES(1);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef right;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
right = _stack_item_0;
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->rhs_type != NULL);
|
||||
if (Py_TYPE(right_o) != d->rhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache0 = right;
|
||||
SET_CURRENT_CACHED_VALUES(1);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = right;
|
||||
_tos_cache0 = stack_pointer[-1];
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
stack_pointer += -1;
|
||||
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_RHS_r22: {
|
||||
CHECK_CURRENT_CACHED_VALUES(2);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef right;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
_PyStackRef _stack_item_1 = _tos_cache1;
|
||||
right = _stack_item_1;
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->rhs_type != NULL);
|
||||
if (Py_TYPE(right_o) != d->rhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache1 = right;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = right;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_RHS_r33: {
|
||||
CHECK_CURRENT_CACHED_VALUES(3);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
_PyStackRef right;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
_PyStackRef _stack_item_1 = _tos_cache1;
|
||||
_PyStackRef _stack_item_2 = _tos_cache2;
|
||||
right = _stack_item_2;
|
||||
PyObject *descr = (PyObject *)CURRENT_OPERAND0_64();
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard == NULL && d->rhs_type != NULL);
|
||||
if (Py_TYPE(right_o) != d->rhs_type) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache2 = right;
|
||||
_tos_cache1 = _stack_item_1;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(3);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache2 = right;
|
||||
_tos_cache1 = _stack_item_1;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(3);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_r22: {
|
||||
CHECK_CURRENT_CACHED_VALUES(2);
|
||||
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
|
||||
|
|
@ -6409,15 +6619,17 @@
|
|||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard);
|
||||
assert(d != NULL);
|
||||
stack_pointer[0] = left;
|
||||
stack_pointer[1] = right;
|
||||
stack_pointer += 2;
|
||||
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
int res = d->guard(left_o, right_o);
|
||||
int match = (d->guard != NULL)
|
||||
? d->guard(left_o, right_o)
|
||||
: (Py_TYPE(left_o) == d->lhs_type && Py_TYPE(right_o) == d->rhs_type);
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
if (!res) {
|
||||
if (!match) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache1 = right;
|
||||
_tos_cache0 = left;
|
||||
|
|
@ -6465,6 +6677,8 @@
|
|||
SET_CURRENT_CACHED_VALUES(0);
|
||||
JUMP_TO_ERROR();
|
||||
}
|
||||
assert(d->result_type == NULL || Py_TYPE(res_o) == d->result_type);
|
||||
assert(!d->result_unique || Py_REFCNT(res_o) == 1 || _Py_IsImmortal(res_o));
|
||||
assert(!PyFloat_CheckExact(res_o) || Py_REFCNT(res_o) == 1);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
l = left;
|
||||
|
|
|
|||
10
Python/generated_cases.c.h
generated
10
Python/generated_cases.c.h
generated
|
|
@ -342,11 +342,13 @@
|
|||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr;
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
assert(d && d->guard);
|
||||
assert(d != NULL);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
int res = d->guard(left_o, right_o);
|
||||
int match = (d->guard != NULL)
|
||||
? d->guard(left_o, right_o)
|
||||
: (Py_TYPE(left_o) == d->lhs_type && Py_TYPE(right_o) == d->rhs_type);
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
if (!res) {
|
||||
if (!match) {
|
||||
UPDATE_MISS_STATS(BINARY_OP);
|
||||
assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
|
||||
JUMP_TO_PREDICTED(BINARY_OP);
|
||||
|
|
@ -367,6 +369,8 @@
|
|||
if (res_o == NULL) {
|
||||
JUMP_TO_LABEL(error);
|
||||
}
|
||||
assert(d->result_type == NULL || Py_TYPE(res_o) == d->result_type);
|
||||
assert(!d->result_unique || Py_REFCNT(res_o) == 1 || _Py_IsImmortal(res_o));
|
||||
assert(!PyFloat_CheckExact(res_o) || Py_REFCNT(res_o) == 1);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
l = left;
|
||||
|
|
|
|||
|
|
@ -485,6 +485,46 @@ dummy_func(void) {
|
|||
r = right;
|
||||
}
|
||||
|
||||
op(_GUARD_BINARY_OP_EXTEND_LHS, (descr/4, left, right -- left, right)) {
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
assert(d != NULL && d->guard == NULL && d->lhs_type != NULL);
|
||||
if (sym_matches_type(left, d->lhs_type)) {
|
||||
ADD_OP(_NOP, 0, 0);
|
||||
}
|
||||
sym_set_type(left, d->lhs_type);
|
||||
}
|
||||
|
||||
op(_GUARD_BINARY_OP_EXTEND_RHS, (descr/4, left, right -- left, right)) {
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
assert(d != NULL && d->guard == NULL && d->rhs_type != NULL);
|
||||
if (sym_matches_type(right, d->rhs_type)) {
|
||||
ADD_OP(_NOP, 0, 0);
|
||||
}
|
||||
sym_set_type(right, d->rhs_type);
|
||||
}
|
||||
|
||||
op(_GUARD_BINARY_OP_EXTEND, (descr/4, left, right -- left, right)) {
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
if (d != NULL && d->guard == NULL) {
|
||||
/* guard == NULL means the check is purely a type test against
|
||||
lhs_type/rhs_type, so eliminate it when types are already known. */
|
||||
assert(d->lhs_type != NULL && d->rhs_type != NULL);
|
||||
bool lhs_known = sym_matches_type(left, d->lhs_type);
|
||||
bool rhs_known = sym_matches_type(right, d->rhs_type);
|
||||
if (lhs_known && rhs_known) {
|
||||
ADD_OP(_NOP, 0, 0);
|
||||
}
|
||||
else if (lhs_known) {
|
||||
ADD_OP(_GUARD_BINARY_OP_EXTEND_RHS, 0, (uintptr_t)d);
|
||||
sym_set_type(right, d->rhs_type);
|
||||
}
|
||||
else if (rhs_known) {
|
||||
ADD_OP(_GUARD_BINARY_OP_EXTEND_LHS, 0, (uintptr_t)d);
|
||||
sym_set_type(left, d->lhs_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
op(_BINARY_OP_EXTEND, (descr/4, left, right -- res, l, r)) {
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
if (d != NULL && d->result_type != NULL) {
|
||||
|
|
|
|||
48
Python/optimizer_cases.c.h
generated
48
Python/optimizer_cases.c.h
generated
|
|
@ -1210,7 +1210,55 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_LHS: {
|
||||
JitOptRef left;
|
||||
left = stack_pointer[-2];
|
||||
PyObject *descr = (PyObject *)this_instr->operand0;
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
assert(d != NULL && d->guard == NULL && d->lhs_type != NULL);
|
||||
if (sym_matches_type(left, d->lhs_type)) {
|
||||
ADD_OP(_NOP, 0, 0);
|
||||
}
|
||||
sym_set_type(left, d->lhs_type);
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND_RHS: {
|
||||
JitOptRef right;
|
||||
right = stack_pointer[-1];
|
||||
PyObject *descr = (PyObject *)this_instr->operand0;
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
assert(d != NULL && d->guard == NULL && d->rhs_type != NULL);
|
||||
if (sym_matches_type(right, d->rhs_type)) {
|
||||
ADD_OP(_NOP, 0, 0);
|
||||
}
|
||||
sym_set_type(right, d->rhs_type);
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BINARY_OP_EXTEND: {
|
||||
JitOptRef right;
|
||||
JitOptRef left;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
PyObject *descr = (PyObject *)this_instr->operand0;
|
||||
_PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr *)descr;
|
||||
if (d != NULL && d->guard == NULL) {
|
||||
assert(d->lhs_type != NULL && d->rhs_type != NULL);
|
||||
bool lhs_known = sym_matches_type(left, d->lhs_type);
|
||||
bool rhs_known = sym_matches_type(right, d->rhs_type);
|
||||
if (lhs_known && rhs_known) {
|
||||
ADD_OP(_NOP, 0, 0);
|
||||
}
|
||||
else if (lhs_known) {
|
||||
ADD_OP(_GUARD_BINARY_OP_EXTEND_RHS, 0, (uintptr_t)d);
|
||||
sym_set_type(right, d->rhs_type);
|
||||
}
|
||||
else if (rhs_known) {
|
||||
ADD_OP(_GUARD_BINARY_OP_EXTEND_LHS, 0, (uintptr_t)d);
|
||||
sym_set_type(left, d->lhs_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "opcode.h"
|
||||
|
||||
#include "pycore_bytesobject.h" // _PyBytes_Concat
|
||||
#include "pycore_code.h"
|
||||
#include "pycore_critical_section.h"
|
||||
#include "pycore_descrobject.h" // _PyMethodWrapper_Type
|
||||
|
|
@ -9,7 +10,8 @@
|
|||
#include "pycore_function.h" // _PyFunction_GetVersionForCurrentState()
|
||||
#include "pycore_interpframe.h" // FRAME_SPECIALS_SIZE
|
||||
#include "pycore_lazyimportobject.h" // PyLazyImport_CheckExact
|
||||
#include "pycore_list.h" // _PyListIterObject
|
||||
#include "pycore_list.h" // _PyListIterObject, _PyList_Concat
|
||||
#include "pycore_tuple.h" // _PyTuple_Concat
|
||||
#include "pycore_long.h" // _PyLong_IsNonNegativeCompact()
|
||||
#include "pycore_moduleobject.h"
|
||||
#include "pycore_object.h"
|
||||
|
|
@ -2120,6 +2122,56 @@ is_compactlong(PyObject *v)
|
|||
_PyLong_IsCompact((PyLongObject *)v);
|
||||
}
|
||||
|
||||
/* sequence * int helpers: bypass PyNumber_Multiply dispatch overhead
|
||||
by calling sq_repeat directly with PyLong_AsSsize_t. */
|
||||
|
||||
static inline PyObject *
|
||||
seq_int_multiply(PyObject *seq, PyObject *n,
|
||||
ssizeargfunc repeat)
|
||||
{
|
||||
Py_ssize_t count = PyLong_AsSsize_t(n);
|
||||
if (count == -1 && PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
return repeat(seq, count);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
str_int_multiply(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
return seq_int_multiply(lhs, rhs, PyUnicode_Type.tp_as_sequence->sq_repeat);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
int_str_multiply(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
return seq_int_multiply(rhs, lhs, PyUnicode_Type.tp_as_sequence->sq_repeat);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bytes_int_multiply(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
return seq_int_multiply(lhs, rhs, PyBytes_Type.tp_as_sequence->sq_repeat);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
int_bytes_multiply(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
return seq_int_multiply(rhs, lhs, PyBytes_Type.tp_as_sequence->sq_repeat);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
tuple_int_multiply(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
return seq_int_multiply(lhs, rhs, PyTuple_Type.tp_as_sequence->sq_repeat);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
int_tuple_multiply(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
return seq_int_multiply(rhs, lhs, PyTuple_Type.tp_as_sequence->sq_repeat);
|
||||
}
|
||||
|
||||
static int
|
||||
compactlongs_guard(PyObject *lhs, PyObject *rhs)
|
||||
{
|
||||
|
|
@ -2210,25 +2262,63 @@ LONG_FLOAT_ACTION(compactlong_float_true_div, /)
|
|||
#undef LONG_FLOAT_ACTION
|
||||
|
||||
static _PyBinaryOpSpecializationDescr binaryop_extend_descrs[] = {
|
||||
/* long-long arithmetic */
|
||||
{NB_OR, compactlongs_guard, compactlongs_or, &PyLong_Type, 1},
|
||||
{NB_AND, compactlongs_guard, compactlongs_and, &PyLong_Type, 1},
|
||||
{NB_XOR, compactlongs_guard, compactlongs_xor, &PyLong_Type, 1},
|
||||
{NB_INPLACE_OR, compactlongs_guard, compactlongs_or, &PyLong_Type, 1},
|
||||
{NB_INPLACE_AND, compactlongs_guard, compactlongs_and, &PyLong_Type, 1},
|
||||
{NB_INPLACE_XOR, compactlongs_guard, compactlongs_xor, &PyLong_Type, 1},
|
||||
/* long-long arithmetic: guards also check _PyLong_IsCompact, so
|
||||
type alone is not sufficient to eliminate the guard. */
|
||||
{NB_OR, compactlongs_guard, compactlongs_or, &PyLong_Type, 1, NULL, NULL},
|
||||
{NB_AND, compactlongs_guard, compactlongs_and, &PyLong_Type, 1, NULL, NULL},
|
||||
{NB_XOR, compactlongs_guard, compactlongs_xor, &PyLong_Type, 1, NULL, NULL},
|
||||
{NB_INPLACE_OR, compactlongs_guard, compactlongs_or, &PyLong_Type, 1, NULL, NULL},
|
||||
{NB_INPLACE_AND, compactlongs_guard, compactlongs_and, &PyLong_Type, 1, NULL, NULL},
|
||||
{NB_INPLACE_XOR, compactlongs_guard, compactlongs_xor, &PyLong_Type, 1, NULL, NULL},
|
||||
|
||||
/* float-long arithemetic */
|
||||
{NB_ADD, float_compactlong_guard, float_compactlong_add, &PyFloat_Type, 1},
|
||||
{NB_SUBTRACT, float_compactlong_guard, float_compactlong_subtract, &PyFloat_Type, 1},
|
||||
{NB_TRUE_DIVIDE, nonzero_float_compactlong_guard, float_compactlong_true_div, &PyFloat_Type, 1},
|
||||
{NB_MULTIPLY, float_compactlong_guard, float_compactlong_multiply, &PyFloat_Type, 1},
|
||||
/* float-long arithmetic: guards also check NaN and compactness. */
|
||||
{NB_ADD, float_compactlong_guard, float_compactlong_add, &PyFloat_Type, 1, NULL, NULL},
|
||||
{NB_SUBTRACT, float_compactlong_guard, float_compactlong_subtract, &PyFloat_Type, 1, NULL, NULL},
|
||||
{NB_TRUE_DIVIDE, nonzero_float_compactlong_guard, float_compactlong_true_div, &PyFloat_Type, 1, NULL, NULL},
|
||||
{NB_MULTIPLY, float_compactlong_guard, float_compactlong_multiply, &PyFloat_Type, 1, NULL, NULL},
|
||||
|
||||
/* float-float arithmetic */
|
||||
{NB_ADD, compactlong_float_guard, compactlong_float_add, &PyFloat_Type, 1},
|
||||
{NB_SUBTRACT, compactlong_float_guard, compactlong_float_subtract, &PyFloat_Type, 1},
|
||||
{NB_TRUE_DIVIDE, nonzero_compactlong_float_guard, compactlong_float_true_div, &PyFloat_Type, 1},
|
||||
{NB_MULTIPLY, compactlong_float_guard, compactlong_float_multiply, &PyFloat_Type, 1},
|
||||
/* long-float arithmetic: guards also check NaN and compactness. */
|
||||
{NB_ADD, compactlong_float_guard, compactlong_float_add, &PyFloat_Type, 1, NULL, NULL},
|
||||
{NB_SUBTRACT, compactlong_float_guard, compactlong_float_subtract, &PyFloat_Type, 1, NULL, NULL},
|
||||
{NB_TRUE_DIVIDE, nonzero_compactlong_float_guard, compactlong_float_true_div, &PyFloat_Type, 1, NULL, NULL},
|
||||
{NB_MULTIPLY, compactlong_float_guard, compactlong_float_multiply, &PyFloat_Type, 1, NULL, NULL},
|
||||
|
||||
/* list-list concatenation: _PyList_Concat always allocates a new list */
|
||||
{NB_ADD, NULL, _PyList_Concat, &PyList_Type, 1, &PyList_Type, &PyList_Type},
|
||||
/* tuple-tuple concatenation: _PyTuple_Concat has a zero-length shortcut
|
||||
that can return one of the operands, so the result is not guaranteed
|
||||
to be a freshly allocated object. */
|
||||
{NB_ADD, NULL, _PyTuple_Concat, &PyTuple_Type, 0, &PyTuple_Type, &PyTuple_Type},
|
||||
|
||||
/* str * int / int * str: call unicode_repeat directly.
|
||||
unicode_repeat returns the original when n == 1. */
|
||||
{NB_MULTIPLY, NULL, str_int_multiply, &PyUnicode_Type, 0, &PyUnicode_Type, &PyLong_Type},
|
||||
{NB_MULTIPLY, NULL, int_str_multiply, &PyUnicode_Type, 0, &PyLong_Type, &PyUnicode_Type},
|
||||
{NB_INPLACE_MULTIPLY, NULL, str_int_multiply, &PyUnicode_Type, 0, &PyUnicode_Type, &PyLong_Type},
|
||||
{NB_INPLACE_MULTIPLY, NULL, int_str_multiply, &PyUnicode_Type, 0, &PyLong_Type, &PyUnicode_Type},
|
||||
|
||||
/* bytes + bytes: bytes_concat may return an operand when one side
|
||||
is empty, so result is not always unique. */
|
||||
{NB_ADD, NULL, _PyBytes_Concat, &PyBytes_Type, 0, &PyBytes_Type, &PyBytes_Type},
|
||||
{NB_INPLACE_ADD, NULL, _PyBytes_Concat, &PyBytes_Type, 0, &PyBytes_Type, &PyBytes_Type},
|
||||
|
||||
/* bytes * int / int * bytes: call bytes_repeat directly.
|
||||
bytes_repeat returns the original when n == 1. */
|
||||
{NB_MULTIPLY, NULL, bytes_int_multiply, &PyBytes_Type, 0, &PyBytes_Type, &PyLong_Type},
|
||||
{NB_MULTIPLY, NULL, int_bytes_multiply, &PyBytes_Type, 0, &PyLong_Type, &PyBytes_Type},
|
||||
{NB_INPLACE_MULTIPLY, NULL, bytes_int_multiply, &PyBytes_Type, 0, &PyBytes_Type, &PyLong_Type},
|
||||
{NB_INPLACE_MULTIPLY, NULL, int_bytes_multiply, &PyBytes_Type, 0, &PyLong_Type, &PyBytes_Type},
|
||||
|
||||
/* tuple * int / int * tuple: call tuple_repeat directly.
|
||||
tuple_repeat returns the original when n == 1. */
|
||||
{NB_MULTIPLY, NULL, tuple_int_multiply, &PyTuple_Type, 0, &PyTuple_Type, &PyLong_Type},
|
||||
{NB_MULTIPLY, NULL, int_tuple_multiply, &PyTuple_Type, 0, &PyLong_Type, &PyTuple_Type},
|
||||
{NB_INPLACE_MULTIPLY, NULL, tuple_int_multiply, &PyTuple_Type, 0, &PyTuple_Type, &PyLong_Type},
|
||||
{NB_INPLACE_MULTIPLY, NULL, int_tuple_multiply, &PyTuple_Type, 0, &PyLong_Type, &PyTuple_Type},
|
||||
|
||||
/* dict | dict */
|
||||
{NB_OR, NULL, _PyDict_Or, &PyDict_Type, 1, &PyDict_Type, &PyDict_Type},
|
||||
{NB_INPLACE_OR, NULL, _PyDict_IOr, &PyDict_Type, 0, &PyDict_Type, &PyDict_Type},
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -2238,7 +2328,13 @@ binary_op_extended_specialization(PyObject *lhs, PyObject *rhs, int oparg,
|
|||
size_t n = sizeof(binaryop_extend_descrs)/sizeof(_PyBinaryOpSpecializationDescr);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
_PyBinaryOpSpecializationDescr *d = &binaryop_extend_descrs[i];
|
||||
if (d->oparg == oparg && d->guard(lhs, rhs)) {
|
||||
if (d->oparg != oparg) {
|
||||
continue;
|
||||
}
|
||||
int match = (d->guard != NULL)
|
||||
? d->guard(lhs, rhs)
|
||||
: (Py_TYPE(lhs) == d->lhs_type && Py_TYPE(rhs) == d->rhs_type);
|
||||
if (match) {
|
||||
*descr = d;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue