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