diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index e0cc010f15513b..1d8c6422faeaa3 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -1129,6 +1129,14 @@ def f(self): print(ExecError) self.assertInBytecode(f, "LOAD_FAST_BORROW", "self") + def test_ternary_expression_uses_load_fast_borrow(self): + def f(a, b): + return a if a < b else b + + self.assertNotInBytecode(f, "LOAD_FAST") + self.assertInBytecode(f, "LOAD_FAST_BORROW", "a") + self.assertInBytecode(f, "LOAD_FAST_BORROW", "b") + class DirectCfgOptimizerTests(CfgOptimizationTestCase): def cfg_optimization_test(self, insts, expected_insts, diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-27-04-16-08.gh-issue-145629.eLFhwn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-27-04-16-08.gh-issue-145629.eLFhwn.rst new file mode 100644 index 00000000000000..705057a6ab95a1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-27-04-16-08.gh-issue-145629.eLFhwn.rst @@ -0,0 +1 @@ +Fix missed ``LOAD_FAST_BORROW`` optimization for ternary expressions by improving basic block inlining during the compiler's control flow graph optimization phase. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index f446a87ee69432..36d57b0fbed1c0 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1218,6 +1218,7 @@ basicblock_has_no_lineno(basicblock *b) { /* If this block ends with an unconditional jump to a small exit block or * a block that has no line numbers (and no fallthrough), then * remove the jump and extend this block with the target. + * Also handles the case where a block falls through to a small exit block. * Returns 1 if extended, 0 if no change, and -1 on error. */ static int @@ -1227,6 +1228,15 @@ basicblock_inline_small_or_no_lineno_blocks(basicblock *bb) { return 0; } if (!IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { + // If the block ends with a fallthrough to a small exit block, inline it. + if (BB_HAS_FALLTHROUGH(bb) && bb->b_next != NULL && !is_jump(last)) { + basicblock *next = bb->b_next; + if (basicblock_exits_scope(next) && next->b_iused <= MAX_COPY_SIZE) { + RETURN_IF_ERROR(basicblock_append_instructions(bb, next)); + next->b_predecessors--; + return 1; + } + } return 0; } basicblock *target = last->i_target;