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