1832666c4SRyan Hunt //! A control flow graph represented as mappings of basic blocks to their predecessors 2747ad3c4Slazypassion //! and successors. 3747ad3c4Slazypassion //! 4832666c4SRyan Hunt //! Successors are represented as basic blocks while predecessors are represented by basic 5832666c4SRyan Hunt //! blocks. Basic blocks are denoted by tuples of block and branch/jump instructions. Each 6747ad3c4Slazypassion //! predecessor tuple corresponds to the end of a basic block. 7747ad3c4Slazypassion //! 8747ad3c4Slazypassion //! ```c 9832666c4SRyan Hunt //! Block0: 10747ad3c4Slazypassion //! ... ; beginning of basic block 11747ad3c4Slazypassion //! 12747ad3c4Slazypassion //! ... 13747ad3c4Slazypassion //! 14a5698cedSTrevor Elliott //! brif vx, Block1, Block2 ; end of basic block 15747ad3c4Slazypassion //! 16a5698cedSTrevor Elliott //! Block1: 17a5698cedSTrevor Elliott //! jump block3 18747ad3c4Slazypassion //! ``` 19747ad3c4Slazypassion //! 20a5698cedSTrevor Elliott //! Here `Block1` and `Block2` would each have a single predecessor denoted as `(Block0, brif)`, 21a5698cedSTrevor Elliott //! while `Block3` would have a single predecessor denoted as `(Block1, jump block3)`. 22747ad3c4Slazypassion 23747ad3c4Slazypassion use crate::bforest; 24747ad3c4Slazypassion use crate::entity::SecondaryMap; 2534ec4b4eSTrevor Elliott use crate::inst_predicates; 2634ec4b4eSTrevor Elliott use crate::ir::{Block, Function, Inst}; 27747ad3c4Slazypassion use crate::timing; 28747ad3c4Slazypassion use core::mem; 29747ad3c4Slazypassion 30832666c4SRyan Hunt /// A basic block denoted by its enclosing Block and last instruction. 31c7b4b98cSSean Stangl #[derive(Debug, PartialEq, Eq)] 32832666c4SRyan Hunt pub struct BlockPredecessor { 33832666c4SRyan Hunt /// Enclosing Block key. 34832666c4SRyan Hunt pub block: Block, 35747ad3c4Slazypassion /// Last instruction in the basic block. 36747ad3c4Slazypassion pub inst: Inst, 37747ad3c4Slazypassion } 38747ad3c4Slazypassion 39832666c4SRyan Hunt impl BlockPredecessor { 40832666c4SRyan Hunt /// Convenient method to construct new BlockPredecessor. new(block: Block, inst: Inst) -> Self41832666c4SRyan Hunt pub fn new(block: Block, inst: Inst) -> Self { 42832666c4SRyan Hunt Self { block, inst } 43747ad3c4Slazypassion } 44747ad3c4Slazypassion } 45747ad3c4Slazypassion 46832666c4SRyan Hunt /// A container for the successors and predecessors of some Block. 47747ad3c4Slazypassion #[derive(Clone, Default)] 48747ad3c4Slazypassion struct CFGNode { 49832666c4SRyan Hunt /// Instructions that can branch or jump to this block. 50747ad3c4Slazypassion /// 51832666c4SRyan Hunt /// This maps branch instruction -> predecessor block which is redundant since the block containing 52832666c4SRyan Hunt /// the branch instruction is available from the `layout.inst_block()` method. We store the 53747ad3c4Slazypassion /// redundant information because: 54747ad3c4Slazypassion /// 55832666c4SRyan Hunt /// 1. Many `pred_iter()` consumers want the block anyway, so it is handily available. 56832666c4SRyan Hunt /// 2. The `invalidate_block_successors()` may be called *after* branches have been removed from 57832666c4SRyan Hunt /// their block, but we still need to remove them form the old block predecessor map. 58747ad3c4Slazypassion /// 59832666c4SRyan Hunt /// The redundant block stored here is always consistent with the CFG successor lists, even after 60747ad3c4Slazypassion /// the IR has been edited. 61832666c4SRyan Hunt pub predecessors: bforest::Map<Inst, Block>, 62747ad3c4Slazypassion 63832666c4SRyan Hunt /// Set of blocks that are the targets of branches and jumps in this block. 64832666c4SRyan Hunt /// The set is ordered by block number, indicated by the `()` comparator type. 65832666c4SRyan Hunt pub successors: bforest::Set<Block>, 66747ad3c4Slazypassion } 67747ad3c4Slazypassion 68832666c4SRyan Hunt /// The Control Flow Graph maintains a mapping of blocks to their predecessors 69747ad3c4Slazypassion /// and successors where predecessors are basic blocks and successors are 70832666c4SRyan Hunt /// basic blocks. 71747ad3c4Slazypassion pub struct ControlFlowGraph { 72832666c4SRyan Hunt data: SecondaryMap<Block, CFGNode>, 73832666c4SRyan Hunt pred_forest: bforest::MapForest<Inst, Block>, 74832666c4SRyan Hunt succ_forest: bforest::SetForest<Block>, 75747ad3c4Slazypassion valid: bool, 76747ad3c4Slazypassion } 77747ad3c4Slazypassion 78747ad3c4Slazypassion impl ControlFlowGraph { 79747ad3c4Slazypassion /// Allocate a new blank control flow graph. new() -> Self80747ad3c4Slazypassion pub fn new() -> Self { 81747ad3c4Slazypassion Self { 82747ad3c4Slazypassion data: SecondaryMap::new(), 83747ad3c4Slazypassion valid: false, 84747ad3c4Slazypassion pred_forest: bforest::MapForest::new(), 85747ad3c4Slazypassion succ_forest: bforest::SetForest::new(), 86747ad3c4Slazypassion } 87747ad3c4Slazypassion } 88747ad3c4Slazypassion 89747ad3c4Slazypassion /// Clear all data structures in this control flow graph. clear(&mut self)90747ad3c4Slazypassion pub fn clear(&mut self) { 91747ad3c4Slazypassion self.data.clear(); 92747ad3c4Slazypassion self.pred_forest.clear(); 93747ad3c4Slazypassion self.succ_forest.clear(); 94747ad3c4Slazypassion self.valid = false; 95747ad3c4Slazypassion } 96747ad3c4Slazypassion 97747ad3c4Slazypassion /// Allocate and compute the control flow graph for `func`. with_function(func: &Function) -> Self98747ad3c4Slazypassion pub fn with_function(func: &Function) -> Self { 99747ad3c4Slazypassion let mut cfg = Self::new(); 100747ad3c4Slazypassion cfg.compute(func); 101747ad3c4Slazypassion cfg 102747ad3c4Slazypassion } 103747ad3c4Slazypassion 104747ad3c4Slazypassion /// Compute the control flow graph of `func`. 105747ad3c4Slazypassion /// 106747ad3c4Slazypassion /// This will clear and overwrite any information already stored in this data structure. compute(&mut self, func: &Function)107747ad3c4Slazypassion pub fn compute(&mut self, func: &Function) { 108747ad3c4Slazypassion let _tt = timing::flowgraph(); 109747ad3c4Slazypassion self.clear(); 110832666c4SRyan Hunt self.data.resize(func.dfg.num_blocks()); 111747ad3c4Slazypassion 112832666c4SRyan Hunt for block in &func.layout { 113832666c4SRyan Hunt self.compute_block(func, block); 114747ad3c4Slazypassion } 115747ad3c4Slazypassion 116747ad3c4Slazypassion self.valid = true; 117747ad3c4Slazypassion } 118747ad3c4Slazypassion compute_block(&mut self, func: &Function, block: Block)119832666c4SRyan Hunt fn compute_block(&mut self, func: &Function, block: Block) { 12034ec4b4eSTrevor Elliott inst_predicates::visit_block_succs(func, block, |inst, dest, _| { 12134ec4b4eSTrevor Elliott self.add_edge(block, inst, dest); 12234ec4b4eSTrevor Elliott }); 123747ad3c4Slazypassion } 124747ad3c4Slazypassion invalidate_block_successors(&mut self, block: Block)125832666c4SRyan Hunt fn invalidate_block_successors(&mut self, block: Block) { 126747ad3c4Slazypassion // Temporarily take ownership because we need mutable access to self.data inside the loop. 127747ad3c4Slazypassion // Unfortunately borrowck cannot see that our mut accesses to predecessors don't alias 128747ad3c4Slazypassion // our iteration over successors. 129832666c4SRyan Hunt let mut successors = mem::replace(&mut self.data[block].successors, Default::default()); 130747ad3c4Slazypassion for succ in successors.iter(&self.succ_forest) { 131747ad3c4Slazypassion self.data[succ] 132747ad3c4Slazypassion .predecessors 133832666c4SRyan Hunt .retain(&mut self.pred_forest, |_, &mut e| e != block); 134747ad3c4Slazypassion } 135747ad3c4Slazypassion successors.clear(&mut self.succ_forest); 136747ad3c4Slazypassion } 137747ad3c4Slazypassion 138832666c4SRyan Hunt /// Recompute the control flow graph of `block`. 139747ad3c4Slazypassion /// 140832666c4SRyan Hunt /// This is for use after modifying instructions within a specific block. It recomputes all edges 141832666c4SRyan Hunt /// from `block` while leaving edges to `block` intact. Its functionality a subset of that of the 142747ad3c4Slazypassion /// more expensive `compute`, and should be used when we know we don't need to recompute the CFG 143832666c4SRyan Hunt /// from scratch, but rather that our changes have been restricted to specific blocks. recompute_block(&mut self, func: &Function, block: Block)144832666c4SRyan Hunt pub fn recompute_block(&mut self, func: &Function, block: Block) { 145747ad3c4Slazypassion debug_assert!(self.is_valid()); 146832666c4SRyan Hunt self.invalidate_block_successors(block); 147832666c4SRyan Hunt self.compute_block(func, block); 148747ad3c4Slazypassion } 149747ad3c4Slazypassion add_edge(&mut self, from: Block, from_inst: Inst, to: Block)150832666c4SRyan Hunt fn add_edge(&mut self, from: Block, from_inst: Inst, to: Block) { 151747ad3c4Slazypassion self.data[from] 152747ad3c4Slazypassion .successors 153747ad3c4Slazypassion .insert(to, &mut self.succ_forest, &()); 154747ad3c4Slazypassion self.data[to] 155747ad3c4Slazypassion .predecessors 156747ad3c4Slazypassion .insert(from_inst, from, &mut self.pred_forest, &()); 157747ad3c4Slazypassion } 158747ad3c4Slazypassion 159832666c4SRyan Hunt /// Get an iterator over the CFG predecessors to `block`. pred_iter(&self, block: Block) -> PredIter<'_>160*8a42768fSAlex Crichton pub fn pred_iter(&self, block: Block) -> PredIter<'_> { 161832666c4SRyan Hunt PredIter(self.data[block].predecessors.iter(&self.pred_forest)) 162747ad3c4Slazypassion } 163747ad3c4Slazypassion 164832666c4SRyan Hunt /// Get an iterator over the CFG successors to `block`. succ_iter(&self, block: Block) -> SuccIter<'_>165*8a42768fSAlex Crichton pub fn succ_iter(&self, block: Block) -> SuccIter<'_> { 166747ad3c4Slazypassion debug_assert!(self.is_valid()); 167832666c4SRyan Hunt self.data[block].successors.iter(&self.succ_forest) 168747ad3c4Slazypassion } 169747ad3c4Slazypassion 170747ad3c4Slazypassion /// Check if the CFG is in a valid state. 171747ad3c4Slazypassion /// 172747ad3c4Slazypassion /// Note that this doesn't perform any kind of validity checks. It simply checks if the 173747ad3c4Slazypassion /// `compute()` method has been called since the last `clear()`. It does not check that the 174747ad3c4Slazypassion /// CFG is consistent with the function. is_valid(&self) -> bool175747ad3c4Slazypassion pub fn is_valid(&self) -> bool { 176747ad3c4Slazypassion self.valid 177747ad3c4Slazypassion } 178747ad3c4Slazypassion } 179747ad3c4Slazypassion 180832666c4SRyan Hunt /// An iterator over block predecessors. The iterator type is `BlockPredecessor`. 181747ad3c4Slazypassion /// 182832666c4SRyan Hunt /// Each predecessor is an instruction that branches to the block. 183832666c4SRyan Hunt pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Block>); 184747ad3c4Slazypassion 185747ad3c4Slazypassion impl<'a> Iterator for PredIter<'a> { 186832666c4SRyan Hunt type Item = BlockPredecessor; 187747ad3c4Slazypassion next(&mut self) -> Option<BlockPredecessor>188832666c4SRyan Hunt fn next(&mut self) -> Option<BlockPredecessor> { 189832666c4SRyan Hunt self.0.next().map(|(i, e)| BlockPredecessor::new(e, i)) 190747ad3c4Slazypassion } 191747ad3c4Slazypassion } 192747ad3c4Slazypassion 193832666c4SRyan Hunt /// An iterator over block successors. The iterator type is `Block`. 194832666c4SRyan Hunt pub type SuccIter<'a> = bforest::SetIter<'a, Block>; 195747ad3c4Slazypassion 196747ad3c4Slazypassion #[cfg(test)] 197747ad3c4Slazypassion mod tests { 198747ad3c4Slazypassion use super::*; 199747ad3c4Slazypassion use crate::cursor::{Cursor, FuncCursor}; 20090ac295eSAlex Crichton use crate::ir::{InstBuilder, types}; 20110e226f9Sbjorn3 use alloc::vec::Vec; 202747ad3c4Slazypassion 203747ad3c4Slazypassion #[test] empty()204747ad3c4Slazypassion fn empty() { 205747ad3c4Slazypassion let func = Function::new(); 206747ad3c4Slazypassion ControlFlowGraph::with_function(&func); 207747ad3c4Slazypassion } 208747ad3c4Slazypassion 209747ad3c4Slazypassion #[test] no_predecessors()210747ad3c4Slazypassion fn no_predecessors() { 211747ad3c4Slazypassion let mut func = Function::new(); 212832666c4SRyan Hunt let block0 = func.dfg.make_block(); 213832666c4SRyan Hunt let block1 = func.dfg.make_block(); 214832666c4SRyan Hunt let block2 = func.dfg.make_block(); 215832666c4SRyan Hunt func.layout.append_block(block0); 216832666c4SRyan Hunt func.layout.append_block(block1); 217832666c4SRyan Hunt func.layout.append_block(block2); 218747ad3c4Slazypassion 219747ad3c4Slazypassion let cfg = ControlFlowGraph::with_function(&func); 220747ad3c4Slazypassion 221832666c4SRyan Hunt let mut fun_blocks = func.layout.blocks(); 222832666c4SRyan Hunt for block in func.layout.blocks() { 223832666c4SRyan Hunt assert_eq!(block, fun_blocks.next().unwrap()); 224832666c4SRyan Hunt assert_eq!(cfg.pred_iter(block).count(), 0); 225832666c4SRyan Hunt assert_eq!(cfg.succ_iter(block).count(), 0); 226747ad3c4Slazypassion } 227747ad3c4Slazypassion } 228747ad3c4Slazypassion 229747ad3c4Slazypassion #[test] branches_and_jumps()230747ad3c4Slazypassion fn branches_and_jumps() { 231747ad3c4Slazypassion let mut func = Function::new(); 232832666c4SRyan Hunt let block0 = func.dfg.make_block(); 233832666c4SRyan Hunt let cond = func.dfg.append_block_param(block0, types::I32); 234832666c4SRyan Hunt let block1 = func.dfg.make_block(); 235832666c4SRyan Hunt let block2 = func.dfg.make_block(); 236747ad3c4Slazypassion 237a5698cedSTrevor Elliott let br_block0_block2_block1; 238a5698cedSTrevor Elliott let br_block1_block1_block2; 239747ad3c4Slazypassion 240747ad3c4Slazypassion { 241747ad3c4Slazypassion let mut cur = FuncCursor::new(&mut func); 242747ad3c4Slazypassion 243832666c4SRyan Hunt cur.insert_block(block0); 244a5698cedSTrevor Elliott br_block0_block2_block1 = cur.ins().brif(cond, block2, &[], block1, &[]); 245747ad3c4Slazypassion 246832666c4SRyan Hunt cur.insert_block(block1); 247a5698cedSTrevor Elliott br_block1_block1_block2 = cur.ins().brif(cond, block1, &[], block2, &[]); 248747ad3c4Slazypassion 249832666c4SRyan Hunt cur.insert_block(block2); 250747ad3c4Slazypassion } 251747ad3c4Slazypassion 252747ad3c4Slazypassion let mut cfg = ControlFlowGraph::with_function(&func); 253747ad3c4Slazypassion 254747ad3c4Slazypassion { 255832666c4SRyan Hunt let block0_predecessors = cfg.pred_iter(block0).collect::<Vec<_>>(); 256832666c4SRyan Hunt let block1_predecessors = cfg.pred_iter(block1).collect::<Vec<_>>(); 257832666c4SRyan Hunt let block2_predecessors = cfg.pred_iter(block2).collect::<Vec<_>>(); 258747ad3c4Slazypassion 259832666c4SRyan Hunt let block0_successors = cfg.succ_iter(block0).collect::<Vec<_>>(); 260832666c4SRyan Hunt let block1_successors = cfg.succ_iter(block1).collect::<Vec<_>>(); 261832666c4SRyan Hunt let block2_successors = cfg.succ_iter(block2).collect::<Vec<_>>(); 262747ad3c4Slazypassion 263832666c4SRyan Hunt assert_eq!(block0_predecessors.len(), 0); 264832666c4SRyan Hunt assert_eq!(block1_predecessors.len(), 2); 265832666c4SRyan Hunt assert_eq!(block2_predecessors.len(), 2); 266747ad3c4Slazypassion 267747ad3c4Slazypassion assert_eq!( 268a5698cedSTrevor Elliott block1_predecessors 269a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block0, br_block0_block2_block1)), 270747ad3c4Slazypassion true 271747ad3c4Slazypassion ); 272747ad3c4Slazypassion assert_eq!( 273a5698cedSTrevor Elliott block1_predecessors 274a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), 275747ad3c4Slazypassion true 276747ad3c4Slazypassion ); 277747ad3c4Slazypassion assert_eq!( 278a5698cedSTrevor Elliott block2_predecessors 279a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block0, br_block0_block2_block1)), 280747ad3c4Slazypassion true 281747ad3c4Slazypassion ); 282747ad3c4Slazypassion assert_eq!( 283a5698cedSTrevor Elliott block2_predecessors 284a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), 285747ad3c4Slazypassion true 286747ad3c4Slazypassion ); 287747ad3c4Slazypassion 288832666c4SRyan Hunt assert_eq!(block0_successors, [block1, block2]); 289832666c4SRyan Hunt assert_eq!(block1_successors, [block1, block2]); 290832666c4SRyan Hunt assert_eq!(block2_successors, []); 291747ad3c4Slazypassion } 292747ad3c4Slazypassion 293a5698cedSTrevor Elliott // Add a new block to hold a return instruction 294a5698cedSTrevor Elliott let ret_block = func.dfg.make_block(); 295a5698cedSTrevor Elliott 296a5698cedSTrevor Elliott { 297a5698cedSTrevor Elliott let mut cur = FuncCursor::new(&mut func); 298a5698cedSTrevor Elliott cur.insert_block(ret_block); 299a5698cedSTrevor Elliott cur.ins().return_(&[]); 300a5698cedSTrevor Elliott } 301a5698cedSTrevor Elliott 302a5698cedSTrevor Elliott // Change some instructions and recompute block0 and ret_block 303a5698cedSTrevor Elliott func.dfg 304a5698cedSTrevor Elliott .replace(br_block0_block2_block1) 305a5698cedSTrevor Elliott .brif(cond, block1, &[], ret_block, &[]); 3069bd2979eSAlex Crichton cfg.recompute_block(&func, block0); 3079bd2979eSAlex Crichton cfg.recompute_block(&func, ret_block); 308a5698cedSTrevor Elliott let br_block0_block1_ret_block = br_block0_block2_block1; 309747ad3c4Slazypassion 310747ad3c4Slazypassion { 311832666c4SRyan Hunt let block0_predecessors = cfg.pred_iter(block0).collect::<Vec<_>>(); 312832666c4SRyan Hunt let block1_predecessors = cfg.pred_iter(block1).collect::<Vec<_>>(); 313832666c4SRyan Hunt let block2_predecessors = cfg.pred_iter(block2).collect::<Vec<_>>(); 314747ad3c4Slazypassion 315832666c4SRyan Hunt let block0_successors = cfg.succ_iter(block0); 316832666c4SRyan Hunt let block1_successors = cfg.succ_iter(block1); 317832666c4SRyan Hunt let block2_successors = cfg.succ_iter(block2); 318747ad3c4Slazypassion 319832666c4SRyan Hunt assert_eq!(block0_predecessors.len(), 0); 320832666c4SRyan Hunt assert_eq!(block1_predecessors.len(), 2); 321832666c4SRyan Hunt assert_eq!(block2_predecessors.len(), 1); 322747ad3c4Slazypassion 323747ad3c4Slazypassion assert_eq!( 324a5698cedSTrevor Elliott block1_predecessors 325a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block0, br_block0_block1_ret_block)), 326747ad3c4Slazypassion true 327747ad3c4Slazypassion ); 328747ad3c4Slazypassion assert_eq!( 329a5698cedSTrevor Elliott block1_predecessors 330a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), 331747ad3c4Slazypassion true 332747ad3c4Slazypassion ); 333747ad3c4Slazypassion assert_eq!( 334a5698cedSTrevor Elliott block2_predecessors 335a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block0, br_block0_block1_ret_block)), 336747ad3c4Slazypassion false 337747ad3c4Slazypassion ); 338747ad3c4Slazypassion assert_eq!( 339a5698cedSTrevor Elliott block2_predecessors 340a5698cedSTrevor Elliott .contains(&BlockPredecessor::new(block1, br_block1_block1_block2)), 341747ad3c4Slazypassion true 342747ad3c4Slazypassion ); 343747ad3c4Slazypassion 344a5698cedSTrevor Elliott assert_eq!(block0_successors.collect::<Vec<_>>(), [block1, ret_block]); 345832666c4SRyan Hunt assert_eq!(block1_successors.collect::<Vec<_>>(), [block1, block2]); 346832666c4SRyan Hunt assert_eq!(block2_successors.collect::<Vec<_>>(), []); 347747ad3c4Slazypassion } 348747ad3c4Slazypassion } 349747ad3c4Slazypassion } 350