Coverage Report

Created: 2025-01-09 07:53

/src/regalloc2/src/cfg.rs
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Released under the terms of the Apache 2.0 license with LLVM
3
 * exception. See `LICENSE` for details.
4
 */
5
6
//! Lightweight CFG analyses.
7
8
use crate::alloc::vec::Vec;
9
10
use crate::{domtree, postorder, Block, Function, Inst, ProgPoint, RegAllocError, VecExt};
11
use smallvec::{smallvec, SmallVec};
12
13
#[derive(Debug, Default)]
14
pub struct CFGInfoCtx {
15
    visited: Vec<bool>,
16
    block_to_rpo: Vec<Option<u32>>,
17
    backedge: Vec<u32>,
18
}
19
20
#[derive(Debug, Default)]
21
pub struct CFGInfo {
22
    /// Postorder traversal of blocks.
23
    pub postorder: Vec<Block>,
24
    /// Domtree parents, indexed by block.
25
    pub domtree: Vec<Block>,
26
    /// For each instruction, the block it belongs to.
27
    pub insn_block: Vec<Block>,
28
    /// For each block, the first instruction.
29
    pub block_entry: Vec<ProgPoint>,
30
    /// For each block, the last instruction.
31
    pub block_exit: Vec<ProgPoint>,
32
    /// For each block, what is the approximate loop depth?
33
    ///
34
    /// This measure is fully precise iff the input CFG is reducible
35
    /// and blocks are in RPO, so that loop backedges are precisely
36
    /// those whose block target indices are less than their source
37
    /// indices. Otherwise, it will be approximate, but should still
38
    /// be usable for heuristic purposes.
39
    pub approx_loop_depth: Vec<u32>,
40
}
41
42
impl CFGInfo {
43
0
    pub fn new<F: Function>(f: &F) -> Result<Self, RegAllocError> {
44
0
        let mut ctx = CFGInfoCtx::default();
45
0
        let mut this = Self::default();
46
0
        this.init(f, &mut ctx)?;
47
0
        Ok(this)
48
0
    }
49
50
11.3k
    pub fn init<F: Function>(&mut self, f: &F, ctx: &mut CFGInfoCtx) -> Result<(), RegAllocError> {
51
11.3k
        let nb = f.num_blocks();
52
11.3k
53
11.3k
        postorder::calculate(
54
11.3k
            nb,
55
11.3k
            f.entry_block(),
56
11.3k
            &mut ctx.visited,
57
11.3k
            &mut self.postorder,
58
559k
            |block| f.block_succs(block),
<regalloc2::cfg::CFGInfo>::init::<regalloc2::fuzzing::func::Func>::{closure#0}
Line
Count
Source
58
559k
            |block| f.block_succs(block),
Unexecuted instantiation: <regalloc2::cfg::CFGInfo>::init::<_>::{closure#0}
59
11.3k
        );
60
11.3k
61
11.3k
        domtree::calculate(
62
11.3k
            nb,
63
2.79M
            |block| f.block_preds(block),
<regalloc2::cfg::CFGInfo>::init::<regalloc2::fuzzing::func::Func>::{closure#1}
Line
Count
Source
63
2.79M
            |block| f.block_preds(block),
Unexecuted instantiation: <regalloc2::cfg::CFGInfo>::init::<_>::{closure#1}
64
11.3k
            &self.postorder,
65
11.3k
            &mut ctx.block_to_rpo,
66
11.3k
            &mut self.domtree,
67
11.3k
            f.entry_block(),
68
11.3k
        );
69
11.3k
70
11.3k
        let insn_block = self.insn_block.repopulate(f.num_insts(), Block::invalid());
71
11.3k
        let block_entry = self
72
11.3k
            .block_entry
73
11.3k
            .repopulate(nb, ProgPoint::before(Inst::invalid()));
74
11.3k
        let block_exit = self
75
11.3k
            .block_exit
76
11.3k
            .repopulate(nb, ProgPoint::before(Inst::invalid()));
77
11.3k
        let (backedge_in, backedge_out) = ctx.backedge.repopulate(nb * 2, 0).split_at_mut(nb);
78
79
559k
        for block in 0..f.num_blocks() {
80
559k
            let block = Block::new(block);
81
5.29M
            for inst in f.block_insns(block).iter() {
82
5.29M
                insn_block[inst.index()] = block;
83
5.29M
            }
84
559k
            block_entry[block.index()] = ProgPoint::before(f.block_insns(block).first());
85
559k
            block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last());
86
87
            // Check critical edge condition: if there is more than
88
            // one predecessor, each must have only one successor
89
            // (this block).
90
559k
            let preds = f.block_preds(block).len() + if block == f.entry_block() { 1 } else { 0 };
91
559k
            if preds > 1 {
92
195k
                for &pred in f.block_preds(block) {
93
195k
                    let succs = f.block_succs(pred).len();
94
195k
                    if succs > 1 {
95
0
                        return Err(RegAllocError::CritEdge(pred, block));
96
195k
                    }
97
                }
98
499k
            }
99
100
            // Check branch-arg condition: if any successors have more
101
            // than one predecessor (given above, there will only be
102
            // one such successor), then the last instruction of this
103
            // block (the branch) cannot have any args other than the
104
            // blockparams.
105
559k
            let mut require_no_branch_args = false;
106
688k
            for &succ in f.block_succs(block) {
107
688k
                let preds = f.block_preds(succ).len() + if succ == f.entry_block() { 1 } else { 0 };
108
688k
                if preds > 1 {
109
195k
                    require_no_branch_args = true;
110
195k
                    break;
111
492k
                }
112
            }
113
559k
            if require_no_branch_args {
114
195k
                let last = f.block_insns(block).last();
115
195k
                if !f.inst_operands(last).is_empty() {
116
0
                    return Err(RegAllocError::DisallowedBranchArg(last));
117
195k
                }
118
364k
            }
119
120
688k
            for &succ in f.block_succs(block) {
121
688k
                if succ.index() <= block.index() {
122
107k
                    backedge_in[succ.index()] += 1;
123
107k
                    backedge_out[block.index()] += 1;
124
580k
                }
125
            }
126
        }
127
128
11.3k
        let approx_loop_depth = self.approx_loop_depth.cleared();
129
11.3k
        let mut backedge_stack: SmallVec<[u32; 4]> = smallvec![];
130
11.3k
        let mut cur_depth = 0;
131
559k
        for block in 0..nb {
132
559k
            if backedge_in[block] > 0 {
133
45.2k
                cur_depth += 1;
134
45.2k
                backedge_stack.push(backedge_in[block]);
135
514k
            }
136
137
559k
            approx_loop_depth.push(cur_depth);
138
139
667k
            while backedge_stack.len() > 0 && backedge_out[block] > 0 {
140
107k
                backedge_out[block] -= 1;
141
107k
                *backedge_stack.last_mut().unwrap() -= 1;
142
107k
                if *backedge_stack.last().unwrap() == 0 {
143
45.2k
                    cur_depth -= 1;
144
45.2k
                    backedge_stack.pop();
145
62.3k
                }
146
            }
147
        }
148
149
11.3k
        Ok(())
150
11.3k
    }
<regalloc2::cfg::CFGInfo>::init::<regalloc2::fuzzing::func::Func>
Line
Count
Source
50
11.3k
    pub fn init<F: Function>(&mut self, f: &F, ctx: &mut CFGInfoCtx) -> Result<(), RegAllocError> {
51
11.3k
        let nb = f.num_blocks();
52
11.3k
53
11.3k
        postorder::calculate(
54
11.3k
            nb,
55
11.3k
            f.entry_block(),
56
11.3k
            &mut ctx.visited,
57
11.3k
            &mut self.postorder,
58
11.3k
            |block| f.block_succs(block),
59
11.3k
        );
60
11.3k
61
11.3k
        domtree::calculate(
62
11.3k
            nb,
63
11.3k
            |block| f.block_preds(block),
64
11.3k
            &self.postorder,
65
11.3k
            &mut ctx.block_to_rpo,
66
11.3k
            &mut self.domtree,
67
11.3k
            f.entry_block(),
68
11.3k
        );
69
11.3k
70
11.3k
        let insn_block = self.insn_block.repopulate(f.num_insts(), Block::invalid());
71
11.3k
        let block_entry = self
72
11.3k
            .block_entry
73
11.3k
            .repopulate(nb, ProgPoint::before(Inst::invalid()));
74
11.3k
        let block_exit = self
75
11.3k
            .block_exit
76
11.3k
            .repopulate(nb, ProgPoint::before(Inst::invalid()));
77
11.3k
        let (backedge_in, backedge_out) = ctx.backedge.repopulate(nb * 2, 0).split_at_mut(nb);
78
79
559k
        for block in 0..f.num_blocks() {
80
559k
            let block = Block::new(block);
81
5.29M
            for inst in f.block_insns(block).iter() {
82
5.29M
                insn_block[inst.index()] = block;
83
5.29M
            }
84
559k
            block_entry[block.index()] = ProgPoint::before(f.block_insns(block).first());
85
559k
            block_exit[block.index()] = ProgPoint::after(f.block_insns(block).last());
86
87
            // Check critical edge condition: if there is more than
88
            // one predecessor, each must have only one successor
89
            // (this block).
90
559k
            let preds = f.block_preds(block).len() + if block == f.entry_block() { 1 } else { 0 };
91
559k
            if preds > 1 {
92
195k
                for &pred in f.block_preds(block) {
93
195k
                    let succs = f.block_succs(pred).len();
94
195k
                    if succs > 1 {
95
0
                        return Err(RegAllocError::CritEdge(pred, block));
96
195k
                    }
97
                }
98
499k
            }
99
100
            // Check branch-arg condition: if any successors have more
101
            // than one predecessor (given above, there will only be
102
            // one such successor), then the last instruction of this
103
            // block (the branch) cannot have any args other than the
104
            // blockparams.
105
559k
            let mut require_no_branch_args = false;
106
688k
            for &succ in f.block_succs(block) {
107
688k
                let preds = f.block_preds(succ).len() + if succ == f.entry_block() { 1 } else { 0 };
108
688k
                if preds > 1 {
109
195k
                    require_no_branch_args = true;
110
195k
                    break;
111
492k
                }
112
            }
113
559k
            if require_no_branch_args {
114
195k
                let last = f.block_insns(block).last();
115
195k
                if !f.inst_operands(last).is_empty() {
116
0
                    return Err(RegAllocError::DisallowedBranchArg(last));
117
195k
                }
118
364k
            }
119
120
688k
            for &succ in f.block_succs(block) {
121
688k
                if succ.index() <= block.index() {
122
107k
                    backedge_in[succ.index()] += 1;
123
107k
                    backedge_out[block.index()] += 1;
124
580k
                }
125
            }
126
        }
127
128
11.3k
        let approx_loop_depth = self.approx_loop_depth.cleared();
129
11.3k
        let mut backedge_stack: SmallVec<[u32; 4]> = smallvec![];
130
11.3k
        let mut cur_depth = 0;
131
559k
        for block in 0..nb {
132
559k
            if backedge_in[block] > 0 {
133
45.2k
                cur_depth += 1;
134
45.2k
                backedge_stack.push(backedge_in[block]);
135
514k
            }
136
137
559k
            approx_loop_depth.push(cur_depth);
138
139
667k
            while backedge_stack.len() > 0 && backedge_out[block] > 0 {
140
107k
                backedge_out[block] -= 1;
141
107k
                *backedge_stack.last_mut().unwrap() -= 1;
142
107k
                if *backedge_stack.last().unwrap() == 0 {
143
45.2k
                    cur_depth -= 1;
144
45.2k
                    backedge_stack.pop();
145
62.3k
                }
146
            }
147
        }
148
149
11.3k
        Ok(())
150
11.3k
    }
Unexecuted instantiation: <regalloc2::cfg::CFGInfo>::init::<_>
151
152
0
    pub fn dominates(&self, a: Block, b: Block) -> bool {
153
0
        domtree::dominates(&self.domtree[..], a, b)
154
0
    }
155
}