Skip to content

Commit a24ceb9

Browse files
committed
Refine CFG scope-exit backedge ordering
1 parent 8dac612 commit a24ceb9

1 file changed

Lines changed: 82 additions & 26 deletions

File tree

crates/codegen/src/ir.rs

Lines changed: 82 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ impl CodeInfo {
310310
inline_single_predecessor_artificial_expr_exit_blocks(&mut self.blocks);
311311
push_cold_blocks_to_end(&mut self.blocks);
312312
reorder_conditional_chain_and_jump_back_blocks(&mut self.blocks);
313-
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks);
313+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, true, true);
314314

315315
// Phase 2: _PyCfg_OptimizedCfgToInstructionSequence (flowgraph.c)
316316
normalize_jumps(&mut self.blocks);
@@ -319,12 +319,15 @@ impl CodeInfo {
319319
reorder_conditional_break_continue_blocks(&mut self.blocks);
320320
reorder_conditional_explicit_continue_scope_exit_blocks(&mut self.blocks);
321321
reorder_conditional_implicit_continue_scope_exit_blocks(&mut self.blocks);
322-
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks);
322+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, true, true);
323323
reorder_exception_handler_conditional_continue_raise_blocks(&mut self.blocks);
324324
deduplicate_adjacent_jump_back_blocks(&mut self.blocks);
325325
reorder_conditional_body_and_implicit_continue_blocks(&mut self.blocks);
326-
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks);
326+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, true, true);
327327
reorder_jump_over_exception_cleanup_blocks(&mut self.blocks);
328+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, false, true);
329+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, false, true);
330+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, false, false);
328331
self.dce(); // re-run within-block DCE after normalize_jumps creates new instructions
329332
self.eliminate_unreachable_blocks();
330333
resolve_line_numbers(&mut self.blocks);
@@ -9410,7 +9413,7 @@ impl CodeInfo {
94109413
self.debug_block_dump(),
94119414
));
94129415
reorder_conditional_chain_and_jump_back_blocks(&mut self.blocks);
9413-
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks);
9416+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, true, true);
94149417

94159418
trace.push((
94169419
"after_push_cold_blocks_to_end".to_owned(),
@@ -9424,11 +9427,14 @@ impl CodeInfo {
94249427
reorder_conditional_break_continue_blocks(&mut self.blocks);
94259428
reorder_conditional_explicit_continue_scope_exit_blocks(&mut self.blocks);
94269429
reorder_conditional_implicit_continue_scope_exit_blocks(&mut self.blocks);
9427-
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks);
9430+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, true, true);
94289431
deduplicate_adjacent_jump_back_blocks(&mut self.blocks);
94299432
reorder_conditional_body_and_implicit_continue_blocks(&mut self.blocks);
9430-
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks);
9433+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, true, true);
94319434
reorder_jump_over_exception_cleanup_blocks(&mut self.blocks);
9435+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, false, true);
9436+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, false, true);
9437+
reorder_conditional_scope_exit_and_jump_back_blocks(&mut self.blocks, false, false);
94329438
trace.push(("after_reorder".to_owned(), self.debug_block_dump()));
94339439

94349440
self.dce();
@@ -11924,7 +11930,53 @@ fn reorder_conditional_chain_and_jump_back_blocks(blocks: &mut Vec<Block>) {
1192411930
}
1192511931
}
1192611932

