cranelift_codegen/
unreachable_code.rs

1//! Unreachable code elimination.
2
3use cranelift_entity::EntitySet;
4
5use crate::cursor::{Cursor, FuncCursor};
6use crate::dominator_tree::DominatorTree;
7use crate::flowgraph::ControlFlowGraph;
8use crate::timing;
9use 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.
17pub 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}