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