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.
eliminate_unreachable_code( func: &mut ir::Function, cfg: &mut ControlFlowGraph, domtree: &DominatorTree, )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