@@ -241,6 +241,12 @@ impl CodeInfo {
241241 self . dce ( ) ; // truncate after terminal in blocks that got return duplicated
242242 self . eliminate_unreachable_blocks ( ) ; // remove now-unreachable last block
243243 remove_redundant_nops_and_jumps ( & mut self . blocks ) ;
244+ // Some jump-only blocks only appear after late CFG cleanup. Thread them
245+ // once more so loop backedges stay direct instead of becoming
246+ // JUMP_FORWARD -> JUMP_BACKWARD chains.
247+ jump_threading ( & mut self . blocks ) ;
248+ self . eliminate_unreachable_blocks ( ) ;
249+ remove_redundant_nops_and_jumps ( & mut self . blocks ) ;
244250 self . add_checks_for_loads_of_uninitialized_variables ( ) ;
245251 // optimize_load_fast: after normalize_jumps
246252 self . optimize_load_fast_borrow ( ) ;
@@ -3199,6 +3205,13 @@ fn is_exit_without_lineno(block: &Block) -> bool {
31993205 !instruction_has_lineno ( first) && last. instr . is_scope_exit ( )
32003206}
32013207
3208+ fn is_jump_only_block ( block : & Block ) -> bool {
3209+ let [ instr] = block. instructions . as_slice ( ) else {
3210+ return false ;
3211+ } ;
3212+ instr. instr . is_unconditional_jump ( ) && instr. target != BlockIdx :: NULL
3213+ }
3214+
32023215fn maybe_propagate_location (
32033216 instr : & mut InstructionInfo ,
32043217 location : SourceLocation ,
@@ -3321,6 +3334,45 @@ fn duplicate_exits_without_lineno(blocks: &mut Vec<Block>, predecessors: &mut Ve
33213334 }
33223335}
33233336
3337+ fn duplicate_jump_targets_without_lineno ( blocks : & mut Vec < Block > , predecessors : & mut Vec < u32 > ) {
3338+ let mut current = BlockIdx ( 0 ) ;
3339+ while current != BlockIdx :: NULL {
3340+ let block = & blocks[ current. idx ( ) ] ;
3341+ let last = match block. instructions . last ( ) {
3342+ Some ( ins) if ins. instr . is_unconditional_jump ( ) && ins. target != BlockIdx :: NULL => * ins,
3343+ _ => {
3344+ current = blocks[ current. idx ( ) ] . next ;
3345+ continue ;
3346+ }
3347+ } ;
3348+
3349+ let target = next_nonempty_block ( blocks, last. target ) ;
3350+ if target == BlockIdx :: NULL || !is_jump_only_block ( & blocks[ target. idx ( ) ] ) {
3351+ current = blocks[ current. idx ( ) ] . next ;
3352+ continue ;
3353+ }
3354+ if predecessors[ target. idx ( ) ] <= 1 {
3355+ current = blocks[ current. idx ( ) ] . next ;
3356+ continue ;
3357+ }
3358+
3359+ let new_idx = BlockIdx ( blocks. len ( ) as u32 ) ;
3360+ let mut new_block = blocks[ target. idx ( ) ] . clone ( ) ;
3361+ propagate_locations_in_block ( & mut new_block, last. location , last. end_location ) ;
3362+ let old_next = blocks[ current. idx ( ) ] . next ;
3363+ new_block. next = old_next;
3364+ blocks. push ( new_block) ;
3365+ blocks[ current. idx ( ) ] . next = new_idx;
3366+
3367+ let last_mut = blocks[ current. idx ( ) ] . instructions . last_mut ( ) . unwrap ( ) ;
3368+ last_mut. target = new_idx;
3369+ predecessors[ target. idx ( ) ] -= 1 ;
3370+ predecessors. push ( 1 ) ;
3371+
3372+ current = old_next;
3373+ }
3374+ }
3375+
33243376fn propagate_line_numbers ( blocks : & mut [ Block ] , predecessors : & [ u32 ] ) {
33253377 let mut current = BlockIdx ( 0 ) ;
33263378 while current != BlockIdx :: NULL {
@@ -3371,6 +3423,7 @@ fn propagate_line_numbers(blocks: &mut [Block], predecessors: &[u32]) {
33713423fn resolve_line_numbers ( blocks : & mut Vec < Block > ) {
33723424 let mut predecessors = compute_predecessors ( blocks) ;
33733425 duplicate_exits_without_lineno ( blocks, & mut predecessors) ;
3426+ duplicate_jump_targets_without_lineno ( blocks, & mut predecessors) ;
33743427 propagate_line_numbers ( blocks, & predecessors) ;
33753428}
33763429
0 commit comments