diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-15-26-26.gh-issue-130415.BFmc1o.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-15-26-26.gh-issue-130415.BFmc1o.rst new file mode 100644 index 00000000000000..b0ad2640150ffb --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-19-15-26-26.gh-issue-130415.BFmc1o.rst @@ -0,0 +1 @@ +Optimize constant comparison for _COMPARE_OP_FLOAT, _COMPARE_OP_STR, _BINARY_OP in JIT builds diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 7c160cdcb0c149..26b8dc611b7a4e 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -207,6 +207,20 @@ dummy_func(void) { else { res = sym_new_type(ctx, &PyFloat_Type); } + + if (sym_is_const(ctx, lhs) && sym_is_const(ctx, rhs)) { + PyObject *temp = PyObject_RichCompare(sym_get_const(ctx, lhs), + sym_get_const(ctx, rhs), + oparg >> 5); + if (temp == NULL) { + goto error; + } + assert(PyBool_Check(temp)); + assert(_Py_IsImmortal(temp)); + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); + res = sym_new_const(ctx, temp); + Py_DECREF(temp); + } } op(_BINARY_OP_ADD_INT, (left, right -- res)) { @@ -486,11 +500,43 @@ dummy_func(void) { } op(_COMPARE_OP_FLOAT, (left, right -- res)) { - res = sym_new_type(ctx, &PyBool_Type); + if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { + assert(PyLong_CheckExact(sym_get_const(ctx, left))); + assert(PyLong_CheckExact(sym_get_const(ctx, right))); + PyObject *tmp = PyObject_RichCompare(sym_get_const(ctx, left), + sym_get_const(ctx, right), + oparg >> 5); + if (tmp == NULL) { + goto error; + } + assert(PyBool_Check(tmp)); + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)tmp); + res = sym_new_const(ctx, tmp); + Py_DECREF(tmp); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } } op(_COMPARE_OP_STR, (left, right -- res)) { - res = sym_new_type(ctx, &PyBool_Type); + if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { + assert(PyLong_CheckExact(sym_get_const(ctx, left))); + assert(PyLong_CheckExact(sym_get_const(ctx, right))); + PyObject *tmp = PyObject_RichCompare(sym_get_const(ctx, left), + sym_get_const(ctx, right), + oparg >> 5); + if (tmp == NULL) { + goto error; + } + assert(PyBool_Check(tmp)); + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)tmp); + res = sym_new_const(ctx, tmp); + Py_DECREF(tmp); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } } op(_IS_OP, (left, right -- b)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index deb912662e4b0b..28f70b96af7079 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1334,11 +1334,33 @@ } case _COMPARE_OP_FLOAT: { + JitOptSymbol *right; + JitOptSymbol *left; JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { + assert(PyLong_CheckExact(sym_get_const(ctx, left))); + assert(PyLong_CheckExact(sym_get_const(ctx, right))); + PyObject *tmp = PyObject_RichCompare(sym_get_const(ctx, left), + sym_get_const(ctx, right), + oparg >> 5); + if (tmp == NULL) { + goto error; + } + assert(PyBool_Check(tmp)); + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)tmp); + res = sym_new_const(ctx, tmp); + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(tmp); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer += -1; + } + stack_pointer[-1] = res; break; } @@ -1375,11 +1397,33 @@ } case _COMPARE_OP_STR: { + JitOptSymbol *right; + JitOptSymbol *left; JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { + assert(PyLong_CheckExact(sym_get_const(ctx, left))); + assert(PyLong_CheckExact(sym_get_const(ctx, right))); + PyObject *tmp = PyObject_RichCompare(sym_get_const(ctx, left), + sym_get_const(ctx, right), + oparg >> 5); + if (tmp == NULL) { + goto error; + } + assert(PyBool_Check(tmp)); + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)tmp); + res = sym_new_const(ctx, tmp); + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(tmp); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer += -1; + } + stack_pointer[-1] = res; break; } @@ -2344,6 +2388,23 @@ else { res = sym_new_type(ctx, &PyFloat_Type); } + if (sym_is_const(ctx, lhs) && sym_is_const(ctx, rhs)) { + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + PyObject *temp = PyObject_RichCompare(sym_get_const(ctx, lhs), + sym_get_const(ctx, rhs), + oparg >> 5); + if (temp == NULL) { + goto error; + } + assert(PyBool_Check(temp)); + assert(_Py_IsImmortal(temp)); + REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); + res = sym_new_const(ctx, temp); + Py_DECREF(temp); + stack_pointer += 1; + } stack_pointer[-2] = res; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS());