1 //! A control flow graph represented as mappings of basic blocks to their predecessors
2 //! and successors.
3 //!
4 //! Successors are represented as basic blocks while predecessors are represented by basic
5 //! blocks. Basic blocks are denoted by tuples of block and branch/jump instructions. Each
6 //! predecessor tuple corresponds to the end of a basic block.
7 //!
8 //! ```c
9 //!     Block0:
10 //!         ...          ; beginning of basic block
11 //!
12 //!         ...
13 //!
14 //!         brif vx, Block1, Block2 ; end of basic block
15 //!
16 //!     Block1:
17 //!         jump block3
18 //! ```
19 //!
20 //! Here `Block1` and `Block2` would each have a single predecessor denoted as `(Block0, brif)`,
21 //! while `Block3` would have a single predecessor denoted as `(Block1, jump block3)`.
22 
23 use crate::bforest;
24 use crate::entity::SecondaryMap;
25 use crate::ir::{self, Block, Function, Inst};
26 use crate::timing;
27 use core::mem;
28 
29 /// A basic block denoted by its enclosing Block and last instruction.
30 #[derive(Debug, PartialEq, Eq)]
31 pub struct BlockPredecessor {
32     /// Enclosing Block key.
33     pub block: Block,
34     /// Last instruction in the basic block.
35     pub inst: Inst,
36 }
37 
38 impl BlockPredecessor {
39     /// Convenient method to construct new BlockPredecessor.
40     pub fn new(block: Block, inst: Inst) -> Self {
41         Self { block, inst }
42     }
43 }
44 
45 /// A container for the successors and predecessors of some Block.
46 #[derive(Clone, Default)]
47 struct CFGNode {
48     /// Instructions that can branch or jump to this block.
49     ///
50     /// This maps branch instruction -> predecessor block which is redundant since the block containing
51     /// the branch instruction is available from the `layout.inst_block()` method. We store the
52     /// redundant information because:
53     ///
54     /// 1. Many `pred_iter()` consumers want the block anyway, so it is handily available.
55     /// 2. The `invalidate_block_successors()` may be called *after* branches have been removed from
56     ///    their block, but we still need to remove them form the old block predecessor map.
57     ///
58     /// The redundant block stored here is always consistent with the CFG successor lists, even after
59     /// the IR has been edited.
60     pub predecessors: bforest::Map<Inst, Block>,
61 
62     /// Set of blocks that are the targets of branches and jumps in this block.
63     /// The set is ordered by block number, indicated by the `()` comparator type.
64     pub successors: bforest::Set<Block>,
65 }
66 
67 /// The Control Flow Graph maintains a mapping of blocks to their predecessors
68 /// and successors where predecessors are basic blocks and successors are
69 /// basic blocks.
70 pub struct ControlFlowGraph {
71     data: SecondaryMap<Block, CFGNode>,
72     pred_forest: bforest::MapForest<Inst, Block>,
73     succ_forest: bforest::SetForest<Block>,
74     valid: bool,
75 }
76 
77 impl ControlFlowGraph {
78     /// Allocate a new blank control flow graph.
79     pub fn new() -> Self {
80         Self {
81             data: SecondaryMap::new(),
82             valid: false,
83             pred_forest: bforest::MapForest::new(),
84             succ_forest: bforest::SetForest::new(),
85         }
86     }
87 
88     /// Clear all data structures in this control flow graph.
89     pub fn clear(&mut self) {
90         self.data.clear();
91         self.pred_forest.clear();
92         self.succ_forest.clear();
93         self.valid = false;
94     }
95 
96     /// Allocate and compute the control flow graph for `func`.
97     pub fn with_function(func: &Function) -> Self {
98         let mut cfg = Self::new();
99         cfg.compute(func);
100         cfg
101     }
102 
103     /// Compute the control flow graph of `func`.
104     ///
105     /// This will clear and overwrite any information already stored in this data structure.
106     pub fn compute(&mut self, func: &Function) {
107         let _tt = timing::flowgraph();
108         self.clear();
109         self.data.resize(func.dfg.num_blocks());
110 
111         for block in &func.layout {
112             self.compute_block(func, block);
113         }
114 
115         self.valid = true;
116     }
117 
118     fn compute_block(&mut self, func: &Function, block: Block) {
119         if let Some(inst) = func.layout.last_inst(block) {
120             match &func.dfg.insts[inst] {
121                 ir::InstructionData::Jump {
122                     destination: dest, ..
123                 } => {
124                     self.add_edge(block, inst, dest.block(&func.dfg.value_lists));
125                 }
126                 ir::InstructionData::Brif {
127                     blocks: [block_then, block_else],
128                     ..
129                 } => {
130                     self.add_edge(block, inst, block_then.block(&func.dfg.value_lists));
131                     self.add_edge(block, inst, block_else.block(&func.dfg.value_lists));
132                 }
133                 ir::InstructionData::BranchTable {
134                     table: jt,
135                     destination: dest,
136                     ..
137                 } => {
138                     self.add_edge(block, inst, *dest);
139 
140                     for dest in func.stencil.dfg.jump_tables[*jt].iter() {
141                         self.add_edge(block, inst, *dest);
142                     }
143                 }
144                 inst => debug_assert!(!inst.opcode().is_branch()),
145             }
146         }
147     }
148 
149     fn invalidate_block_successors(&mut self, block: Block) {
150         // Temporarily take ownership because we need mutable access to self.data inside the loop.
151         // Unfortunately borrowck cannot see that our mut accesses to predecessors don't alias
152         // our iteration over successors.
153         let mut successors = mem::replace(&mut self.data[block].successors, Default::default());
154         for succ in successors.iter(&self.succ_forest) {
155             self.data[succ]
156                 .predecessors
157                 .retain(&mut self.pred_forest, |_, &mut e| e != block);
158         }
159         successors.clear(&mut self.succ_forest);
160     }
161 
162     /// Recompute the control flow graph of `block`.
163     ///
164     /// This is for use after modifying instructions within a specific block. It recomputes all edges
165     /// from `block` while leaving edges to `block` intact. Its functionality a subset of that of the
166     /// more expensive `compute`, and should be used when we know we don't need to recompute the CFG
167     /// from scratch, but rather that our changes have been restricted to specific blocks.
168     pub fn recompute_block(&mut self, func: &Function, block: Block) {
169         debug_assert!(self.is_valid());
170         self.invalidate_block_successors(block);
171         self.compute_block(func, block);
172     }
173 
174     fn add_edge(&mut self, from: Block, from_inst: Inst, to: Block) {
175         self.data[from]
176             .successors
177             .insert(to, &mut self.succ_forest, &());
178         self.data[to]
179             .predecessors
180             .insert(from_inst, from, &mut self.pred_forest, &());
181     }
182 
183     /// Get an iterator over the CFG predecessors to `block`.
184     pub fn pred_iter(&self, block: Block) -> PredIter {
185         PredIter(self.data[block].predecessors.iter(&self.pred_forest))
186     }
187 
188     /// Get an iterator over the CFG successors to `block`.
189     pub fn succ_iter(&self, block: Block) -> SuccIter {
190         debug_assert!(self.is_valid());
191         self.data[block].successors.iter(&self.succ_forest)
192     }
193 
194     /// Check if the CFG is in a valid state.
195     ///
196     /// Note that this doesn't perform any kind of validity checks. It simply checks if the
197     /// `compute()` method has been called since the last `clear()`. It does not check that the
198     /// CFG is consistent with the function.
199     pub fn is_valid(&self) -> bool {
200         self.valid
201     }
202 }
203 
204 /// An iterator over block predecessors. The iterator type is `BlockPredecessor`.
205 ///
206 /// Each predecessor is an instruction that branches to the block.
207 pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Block>);
208 
209 impl<'a> Iterator for PredIter<'a> {
210     type Item = BlockPredecessor;
211 
212     fn next(&mut self) -> Option<BlockPredecessor> {
213         self.0.next().map(|(i, e)| BlockPredecessor::new(e, i))
214     }
215 }
216 
217 /// An iterator over block successors. The iterator type is `Block`.
218 pub type SuccIter<'a> = bforest::SetIter<'a, Block>;
219 
220 #[cfg(test)]
221 mod tests {
222     use super::*;
223     use crate::cursor::{Cursor, FuncCursor};
224     use crate::ir::{types, Function, InstBuilder};
225     use alloc::vec::Vec;
226 
227     #[test]
228     fn empty() {
229         let func = Function::new();
230         ControlFlowGraph::with_function(&func);
231     }
232 
233     #[test]
234     fn no_predecessors() {
235         let mut func = Function::new();
236         let block0 = func.dfg.make_block();
237         let block1 = func.dfg.make_block();
238         let block2 = func.dfg.make_block();
239         func.layout.append_block(block0);
240         func.layout.append_block(block1);
241         func.layout.append_block(block2);
242 
243         let cfg = ControlFlowGraph::with_function(&func);
244 
245         let mut fun_blocks = func.layout.blocks();
246         for block in func.layout.blocks() {
247             assert_eq!(block, fun_blocks.next().unwrap());
248             assert_eq!(cfg.pred_iter(block).count(), 0);
249             assert_eq!(cfg.succ_iter(block).count(), 0);
250         }
251     }
252 
253     #[test]
254     fn branches_and_jumps() {
255         let mut func = Function::new();
256         let block0 = func.dfg.make_block();
257         let cond = func.dfg.append_block_param(block0, types::I32);
258         let block1 = func.dfg.make_block();
259         let block2 = func.dfg.make_block();
260 
261         let br_block0_block2_block1;
262         let br_block1_block1_block2;
263 
264         {
265             let mut cur = FuncCursor::new(&mut func);
266 
267             cur.insert_block(block0);
268             br_block0_block2_block1 = cur.ins().brif(cond, block2, &[], block1, &[]);
269 
270             cur.insert_block(block1);
271             br_block1_block1_block2 = cur.ins().brif(cond, block1, &[], block2, &[]);
272 
273             cur.insert_block(block2);
274         }
275 
276         let mut cfg = ControlFlowGraph::with_function(&func);
277 
278         {
279             let block0_predecessors = cfg.pred_iter(block0).collect::<Vec<_>>();
280             let block1_predecessors = cfg.pred_iter(block1).collect::<Vec<_>>();
281             let block2_predecessors = cfg.pred_iter(block2).collect::<Vec<_>>();
282 
283             let block0_successors = cfg.succ_iter(block0).collect::<Vec<_>>();
284             let block1_successors = cfg.succ_iter(block1).collect::<Vec<_>>();
285             let block2_successors = cfg.succ_iter(block2).collect::<Vec<_>>();
286 
287             assert_eq!(block0_predecessors.len(), 0);
288             assert_eq!(block1_predecessors.len(), 2);
289             assert_eq!(block2_predecessors.len(), 2);
290 
291             assert_eq!(
292                 block1_predecessors
293                     .contains(&BlockPredecessor::new(block0, br_block0_block2_block1)),
294                 true
295             );
296             assert_eq!(
297                 block1_predecessors
298                     .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)),
299                 true
300             );
301             assert_eq!(
302                 block2_predecessors
303                     .contains(&BlockPredecessor::new(block0, br_block0_block2_block1)),
304                 true
305             );
306             assert_eq!(
307                 block2_predecessors
308                     .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)),
309                 true
310             );
311 
312             assert_eq!(block0_successors, [block1, block2]);
313             assert_eq!(block1_successors, [block1, block2]);
314             assert_eq!(block2_successors, []);
315         }
316 
317         // Add a new block to hold a return instruction
318         let ret_block = func.dfg.make_block();
319 
320         {
321             let mut cur = FuncCursor::new(&mut func);
322             cur.insert_block(ret_block);
323             cur.ins().return_(&[]);
324         }
325 
326         // Change some instructions and recompute block0 and ret_block
327         func.dfg
328             .replace(br_block0_block2_block1)
329             .brif(cond, block1, &[], ret_block, &[]);
330         cfg.recompute_block(&mut func, block0);
331         cfg.recompute_block(&mut func, ret_block);
332         let br_block0_block1_ret_block = br_block0_block2_block1;
333 
334         {
335             let block0_predecessors = cfg.pred_iter(block0).collect::<Vec<_>>();
336             let block1_predecessors = cfg.pred_iter(block1).collect::<Vec<_>>();
337             let block2_predecessors = cfg.pred_iter(block2).collect::<Vec<_>>();
338 
339             let block0_successors = cfg.succ_iter(block0);
340             let block1_successors = cfg.succ_iter(block1);
341             let block2_successors = cfg.succ_iter(block2);
342 
343             assert_eq!(block0_predecessors.len(), 0);
344             assert_eq!(block1_predecessors.len(), 2);
345             assert_eq!(block2_predecessors.len(), 1);
346 
347             assert_eq!(
348                 block1_predecessors
349                     .contains(&BlockPredecessor::new(block0, br_block0_block1_ret_block)),
350                 true
351             );
352             assert_eq!(
353                 block1_predecessors
354                     .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)),
355                 true
356             );
357             assert_eq!(
358                 block2_predecessors
359                     .contains(&BlockPredecessor::new(block0, br_block0_block1_ret_block)),
360                 false
361             );
362             assert_eq!(
363                 block2_predecessors
364                     .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)),
365                 true
366             );
367 
368             assert_eq!(block0_successors.collect::<Vec<_>>(), [block1, ret_block]);
369             assert_eq!(block1_successors.collect::<Vec<_>>(), [block1, block2]);
370             assert_eq!(block2_successors.collect::<Vec<_>>(), []);
371         }
372     }
373 }
374