Jump threading: when a block's last jump targets a block whose first instruction is an unconditional jump, redirect to the final target. flowgraph.c optimize_basic_block + jump_thread
(blocks: &mut [Block])
| 2287 | /// instruction is an unconditional jump, redirect to the final target. |
| 2288 | /// flowgraph.c optimize_basic_block + jump_thread |
| 2289 | fn jump_threading(blocks: &mut [Block]) { |
| 2290 | let mut changed = true; |
| 2291 | while changed { |
| 2292 | changed = false; |
| 2293 | for bi in 0..blocks.len() { |
| 2294 | let last_idx = match blocks[bi].instructions.len().checked_sub(1) { |
| 2295 | Some(i) => i, |
| 2296 | None => continue, |
| 2297 | }; |
| 2298 | let ins = &blocks[bi].instructions[last_idx]; |
| 2299 | let target = ins.target; |
| 2300 | if target == BlockIdx::NULL { |
| 2301 | continue; |
| 2302 | } |
| 2303 | if !ins.instr.is_unconditional_jump() && !is_conditional_jump(&ins.instr) { |
| 2304 | continue; |
| 2305 | } |
| 2306 | // Check if target block's first instruction is an unconditional jump |
| 2307 | let target_block = &blocks[target.idx()]; |
| 2308 | if let Some(target_ins) = target_block.instructions.first() |
| 2309 | && target_ins.instr.is_unconditional_jump() |
| 2310 | && target_ins.target != BlockIdx::NULL |
| 2311 | && target_ins.target != target |
| 2312 | { |
| 2313 | let final_target = target_ins.target; |
| 2314 | blocks[bi].instructions[last_idx].target = final_target; |
| 2315 | changed = true; |
| 2316 | } |
| 2317 | } |
| 2318 | } |
| 2319 | } |
| 2320 | |
| 2321 | fn is_conditional_jump(instr: &AnyInstruction) -> bool { |
| 2322 | matches!( |
no test coverage detected