1 //! Unreachable code elimination. 2 3 use cranelift_entity::EntitySet; 4 5 use crate::cursor::{Cursor, FuncCursor}; 6 use crate::dominator_tree::DominatorTree; 7 use crate::flowgraph::ControlFlowGraph; 8 use crate::timing; 9 use crate::{ir, trace}; 10 11 /// Eliminate unreachable code. 12 /// 13 /// This pass deletes whole blocks that can't be reached from the entry block. It does not delete 14 /// individual instructions whose results are unused. 15 /// 16 /// The reachability analysis is performed by the dominator tree analysis. 17 pub fn eliminate_unreachable_code( 18 func: &mut ir::Function, 19 cfg: &mut ControlFlowGraph, 20 domtree: &DominatorTree, 21 ) { 22 let _tt = timing::unreachable_code(); 23 let mut pos = FuncCursor::new(func); 24 let mut used_tables = EntitySet::with_capacity(pos.func.stencil.dfg.jump_tables.len()); 25 let mut used_exception_tables = 26 EntitySet::with_capacity(pos.func.stencil.dfg.exception_tables.len()); 27 while let Some(block) = pos.next_block() { 28 if domtree.is_reachable(block) { 29 let inst = pos.func.layout.last_inst(block).unwrap(); 30 match pos.func.dfg.insts[inst] { 31 ir::InstructionData::BranchTable { table, .. } => { 32 used_tables.insert(table); 33 } 34 ir::InstructionData::TryCall { exception, .. } 35 | ir::InstructionData::TryCallIndirect { exception, .. } => { 36 used_exception_tables.insert(exception); 37 } 38 _ => (), 39 } 40 continue; 41 } 42 43 trace!("Eliminating unreachable {}", block); 44 // Move the cursor out of the way and make sure the next lop iteration goes to the right 45 // block. 46 pos.prev_block(); 47 48 // Remove all instructions from `block`. 49 while let Some(inst) = pos.func.layout.first_inst(block) { 50 trace!(" - {}", pos.func.dfg.display_inst(inst)); 51 pos.func.layout.remove_inst(inst); 52 } 53 54 // Once the block is completely empty, we can update the CFG which removes it from any 55 // predecessor lists. 56 cfg.recompute_block(pos.func, block); 57 58 // Finally, remove the block from the layout. 59 pos.func.layout.remove_block(block); 60 } 61 62 for (table, jt_data) in func.stencil.dfg.jump_tables.iter_mut() { 63 if !used_tables.contains(table) { 64 jt_data.clear(); 65 } 66 } 67 68 for (exception, exception_data) in func.stencil.dfg.exception_tables.iter_mut() { 69 if !used_exception_tables.contains(exception) { 70 exception_data.clear(); 71 } 72 } 73 } 74