11927-
fn reorder_conditional_scope_exit_and_jump_back_blocks(blocks: &mut [Block]) {
11933+
fn reorder_conditional_scope_exit_and_jump_back_blocks(
11934+
blocks: &mut [Block],
11935+
allow_for_iter_jump_targets: bool,
11936+
allow_true_scope_exit_reorder: bool,
11937+
) {
11938+
fn jump_targets_for_iter(blocks: &[Block], jump_block: BlockIdx) -> bool {
11939+
if jump_block == BlockIdx::NULL {
11940+
return false;
11941+
}
11942+
let Some(info) = blocks[jump_block.idx()].instructions.first() else {
11943+
return false;
11944+
};
11945+
let target = next_nonempty_block(blocks, info.target);
11946+
target != BlockIdx::NULL
11947+
&& blocks[target.idx()]
11948+
.instructions
11949+
.first()
11950+
.is_some_and(|target_info| {
11951+
matches!(target_info.instr.real(), Some(Instruction::ForIter { .. }))
11952+
})
11953+
}
11954+
11955+
fn is_explicit_continue_to_for_iter(blocks: &[Block], jump_block: BlockIdx) -> bool {
11956+
if jump_block == BlockIdx::NULL {
11957+
return false;
11958+
}
11959+
let Some(info) = blocks[jump_block.idx()].instructions.first() else {
11960+
return false;
11961+
};
11962+
matches!(
11963+
info.instr.real(),
11964+
Some(Instruction::JumpBackward { .. } | Instruction::JumpBackwardNoInterrupt { .. })
11965+
) && !matches!(info.lineno_override, Some(line) if line < 0)
11966+
&& jump_targets_for_iter(blocks, jump_block)
11967+
}
11968+
11969+
fn is_explicit_non_for_jump_back(blocks: &[Block], jump_block: BlockIdx) -> bool {
11970+
if jump_block == BlockIdx::NULL || jump_targets_for_iter(blocks, jump_block) {
11971+
return false;
11972+
}
11973+
let Some(info) = blocks[jump_block.idx()].instructions.first() else {
11974+
return false;
11975+
};
11976+
matches!(info.instr.real(), Some(Instruction::JumpBackward { .. }))
11977+
&& info.lineno_override.is_some_and(|line| line >= 0)
11978+
}
11979+
1192811980
let mut current = BlockIdx(0);
1192911981
while current != BlockIdx::NULL {
1193011982
let idx = current.idx();
@@ -11939,6 +11991,11 @@ fn reorder_conditional_scope_exit_and_jump_back_blocks(blocks: &mut [Block]) {
1193911991
let exit_block = next_nonempty_block(blocks, exit_start);
1194011992
let jump_start = cond.target;
1194111993
let jump_block = next_nonempty_block(blocks, jump_start);
11994+
let after_jump = if jump_block != BlockIdx::NULL {
11995+
next_nonempty_block(blocks, blocks[jump_block.idx()].next)
11996+
} else {
11997+
BlockIdx::NULL
11998+
};
1194211999
if exit_start == BlockIdx::NULL
1194312000
|| exit_block == BlockIdx::NULL
1194412001
|| jump_start == BlockIdx::NULL
@@ -11952,6 +12009,18 @@ fn reorder_conditional_scope_exit_and_jump_back_blocks(blocks: &mut [Block]) {
1195212009
|| block_is_protected(&blocks[exit_block.idx()])
1195312010
|| !is_scope_exit_block(&blocks[exit_block.idx()])
1195412011
|| !is_jump_back_only_block(blocks, jump_block)
12012+
|| (!allow_for_iter_jump_targets
12013+
&& is_explicit_continue_to_for_iter(blocks, jump_block))
12014+
&& blocks[exit_block.idx()].instructions.iter().any(|info| {
12015+
matches!(info.instr.real(), Some(Instruction::RaiseVarargs { .. }))
12016+
})
12017+
|| (!allow_for_iter_jump_targets
12018+
&& is_explicit_non_for_jump_back(blocks, jump_block))
12019+
|| (!allow_for_iter_jump_targets
12020+
&& after_jump != BlockIdx::NULL
12021+
&& !blocks[after_jump.idx()].cold
12022+
&& !is_scope_exit_block(&blocks[after_jump.idx()])
12023+
&& !is_loop_cleanup_block(&blocks[after_jump.idx()]))
1195512024
|| next_nonempty_block(blocks, blocks[exit_block.idx()].next) != jump_block
1195612025
{
1195712026
current = next;
@@ -11972,31 +12041,18 @@ fn reorder_conditional_scope_exit_and_jump_back_blocks(blocks: &mut [Block]) {
1197212041
current = next;
1197312042
continue;
1197412043
}
11975-
12044+
if !allow_true_scope_exit_reorder {
12045+
current = next;
12046+
continue;
12047+
}
1197612048
let exit_block = next_nonempty_block(blocks, cond.target);
1197712049
let jump_block = next_nonempty_block(blocks, next);
11978-
let jump_targets_for_iter = jump_block != BlockIdx::NULL
11979-
&& blocks[jump_block.idx()]
11980-
.instructions
11981-
.first()
11982-
.is_some_and(|info| {
11983-
let target = next_nonempty_block(blocks, info.target);
11984-
target != BlockIdx::NULL
11985-
&& blocks[target.idx()]
11986-
.instructions
11987-
.first()
11988-
.is_some_and(|target_info| {
11989-
matches!(
11990-
target_info.instr.real(),
11991-
Some(Instruction::ForIter { .. })
11992-
)
11993-
})
11994-
});
1199512050
if exit_block == BlockIdx::NULL
1199612051
|| jump_block == BlockIdx::NULL
1199712052
|| !is_scope_exit_block(&blocks[exit_block.idx()])
1199812053
|| !is_jump_only_block(&blocks[jump_block.idx()])
11999-
|| jump_targets_for_iter
12054+
|| (jump_targets_for_iter(blocks, jump_block)
12055+
&& !is_explicit_continue_to_for_iter(blocks, jump_block))
1200012056
|| next_nonempty_block(blocks, blocks[jump_block.idx()].next) != exit_block
1200112057
|| !comes_before(
1200212058
blocks,

0 commit comments

Comments
 (0)