gh-115999: Add free-threaded specialization for COMPARE_OP (#126410)

Add free-threaded specialization for COMPARE_OP, and tests for COMPARE_OP specialization in general.

Co-authored-by: Donghee Na <donghee.na92@gmail.com>
This commit is contained in:
T. Wouters 2025-01-07 06:41:01 -08:00 committed by GitHub
parent a734c1e304
commit 8f93dd8a8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 42 additions and 12 deletions

View file

@ -1598,6 +1598,39 @@ class TestSpecializer(TestBase):
self.assert_specialized(binary_subscr_getitems, "BINARY_SUBSCR_GETITEM") self.assert_specialized(binary_subscr_getitems, "BINARY_SUBSCR_GETITEM")
self.assert_no_opcode(binary_subscr_getitems, "BINARY_SUBSCR") self.assert_no_opcode(binary_subscr_getitems, "BINARY_SUBSCR")
@cpython_only
@requires_specialization_ft
def test_compare_op(self):
def compare_op_int():
for _ in range(100):
a, b = 1, 2
c = a == b
self.assertFalse(c)
compare_op_int()
self.assert_specialized(compare_op_int, "COMPARE_OP_INT")
self.assert_no_opcode(compare_op_int, "COMPARE_OP")
def compare_op_float():
for _ in range(100):
a, b = 1.0, 2.0
c = a == b
self.assertFalse(c)
compare_op_float()
self.assert_specialized(compare_op_float, "COMPARE_OP_FLOAT")
self.assert_no_opcode(compare_op_float, "COMPARE_OP")
def compare_op_str():
for _ in range(100):
a, b = "spam", "ham"
c = a == b
self.assertFalse(c)
compare_op_str()
self.assert_specialized(compare_op_str, "COMPARE_OP_STR")
self.assert_no_opcode(compare_op_str, "COMPARE_OP")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -2464,7 +2464,7 @@ dummy_func(
}; };
specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) { specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION_FT
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
next_instr = this_instr; next_instr = this_instr;
_Py_Specialize_CompareOp(left, right, next_instr, oparg); _Py_Specialize_CompareOp(left, right, next_instr, oparg);

View file

@ -3229,7 +3229,7 @@
left = stack_pointer[-2]; left = stack_pointer[-2];
uint16_t counter = read_u16(&this_instr[1].cache); uint16_t counter = read_u16(&this_instr[1].cache);
(void)counter; (void)counter;
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION_FT
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
next_instr = this_instr; next_instr = this_instr;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);

View file

@ -2480,23 +2480,23 @@ _Py_Specialize_CompareOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *i
{ {
PyObject *lhs = PyStackRef_AsPyObjectBorrow(lhs_st); PyObject *lhs = PyStackRef_AsPyObjectBorrow(lhs_st);
PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st);
uint8_t specialized_op;
assert(ENABLE_SPECIALIZATION); assert(ENABLE_SPECIALIZATION_FT);
assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP);
// All of these specializations compute boolean values, so they're all valid // All of these specializations compute boolean values, so they're all valid
// regardless of the fifth-lowest oparg bit. // regardless of the fifth-lowest oparg bit.
_PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1);
if (Py_TYPE(lhs) != Py_TYPE(rhs)) { if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
goto failure; goto failure;
} }
if (PyFloat_CheckExact(lhs)) { if (PyFloat_CheckExact(lhs)) {
instr->op.code = COMPARE_OP_FLOAT; specialized_op = COMPARE_OP_FLOAT;
goto success; goto success;
} }
if (PyLong_CheckExact(lhs)) { if (PyLong_CheckExact(lhs)) {
if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) {
instr->op.code = COMPARE_OP_INT; specialized_op = COMPARE_OP_INT;
goto success; goto success;
} }
else { else {
@ -2511,19 +2511,16 @@ _Py_Specialize_CompareOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *i
goto failure; goto failure;
} }
else { else {
instr->op.code = COMPARE_OP_STR; specialized_op = COMPARE_OP_STR;
goto success; goto success;
} }
} }
SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
failure: failure:
STAT_INC(COMPARE_OP, failure); unspecialize(instr);
instr->op.code = COMPARE_OP;
cache->counter = adaptive_counter_backoff(cache->counter);
return; return;
success: success:
STAT_INC(COMPARE_OP, success); specialize(instr, specialized_op);
cache->counter = adaptive_counter_cooldown();
} }
#ifdef Py_STATS #ifdef Py_STATS