Skip to content

Commit b92ee14

Browse files
GH-130415: Optimize constant comparison in JIT builds (GH-131489)
1 parent 0de5e0c commit b92ee14

File tree

8 files changed

+142
-35
lines changed

8 files changed

+142
-35
lines changed

Include/internal/pycore_uop_ids.h

+30-29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_capi/test_opt.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ def f(n):
15311531
# But all of the appends we care about are still there:
15321532
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
15331533

1534-
def test_narrow_type_to_constant_str_empty(self):
1534+
def test_narrow_type_to_constant_str_empty(self):
15351535
def f(n):
15361536
trace = []
15371537
for i in range(n):
@@ -1564,6 +1564,23 @@ def f(n):
15641564
# But all of the appends we care about are still there:
15651565
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
15661566

1567+
def test_compare_pop_two_load_const_inline_borrow(self):
1568+
def testfunc(n):
1569+
x = 0
1570+
for _ in range(n):
1571+
a = 10
1572+
b = 10
1573+
if a == b:
1574+
x += 1
1575+
return x
1576+
1577+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
1578+
self.assertEqual(res, TIER2_THRESHOLD)
1579+
self.assertIsNotNone(ex)
1580+
uops = get_opnames(ex)
1581+
self.assertNotIn("_COMPARE_OP_INT", uops)
1582+
self.assertIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
1583+
15671584
def global_identity(x):
15681585
return x
15691586

Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Optimize comparison of two constants in JIT builds

Python/bytecodes.c

+6
Original file line numberDiff line numberDiff line change
@@ -5133,6 +5133,12 @@ dummy_func(
51335133
value = PyStackRef_FromPyObjectImmortal(ptr);
51345134
}
51355135

5136+
tier2 pure op(_POP_TWO_LOAD_CONST_INLINE_BORROW, (ptr/4, pop1, pop2 -- value)) {
5137+
PyStackRef_CLOSE(pop2);
5138+
PyStackRef_CLOSE(pop1);
5139+
value = PyStackRef_FromPyObjectImmortal(ptr);
5140+
}
5141+
51365142
tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) {
51375143
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
51385144
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);

Python/executor_cases.c.h

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_bytecodes.c

+19-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,25 @@ dummy_func(void) {
446446
}
447447

448448
op(_COMPARE_OP_INT, (left, right -- res)) {
449-
res = sym_new_type(ctx, &PyBool_Type);
449+
if (sym_is_const(ctx, left) && sym_is_const(ctx, right))
450+
{
451+
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
452+
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
453+
PyObject *tmp = PyObject_RichCompare(sym_get_const(ctx, left),
454+
sym_get_const(ctx, right),
455+
oparg >> 5);
456+
if (tmp == NULL) {
457+
goto error;
458+
}
459+
assert(PyBool_Check(tmp));
460+
assert(_Py_IsImmortal(tmp));
461+
REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)tmp);
462+
res = sym_new_const(ctx, tmp);
463+
Py_DECREF(tmp);
464+
}
465+
else {
466+
res = sym_new_type(ctx, &PyBool_Type);
467+
}
450468
}
451469

452470
op(_COMPARE_OP_FLOAT, (left, right -- res)) {

Python/optimizer_cases.c.h

+40-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)