1 //! Unreachable code elimination.
2 
3 use crate::cursor::{Cursor, FuncCursor};
4 use crate::dominator_tree::DominatorTree;
5 use crate::flowgraph::ControlFlowGraph;
6 use crate::ir;
7 use crate::timing;
8 
9 /// Eliminate unreachable code.
10 ///
11 /// This pass deletes whole blocks that can't be reached from the entry block. It does not delete
12 /// individual instructions whose results are unused.
13 ///
14 /// The reachability analysis is performed by the dominator tree analysis.
eliminate_unreachable_code( func: &mut ir::Function, cfg: &mut ControlFlowGraph, domtree: &DominatorTree, )15 pub fn eliminate_unreachable_code(
16     func: &mut ir::Function,
17     cfg: &mut ControlFlowGraph,
18     domtree: &DominatorTree,
19 ) {
20     let _tt = timing::unreachable_code();
21     let mut pos = FuncCursor::new(func);
22     while let Some(block) = pos.next_block() {
23         if domtree.is_reachable(block) {
24             continue;
25         }
26 
27         log::trace!("Eliminating unreachable {}", block);
28         // Move the cursor out of the way and make sure the next lop iteration goes to the right
29         // block.
30         pos.prev_block();
31 
32         // Remove all instructions from `block`.
33         while let Some(inst) = pos.func.layout.first_inst(block) {
34             log::trace!(" - {}", pos.func.dfg.display_inst(inst, None));
35             pos.func.layout.remove_inst(inst);
36         }
37 
38         // Once the block is completely empty, we can update the CFG which removes it from any
39         // predecessor lists.
40         cfg.recompute_block(pos.func, block);
41 
42         // Finally, remove the block from the layout.
43         pos.func.layout.remove_block(block);
44     }
45 
46     // Remove all jumptable block-list contents that refer to unreachable
47     // blocks; the jumptable itself must have been unused (or used only in an
48     // unreachable block) if so. Note that we are not necessarily removing *all*
49     // unused jumptables, because that would require computing their
50     // reachability as well; we are just removing enough to clean up references
51     // to deleted blocks.
52     for jt_data in func.jump_tables.values_mut() {
53         let invalid_ref = jt_data.iter().any(|block| !domtree.is_reachable(*block));
54         if invalid_ref {
55             jt_data.clear();
56         }
57     }
58 }
59