Skip to content

Commit 2bcbf29

Browse files
ljfpCopilot
andcommitted
pythongh-133672: Allow LOAD_FAST to be optimized to LOAD_FAST_BORROW
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 85d3bcd commit 2bcbf29

3 files changed

Lines changed: 491 additions & 11 deletions

File tree

Lib/test/test_peepholer.py

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,7 +2598,19 @@ def test_for_iter(self):
25982598
("LOAD_CONST", 0, 7),
25992599
("RETURN_VALUE", None, 8),
26002600
]
2601-
self.cfg_optimization_test(insts, insts, consts=[None])
2601+
expected = [
2602+
("LOAD_FAST_BORROW", 0, 1),
2603+
top := self.Label(),
2604+
("FOR_ITER", end := self.Label(), 2),
2605+
("STORE_FAST", 2, 3),
2606+
("JUMP", top, 4),
2607+
end,
2608+
("END_FOR", None, 5),
2609+
("POP_TOP", None, 6),
2610+
("LOAD_CONST", 0, 7),
2611+
("RETURN_VALUE", None, 8),
2612+
]
2613+
self.cfg_optimization_test(insts, expected, consts=[None])
26022614

26032615
def test_load_attr(self):
26042616
insts = [
@@ -2664,7 +2676,7 @@ def test_send(self):
26642676
("RETURN_VALUE", None, 7)
26652677
]
26662678
expected = [
2667-
("LOAD_FAST", 0, 1),
2679+
("LOAD_FAST_BORROW", 0, 1),
26682680
("LOAD_FAST_BORROW", 1, 2),
26692681
("SEND", end := self.Label(), 3),
26702682
("LOAD_CONST", 0, 4),
@@ -2675,6 +2687,69 @@ def test_send(self):
26752687
]
26762688
self.cfg_optimization_test(insts, expected, consts=[None])
26772689

2690+
def test_borrow_checks_exception_handler_edges(self):
2691+
insts = [
2692+
("LOAD_FAST", 0, 1),
2693+
("JUMP", start := self.Label(), 2),
2694+
start,
2695+
("SETUP_FINALLY", handler := self.Label(), 3),
2696+
("LOAD_CONST", 0, 4),
2697+
("BINARY_OP", 0, 5),
2698+
("POP_BLOCK", None, 6),
2699+
("RETURN_VALUE", None, 7),
2700+
handler,
2701+
("STORE_FAST", 1, 8),
2702+
("LOAD_CONST", 0, 9),
2703+
("STORE_FAST", 0, 10),
2704+
("POP_TOP", None, 11),
2705+
("LOAD_CONST", 0, 12),
2706+
("RETURN_VALUE", None, 13),
2707+
]
2708+
expected = [
2709+
("LOAD_FAST", 0, 1),
2710+
("NOP", None, 2),
2711+
("SETUP_FINALLY", handler := self.Label(), 3),
2712+
("LOAD_CONST", 0, 4),
2713+
("BINARY_OP", 0, 5),
2714+
("NOP", None, 6),
2715+
("RETURN_VALUE", None, 7),
2716+
handler,
2717+
("STORE_FAST", 1, 8),
2718+
("LOAD_CONST", 0, 9),
2719+
("STORE_FAST", 0, 10),
2720+
("POP_TOP", None, 11),
2721+
("LOAD_CONST", 0, 12),
2722+
("RETURN_VALUE", None, 13),
2723+
]
2724+
self.cfg_optimization_test(insts, expected, consts=[None])
2725+
2726+
def test_copied_reference_is_not_borrowed(self):
2727+
insts = [
2728+
("LOAD_FAST", 0, 1),
2729+
("COPY", 1, 1),
2730+
("TO_BOOL", None, 1),
2731+
("POP_JUMP_IF_TRUE", target := self.Label(), 1),
2732+
("POP_TOP", None, 1),
2733+
("LOAD_FAST", 1, 1),
2734+
target,
2735+
("STORE_FAST", 0, 1),
2736+
("LOAD_CONST", 0, 2),
2737+
("RETURN_VALUE", None, 2),
2738+
]
2739+
expected = [
2740+
("LOAD_FAST", 0, 1),
2741+
("COPY", 1, 1),
2742+
("TO_BOOL", None, 1),
2743+
("POP_JUMP_IF_TRUE", target := self.Label(), 1),
2744+
("POP_TOP", None, 1),
2745+
("LOAD_FAST", 1, 1),
2746+
target,
2747+
("STORE_FAST", 0, 1),
2748+
("LOAD_CONST", 0, 2),
2749+
("RETURN_VALUE", None, 2),
2750+
]
2751+
self.cfg_optimization_test(insts, expected, consts=[None])
2752+
26782753
def test_format_simple(self):
26792754
# FORMAT_SIMPLE will leave its operand on the stack if it's a unicode
26802755
# object. We treat it conservatively and assume that it always leaves
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The peephole optimizer now converts LOAD_FAST to LOAD_FAST_BORROW more aggressively. This optimization is applied even if the loaded variable remains live on the stack at the end of a basic block, as long as the borrow is otherwise determined to be safe. This can reduce reference counting overhead in certain code patterns, such as with iterables in loops.

0 commit comments

Comments
 (0)