/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 | | } |