| //! Unreachable code elimination. |
| |
| use cranelift_entity::EntitySet; |
| |
| use crate::cursor::{Cursor, FuncCursor}; |
| use crate::dominator_tree::DominatorTree; |
| use crate::flowgraph::ControlFlowGraph; |
| use crate::timing; |
| use crate::{ir, trace}; |
| |
| /// Eliminate unreachable code. |
| /// |
| /// This pass deletes whole blocks that can't be reached from the entry block. It does not delete |
| /// individual instructions whose results are unused. |
| /// |
| /// The reachability analysis is performed by the dominator tree analysis. |
| pub fn eliminate_unreachable_code( |
| func: &mut ir::Function, |
| cfg: &mut ControlFlowGraph, |
| domtree: &DominatorTree, |
| ) { |
| let _tt = timing::unreachable_code(); |
| let mut pos = FuncCursor::new(func); |
| let mut used_tables = EntitySet::with_capacity(pos.func.stencil.dfg.jump_tables.len()); |
| while let Some(block) = pos.next_block() { |
| if domtree.is_reachable(block) { |
| let inst = pos.func.layout.last_inst(block).unwrap(); |
| if let ir::InstructionData::BranchTable { table, .. } = pos.func.dfg.insts[inst] { |
| used_tables.insert(table); |
| } |
| continue; |
| } |
| |
| trace!("Eliminating unreachable {}", block); |
| // Move the cursor out of the way and make sure the next lop iteration goes to the right |
| // block. |
| pos.prev_block(); |
| |
| // Remove all instructions from `block`. |
| while let Some(inst) = pos.func.layout.first_inst(block) { |
| trace!(" - {}", pos.func.dfg.display_inst(inst)); |
| pos.func.layout.remove_inst(inst); |
| } |
| |
| // Once the block is completely empty, we can update the CFG which removes it from any |
| // predecessor lists. |
| cfg.recompute_block(pos.func, block); |
| |
| // Finally, remove the block from the layout. |
| pos.func.layout.remove_block(block); |
| } |
| |
| for (table, jt_data) in func.stencil.dfg.jump_tables.iter_mut() { |
| if !used_tables.contains(table) { |
| jt_data.clear(); |
| } |
| } |
| } |