Coverage Report

Created: 2026-02-14 07:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/regalloc2-0.13.5/src/domtree.rs
Line
Count
Source
1
/*
2
 * Derives from the dominator tree implementation in regalloc.rs, which is
3
 * licensed under the Apache Public License 2.0 with LLVM Exception. See:
4
 * https://github.com/bytecodealliance/regalloc.rs
5
 */
6
7
// This is an implementation of the algorithm described in
8
//
9
//   A Simple, Fast Dominance Algorithm
10
//   Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
11
//   Department of Computer Science, Rice University, Houston, Texas, USA
12
//   TR-06-33870
13
//   https://www.cs.rice.edu/~keith/EMBED/dom.pdf
14
15
use core::u32;
16
17
use alloc::vec::Vec;
18
19
use crate::{Block, VecExt};
20
21
// Helper
22
506k
fn merge_sets(
23
506k
    idom: &[Block], // map from Block to Block
24
506k
    block_to_rpo: &[Option<u32>],
25
506k
    mut node1: Block,
26
506k
    mut node2: Block,
27
506k
) -> Block {
28
2.40M
    while node1 != node2 {
29
1.90M
        if node1.is_invalid() || node2.is_invalid() {
30
0
            return Block::invalid();
31
1.90M
        }
32
1.90M
        let rpo1 = block_to_rpo[node1.index()].unwrap();
33
1.90M
        let rpo2 = block_to_rpo[node2.index()].unwrap();
34
1.90M
        if rpo1 > rpo2 {
35
734k
            node1 = idom[node1.index()];
36
1.16M
        } else if rpo2 > rpo1 {
37
1.16M
            node2 = idom[node2.index()];
38
1.16M
        }
39
    }
40
506k
    debug_assert!(node1 == node2);
41
506k
    node1
42
506k
}
43
44
430k
pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
45
430k
    num_blocks: usize,
46
430k
    preds: PredFn,
47
430k
    post_ord: &[Block],
48
430k
    block_to_rpo_scratch: &mut Vec<Option<u32>>,
49
430k
    out: &mut Vec<Block>,
50
430k
    start: Block,
