@@ -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