Skip to content

Commit 4f7f72c

Browse files
authored
GH-130415: Improve the JIT's unneeded uop removal pass (GH-132333)
1 parent 9be3645 commit 4f7f72c

File tree

5 files changed

+46
-18
lines changed

5 files changed

+46
-18
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ class Bar:
12831283
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call)
12841284
load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
12851285
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1)
1286-
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1)
1286+
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 2)
12871287

12881288
def test_guard_type_version_removed_escaping(self):
12891289

@@ -1306,7 +1306,7 @@ class Foo:
13061306
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call)
13071307
load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
13081308
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1)
1309-
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1)
1309+
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 2)
13101310

13111311
def test_guard_type_version_executor_invalidated(self):
13121312
"""
@@ -1601,7 +1601,7 @@ def testfunc(n):
16011601
self.assertIsNotNone(ex)
16021602
uops = get_opnames(ex)
16031603
self.assertNotIn("_COMPARE_OP_INT", uops)
1604-
self.assertIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
1604+
self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
16051605

16061606
def test_to_bool_bool_contains_op_set(self):
16071607
"""
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Improve the JIT's ability to remove unused constant and local variable
2+
loads, and fix an issue where deallocating unused values could cause JIT
3+
code to crash or behave incorrectly.

Python/optimizer_analysis.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -555,28 +555,47 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
555555
}
556556
break;
557557
case _POP_TOP:
558+
case _POP_TOP_LOAD_CONST_INLINE:
559+
case _POP_TOP_LOAD_CONST_INLINE_BORROW:
560+
case _POP_TWO_LOAD_CONST_INLINE_BORROW:
561+
optimize_pop_top_again:
558562
{
559563
_PyUOpInstruction *last = &buffer[pc-1];
560564
while (last->opcode == _NOP) {
561565
last--;
562566
}
563-
if (last->opcode == _LOAD_CONST_INLINE ||
564-
last->opcode == _LOAD_CONST_INLINE_BORROW ||
565-
last->opcode == _LOAD_FAST ||
566-
last->opcode == _LOAD_FAST_BORROW ||
567-
last->opcode == _COPY
568-
) {
569-
last->opcode = _NOP;
570-
buffer[pc].opcode = _NOP;
571-
}
572-
if (last->opcode == _REPLACE_WITH_TRUE) {
573-
last->opcode = _NOP;
567+
switch (last->opcode) {
568+
case _POP_TWO_LOAD_CONST_INLINE_BORROW:
569+
last->opcode = _POP_TOP;
570+
break;
571+
case _POP_TOP_LOAD_CONST_INLINE:
572+
case _POP_TOP_LOAD_CONST_INLINE_BORROW:
573+
last->opcode = _NOP;
574+
goto optimize_pop_top_again;
575+
case _COPY:
576+
case _LOAD_CONST_INLINE:
577+
case _LOAD_CONST_INLINE_BORROW:
578+
case _LOAD_FAST:
579+
case _LOAD_FAST_BORROW:
580+
case _LOAD_SMALL_INT:
581+
last->opcode = _NOP;
582+
if (opcode == _POP_TOP) {
583+
opcode = buffer[pc].opcode = _NOP;
584+
}
585+
else if (opcode == _POP_TOP_LOAD_CONST_INLINE) {
586+
opcode = buffer[pc].opcode = _LOAD_CONST_INLINE;
587+
}
588+
else if (opcode == _POP_TOP_LOAD_CONST_INLINE_BORROW) {
589+
opcode = buffer[pc].opcode = _LOAD_CONST_INLINE_BORROW;
590+
}
591+
else {
592+
assert(opcode == _POP_TWO_LOAD_CONST_INLINE_BORROW);
593+
opcode = buffer[pc].opcode = _POP_TOP_LOAD_CONST_INLINE_BORROW;
594+
goto optimize_pop_top_again;
595+
}
574596
}
575-
break;
597+
_Py_FALLTHROUGH;
576598
}
577-
case _JUMP_TO_TOP:
578-
case _EXIT_TRACE:
579-
return pc + 1;
580599
default:
581600
{
582601
/* _PUSH_FRAME doesn't escape or error, but it
@@ -591,7 +610,11 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
591610
buffer[last_set_ip].opcode = _SET_IP;
592611
last_set_ip = -1;
593612
}
613+
break;
594614
}
615+
case _JUMP_TO_TOP:
616+
case _EXIT_TRACE:
617+
return pc + 1;
595618
}
596619
}
597620
Py_UNREACHABLE();

Python/optimizer_bytecodes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ dummy_func(void) {
912912
}
913913

914914
op(_REPLACE_WITH_TRUE, (value -- res)) {
915+
REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)Py_True);
915916
res = sym_new_const(ctx, Py_True);
916917
}
917918

Python/optimizer_cases.c.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)