Skip to main content

cranelift_codegen/
unreachable_code.rs

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