51
430k
) {
52
    // We have post_ord, which is the postorder sequence.
53
    // Compute maps from RPO to block number and vice-versa.
54
430k
    let block_to_rpo = block_to_rpo_scratch.repopulate(num_blocks, None);
55
2.27M
    for (i, rpo_block) in post_ord.iter().rev().enumerate() {
56
2.27M
        block_to_rpo[rpo_block.index()] = Some(i as u32);
57
2.27M
    }
58
59
430k
    let idom = out.repopulate(num_blocks, Block::invalid());
60
    // The start node must have itself as a parent.
61
430k
    idom[start.index()] = start;
62
63
430k
    let mut changed = true;
64
1.06M
    while changed {
65
630k
        changed = false;
66
        // Consider blocks in reverse postorder. Skip any that are unreachable.
67
4.32M
        for &node in post_ord.iter().rev() {
68
4.32M
            let rponum = block_to_rpo[node.index()].unwrap();
69
70
4.32M
            let mut parent = Block::invalid();
71
4.32M
            for &pred in preds(node).iter() {
72
3.71M
                let pred_rpo = match block_to_rpo[pred.index()] {
73
                    None => {
74
                        // Skip unreachable preds.
75
0
                        continue;
76
                    }
77
3.71M
                    Some(r) => r,
78
                };
79
3.71M
                if pred_rpo < rponum {
80
3.69M
                    parent = pred;
81
3.69M
                    break;
82
28.2k
                }
83
            }
84
85
4.32M
            if parent.is_valid() {
86
4.21M
                for &pred in preds(node).iter() {
87
4.21M
                    if pred == parent {
88
3.69M
                        continue;
89
521k
                    }
90
521k
                    if idom[pred.index()].is_invalid() {
91
14.1k
                        continue;
92
506k
                    }
93
506k
                    parent = merge_sets(&idom, &block_to_rpo[..], parent, pred);
94
                }
95
630k
            }
96
97
4.32M
            if parent.is_valid() && parent != idom[node.index()] {
98
1.84M
                idom[node.index()] = parent;
99
1.84M
                changed = true;
100
2.47M
            }
101
        }
102
    }
103
104
    // Now set the start node's dominator-tree parent to "invalid";
105
    // this allows the loop in `dominates` to terminate.
106
430k
    idom[start.index()] = Block::invalid();
107
430k
}
regalloc2::domtree::calculate::<<regalloc2::cfg::CFGInfo>::init<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>::{closure#1}>
Line
Count
Source
44
96.6k
pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
45
96.6k
    num_blocks: usize,
46
96.6k
    preds: PredFn,
47
96.6k
    post_ord: &[Block],
48
96.6k
    block_to_rpo_scratch: &mut Vec<Option<u32>>,
49
96.6k
    out: &mut Vec<Block>,
50
96.6k
    start: Block,
51
96.6k
) {
52
    // We have post_ord, which is the postorder sequence.
53
    // Compute maps from RPO to block number and vice-versa.
54
96.6k
    let block_to_rpo = block_to_rpo_scratch.repopulate(num_blocks, None);
55
251k
    for (i, rpo_block) in post_ord.iter().rev().enumerate() {
56
251k
        block_to_rpo[rpo_block.index()] = Some(i as u32);
57
251k
    }
58
59
96.6k
    let idom = out.repopulate(num_blocks, Block::invalid());
60
    // The start node must have itself as a parent.
61
96.6k
    idom[start.index()] = start;
62
63
96.6k
    let mut changed = true;
64
222k
    while changed {
65
125k
        changed = false;
66
        // Consider blocks in reverse postorder. Skip any that are unreachable.
67
434k
        for &node in post_ord.iter().rev() {
68
434k
            let rponum = block_to_rpo[node.index()].unwrap();
69
70
434k
            let mut parent = Block::invalid();
71
434k
            for &pred in preds(node).iter() {
72
311k
                let pred_rpo = match block_to_rpo[pred.index()] {
73
                    None => {
74
                        // Skip unreachable preds.
75
0
                        continue;
76
                    }
77
311k
                    Some(r) => r,
78
                };
79
311k
                if pred_rpo < rponum {
80
308k
                    parent = pred;
81
308k
                    break;
82
2.75k
                }
83
            }
84
85
434k
            if parent.is_valid() {
86
375k
                for &pred in preds(node).iter() {
87
375k
                    if pred == parent {
88
308k
                        continue;
89
66.5k
                    }
90
66.5k
                    if idom[pred.index()].is_invalid() {
91
1.37k
                        continue;
92
65.1k
                    }
93
65.1k
                    parent = merge_sets(&idom, &block_to_rpo[..], parent, pred);
94
                }
95
125k
            }
96
97
434k
            if parent.is_valid() && parent != idom[node.index()] {
98
154k
                idom[node.index()] = parent;
99
154k
                changed = true;
100
280k
            }
101
        }
102
    }
103
104
    // Now set the start node's dominator-tree parent to "invalid";
105
    // this allows the loop in `dominates` to terminate.
106
96.6k
    idom[start.index()] = Block::invalid();
107
96.6k
}
Unexecuted instantiation: regalloc2::domtree::calculate::<<regalloc2::cfg::CFGInfo>::init<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>::{closure#1}>
Unexecuted instantiation: regalloc2::domtree::calculate::<<regalloc2::cfg::CFGInfo>::init<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>::{closure#1}>
Unexecuted instantiation: regalloc2::domtree::calculate::<_>
regalloc2::domtree::calculate::<<regalloc2::cfg::CFGInfo>::init<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::x64::lower::isle::generated_code::MInst>>::{closure#1}>
Line
Count
Source
44
333k
pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>(
45
333k
    num_blocks: usize,
46
333k
    preds: PredFn,
47
333k
    post_ord: &[Block],
48
333k
    block_to_rpo_scratch: &mut Vec<Option<u32>>,
49
333k
    out: &mut Vec<Block>,
50
333k
    start: Block,
51
333k
) {
52
    // We have post_ord, which is the postorder sequence.
53
    // Compute maps from RPO to block number and vice-versa.
54
333k
    let block_to_rpo = block_to_rpo_scratch.repopulate(num_blocks, None);
55
2.02M
    for (i, rpo_block) in post_ord.iter().rev().enumerate() {
56
2.02M
        block_to_rpo[rpo_block.index()] = Some(i as u32);
57
2.02M
    }
58
59
333k
    let idom = out.repopulate(num_blocks, Block::invalid());
60
    // The start node must have itself as a parent.
61
333k
    idom[start.index()] = start;
62
63
333k
    let mut changed = true;
64
838k
    while changed {
65
504k
        changed = false;
66
        // Consider blocks in reverse postorder. Skip any that are unreachable.
67
3.88M
        for &node in post_ord.iter().rev() {
68
3.88M
            let rponum = block_to_rpo[node.index()].unwrap();
69
70
3.88M
            let mut parent = Block::invalid();
71
3.88M
            for &pred in preds(node).iter() {
72
3.40M
                let pred_rpo = match block_to_rpo[pred.index()] {
73
                    None => {
74
                        // Skip unreachable preds.
75
0
                        continue;
76
                    }
77
3.40M
                    Some(r) => r,
78
                };
79
3.40M
                if pred_rpo < rponum {
80
3.38M
                    parent = pred;
81
3.38M
                    break;
82
25.5k
                }
83
            }
84
85
3.88M
            if parent.is_valid() {
86
3.83M
                for &pred in preds(node).iter() {
87
3.83M
                    if pred == parent {
88
3.38M
                        continue;
89
454k
                    }
90
454k
                    if idom[pred.index()].is_invalid() {
91
12.7k
                        continue;
92
441k
                    }
93
441k
                    parent = merge_sets(&idom, &block_to_rpo[..], parent, pred);
94
                }
95
504k
            }
96
97
3.88M
            if parent.is_valid() && parent != idom[node.index()] {
98
1.69M
                idom[node.index()] = parent;
99
1.69M
                changed = true;
100
2.19M
            }
101
        }
102
    }
103
104
    // Now set the start node's dominator-tree parent to "invalid";
105
    // this allows the loop in `dominates` to terminate.
106
333k
    idom[start.index()] = Block::invalid();
107
333k
}
Unexecuted instantiation: regalloc2::domtree::calculate::<<regalloc2::cfg::CFGInfo>::init<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::aarch64::lower::isle::generated_code::MInst>>::{closure#1}>
Unexecuted instantiation: regalloc2::domtree::calculate::<<regalloc2::cfg::CFGInfo>::init<cranelift_codegen::machinst::vcode::VCode<cranelift_codegen::isa::riscv64::lower::isle::generated_code::MInst>>::{closure#1}>
108
109
0
pub fn dominates(idom: &[Block], a: Block, mut b: Block) -> bool {
110
    loop {
111
0
        if a == b {
112
0
            return true;
113
0
        }
114
0
        if b.is_invalid() {
115
0
            return false;
116
0
        }
117
0
        b = idom[b.index()];
118
    }
119
0
}