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