https://github.com/python/cpython/commit/4f7f72ce34f7825e50346ed0c878fc36ef9421ca
commit: 4f7f72ce34f7825e50346ed0c878fc36ef9421ca
branch: main
author: Brandt Bucher <[email protected]>
committer: brandtbucher <[email protected]>
date: 2025-04-21T09:58:55-07:00
summary:
GH-130415: Improve the JIT's unneeded uop removal pass (GH-132333)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-14-05-54.gh-issue-130415.llQtUq.rst
M Lib/test/test_capi/test_opt.py
M Python/optimizer_analysis.c
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index 34b7c5982245c7..7fb505f27dfb9e 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -1283,7 +1283,7 @@ class Bar:
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
0, call)
load_attr_bottom =
opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"),
1)
-
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1)
+
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 2)
def test_guard_type_version_removed_escaping(self):
@@ -1306,7 +1306,7 @@ class Foo:
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
0, call)
load_attr_bottom =
opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"),
1)
-
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1)
+
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 2)
def test_guard_type_version_executor_invalidated(self):
"""
@@ -1601,7 +1601,7 @@ def testfunc(n):
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertNotIn("_COMPARE_OP_INT", uops)
- self.assertIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
+ self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
def test_to_bool_bool_contains_op_set(self):
"""
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-14-05-54.gh-issue-130415.llQtUq.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-14-05-54.gh-issue-130415.llQtUq.rst
new file mode 100644
index 00000000000000..03523de79b69ab
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-14-05-54.gh-issue-130415.llQtUq.rst
@@ -0,0 +1,3 @@
+Improve the JIT's ability to remove unused constant and local variable
+loads, and fix an issue where deallocating unused values could cause JIT
+code to crash or behave incorrectly.
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
index ab28fae94a96a9..387ebc813abd66 100644
--- a/Python/optimizer_analysis.c
+++ b/Python/optimizer_analysis.c
@@ -555,28 +555,47 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int
buffer_size)
}
break;
case _POP_TOP:
+ case _POP_TOP_LOAD_CONST_INLINE:
+ case _POP_TOP_LOAD_CONST_INLINE_BORROW:
+ case _POP_TWO_LOAD_CONST_INLINE_BORROW:
+ optimize_pop_top_again:
{
_PyUOpInstruction *last = &buffer[pc-1];
while (last->opcode == _NOP) {
last--;
}
- if (last->opcode == _LOAD_CONST_INLINE ||
- last->opcode == _LOAD_CONST_INLINE_BORROW ||
- last->opcode == _LOAD_FAST ||
- last->opcode == _LOAD_FAST_BORROW ||
- last->opcode == _COPY
- ) {
- last->opcode = _NOP;
- buffer[pc].opcode = _NOP;
- }
- if (last->opcode == _REPLACE_WITH_TRUE) {
- last->opcode = _NOP;
+ switch (last->opcode) {
+ case _POP_TWO_LOAD_CONST_INLINE_BORROW:
+ last->opcode = _POP_TOP;
+ break;
+ case _POP_TOP_LOAD_CONST_INLINE:
+ case _POP_TOP_LOAD_CONST_INLINE_BORROW:
+ last->opcode = _NOP;
+ goto optimize_pop_top_again;
+ case _COPY:
+ case _LOAD_CONST_INLINE:
+ case _LOAD_CONST_INLINE_BORROW:
+ case _LOAD_FAST:
+ case _LOAD_FAST_BORROW:
+ case _LOAD_SMALL_INT:
+ last->opcode = _NOP;
+ if (opcode == _POP_TOP) {
+ opcode = buffer[pc].opcode = _NOP;
+ }
+ else if (opcode == _POP_TOP_LOAD_CONST_INLINE) {
+ opcode = buffer[pc].opcode = _LOAD_CONST_INLINE;
+ }
+ else if (opcode == _POP_TOP_LOAD_CONST_INLINE_BORROW) {
+ opcode = buffer[pc].opcode =
_LOAD_CONST_INLINE_BORROW;
+ }
+ else {
+ assert(opcode ==
_POP_TWO_LOAD_CONST_INLINE_BORROW);
+ opcode = buffer[pc].opcode =
_POP_TOP_LOAD_CONST_INLINE_BORROW;
+ goto optimize_pop_top_again;
+ }
}
- break;
+ _Py_FALLTHROUGH;
}
- case _JUMP_TO_TOP:
- case _EXIT_TRACE:
- return pc + 1;
default:
{
/* _PUSH_FRAME doesn't escape or error, but it
@@ -591,7 +610,11 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int
buffer_size)
buffer[last_set_ip].opcode = _SET_IP;
last_set_ip = -1;
}
+ break;
}
+ case _JUMP_TO_TOP:
+ case _EXIT_TRACE:
+ return pc + 1;
}
}
Py_UNREACHABLE();
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index c5d8b536bc6341..6f7f9b03d3bf06 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -912,6 +912,7 @@ dummy_func(void) {
}
op(_REPLACE_WITH_TRUE, (value -- res)) {
+ REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0,
(uintptr_t)Py_True);
res = sym_new_const(ctx, Py_True);
}
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 828f0943a8db86..983af081e2f8cd 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -274,6 +274,7 @@
case _REPLACE_WITH_TRUE: {
JitOptSymbol *res;
+ REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0,
(uintptr_t)Py_True);
res = sym_new_const(ctx, Py_True);
stack_pointer[-1] = res;
break;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]