11bb71d31Samartosch //! A Dominator Tree represented as mappings of Blocks to their immediate dominator. 21bb71d31Samartosch //! Computed using Keith D. Cooper's "Simple, Fast Dominator Algorithm." 31bb71d31Samartosch //! This version have been used in Cranelift for a very long time 41bb71d31Samartosch //! and should be quite stable. Used as a baseline i.e. in verification. 51bb71d31Samartosch 61bb71d31Samartosch use crate::entity::SecondaryMap; 71bb71d31Samartosch use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; 81bb71d31Samartosch use crate::ir::{Block, Function, Layout, ProgramPoint}; 91bb71d31Samartosch use crate::packed_option::PackedOption; 101bb71d31Samartosch use crate::timing; 111bb71d31Samartosch use crate::traversals::Dfs; 121bb71d31Samartosch use alloc::vec::Vec; 131bb71d31Samartosch use core::cmp::Ordering; 141bb71d31Samartosch 151bb71d31Samartosch /// RPO numbers are not first assigned in a contiguous way but as multiples of STRIDE, to leave 161bb71d31Samartosch /// room for modifications of the dominator tree. 171bb71d31Samartosch const STRIDE: u32 = 4; 181bb71d31Samartosch 191bb71d31Samartosch /// Dominator tree node. We keep one of these per block. 201bb71d31Samartosch #[derive(Clone, Default)] 211bb71d31Samartosch struct DomNode { 221bb71d31Samartosch /// Number of this node in a reverse post-order traversal of the CFG, starting from 1. 231bb71d31Samartosch /// This number is monotonic in the reverse postorder but not contiguous, since we leave 241bb71d31Samartosch /// holes for later localized modifications of the dominator tree. 251bb71d31Samartosch /// Unreachable nodes get number 0, all others are positive. 261bb71d31Samartosch rpo_number: u32, 271bb71d31Samartosch 281bb71d31Samartosch /// The immediate dominator of this block. 291bb71d31Samartosch /// 301bb71d31Samartosch /// This is `None` for unreachable blocks and the entry block which doesn't have an immediate 311bb71d31Samartosch /// dominator. 321bb71d31Samartosch idom: PackedOption<Block>, 331bb71d31Samartosch } 341bb71d31Samartosch 351bb71d31Samartosch /// The dominator tree for a single function. 361bb71d31Samartosch pub struct SimpleDominatorTree { 371bb71d31Samartosch nodes: SecondaryMap<Block, DomNode>, 381bb71d31Samartosch 391bb71d31Samartosch /// CFG post-order of all reachable blocks. 401bb71d31Samartosch postorder: Vec<Block>, 411bb71d31Samartosch 421bb71d31Samartosch /// Scratch traversal state used by `compute_postorder()`. 431bb71d31Samartosch dfs: Dfs, 441bb71d31Samartosch 451bb71d31Samartosch valid: bool, 461bb71d31Samartosch } 471bb71d31Samartosch 481bb71d31Samartosch /// Methods for querying the dominator tree. 491bb71d31Samartosch impl SimpleDominatorTree { 501bb71d31Samartosch /// Is `block` reachable from the entry block? is_reachable(&self, block: Block) -> bool511bb71d31Samartosch pub fn is_reachable(&self, block: Block) -> bool { 521bb71d31Samartosch self.nodes[block].rpo_number != 0 531bb71d31Samartosch } 541bb71d31Samartosch 551bb71d31Samartosch /// Get the CFG post-order of blocks that was used to compute the dominator tree. 561bb71d31Samartosch /// 571bb71d31Samartosch /// Note that this post-order is not updated automatically when the CFG is modified. It is 581bb71d31Samartosch /// computed from scratch and cached by `compute()`. cfg_postorder(&self) -> &[Block]591bb71d31Samartosch pub fn cfg_postorder(&self) -> &[Block] { 601bb71d31Samartosch debug_assert!(self.is_valid()); 611bb71d31Samartosch &self.postorder 621bb71d31Samartosch } 631bb71d31Samartosch 641bb71d31Samartosch /// Returns the immediate dominator of `block`. 651bb71d31Samartosch /// 661bb71d31Samartosch /// `block_a` is said to *dominate* `block_b` if all control flow paths from the function 671bb71d31Samartosch /// entry to `block_b` must go through `block_a`. 681bb71d31Samartosch /// 691bb71d31Samartosch /// The *immediate dominator* is the dominator that is closest to `block`. All other dominators 701bb71d31Samartosch /// also dominate the immediate dominator. 711bb71d31Samartosch /// 721bb71d31Samartosch /// This returns `None` if `block` is not reachable from the entry block, or if it is the entry block 731bb71d31Samartosch /// which has no dominators. idom(&self, block: Block) -> Option<Block>741bb71d31Samartosch pub fn idom(&self, block: Block) -> Option<Block> { 751bb71d31Samartosch self.nodes[block].idom.into() 761bb71d31Samartosch } 771bb71d31Samartosch 781bb71d31Samartosch /// Compare two blocks relative to the reverse post-order. rpo_cmp_block(&self, a: Block, b: Block) -> Ordering791bb71d31Samartosch pub fn rpo_cmp_block(&self, a: Block, b: Block) -> Ordering { 801bb71d31Samartosch self.nodes[a].rpo_number.cmp(&self.nodes[b].rpo_number) 811bb71d31Samartosch } 821bb71d31Samartosch 831bb71d31Samartosch /// Compare two program points relative to a reverse post-order traversal of the control-flow 841bb71d31Samartosch /// graph. 851bb71d31Samartosch /// 861bb71d31Samartosch /// Return `Ordering::Less` if `a` comes before `b` in the RPO. 871bb71d31Samartosch /// 881bb71d31Samartosch /// If `a` and `b` belong to the same block, compare their relative position in the block. rpo_cmp<A, B>(&self, a: A, b: B, layout: &Layout) -> Ordering where A: Into<ProgramPoint>, B: Into<ProgramPoint>,891bb71d31Samartosch pub fn rpo_cmp<A, B>(&self, a: A, b: B, layout: &Layout) -> Ordering 901bb71d31Samartosch where 911bb71d31Samartosch A: Into<ProgramPoint>, 921bb71d31Samartosch B: Into<ProgramPoint>, 931bb71d31Samartosch { 941bb71d31Samartosch let a = a.into(); 951bb71d31Samartosch let b = b.into(); 961bb71d31Samartosch self.rpo_cmp_block(layout.pp_block(a), layout.pp_block(b)) 971bb71d31Samartosch .then_with(|| layout.pp_cmp(a, b)) 981bb71d31Samartosch } 991bb71d31Samartosch 1001bb71d31Samartosch /// Returns `true` if `a` dominates `b`. 1011bb71d31Samartosch /// 1021bb71d31Samartosch /// This means that every control-flow path from the function entry to `b` must go through `a`. 1031bb71d31Samartosch /// 1041bb71d31Samartosch /// Dominance is ill defined for unreachable blocks. This function can always determine 1051bb71d31Samartosch /// dominance for instructions in the same block, but otherwise returns `false` if either block 1061bb71d31Samartosch /// is unreachable. 1071bb71d31Samartosch /// 1081bb71d31Samartosch /// An instruction is considered to dominate itself. 1091bb71d31Samartosch /// A block is also considered to dominate itself. dominates<A, B>(&self, a: A, b: B, layout: &Layout) -> bool where A: Into<ProgramPoint>, B: Into<ProgramPoint>,1101bb71d31Samartosch pub fn dominates<A, B>(&self, a: A, b: B, layout: &Layout) -> bool 1111bb71d31Samartosch where 1121bb71d31Samartosch A: Into<ProgramPoint>, 1131bb71d31Samartosch B: Into<ProgramPoint>, 1141bb71d31Samartosch { 1151bb71d31Samartosch let a = a.into(); 1161bb71d31Samartosch let b = b.into(); 1171bb71d31Samartosch match a { 1181bb71d31Samartosch ProgramPoint::Block(block_a) => match b { 1191bb71d31Samartosch ProgramPoint::Block(block_b) => self.block_dominates(block_a, block_b), 1201bb71d31Samartosch ProgramPoint::Inst(inst_b) => { 1211bb71d31Samartosch let block_b = layout 1221bb71d31Samartosch .inst_block(inst_b) 1231bb71d31Samartosch .expect("Instruction not in layout."); 1241bb71d31Samartosch self.block_dominates(block_a, block_b) 1251bb71d31Samartosch } 1261bb71d31Samartosch }, 1271bb71d31Samartosch ProgramPoint::Inst(inst_a) => { 1281bb71d31Samartosch let block_a: Block = layout 1291bb71d31Samartosch .inst_block(inst_a) 1301bb71d31Samartosch .expect("Instruction not in layout."); 1311bb71d31Samartosch match b { 1321bb71d31Samartosch ProgramPoint::Block(block_b) => { 1331bb71d31Samartosch block_a != block_b && self.block_dominates(block_a, block_b) 1341bb71d31Samartosch } 1351bb71d31Samartosch ProgramPoint::Inst(inst_b) => { 1361bb71d31Samartosch let block_b = layout 1371bb71d31Samartosch .inst_block(inst_b) 1381bb71d31Samartosch .expect("Instruction not in layout."); 1391bb71d31Samartosch if block_a == block_b { 1401bb71d31Samartosch layout.pp_cmp(a, b) != Ordering::Greater 1411bb71d31Samartosch } else { 1421bb71d31Samartosch self.block_dominates(block_a, block_b) 1431bb71d31Samartosch } 1441bb71d31Samartosch } 1451bb71d31Samartosch } 1461bb71d31Samartosch } 1471bb71d31Samartosch } 1481bb71d31Samartosch } 1491bb71d31Samartosch 1501bb71d31Samartosch /// Returns `true` if `block_a` dominates `block_b`. 1511bb71d31Samartosch /// 1521bb71d31Samartosch /// A block is considered to dominate itself. block_dominates(&self, block_a: Block, mut block_b: Block) -> bool1531bb71d31Samartosch fn block_dominates(&self, block_a: Block, mut block_b: Block) -> bool { 1541bb71d31Samartosch let rpo_a = self.nodes[block_a].rpo_number; 1551bb71d31Samartosch 1561bb71d31Samartosch // Run a finger up the dominator tree from b until we see a. 1571bb71d31Samartosch // Do nothing if b is unreachable. 1581bb71d31Samartosch while rpo_a < self.nodes[block_b].rpo_number { 1591bb71d31Samartosch let idom = match self.idom(block_b) { 1601bb71d31Samartosch Some(idom) => idom, 1611bb71d31Samartosch None => return false, // a is unreachable, so we climbed past the entry 1621bb71d31Samartosch }; 1631bb71d31Samartosch block_b = idom; 1641bb71d31Samartosch } 1651bb71d31Samartosch 1661bb71d31Samartosch block_a == block_b 1671bb71d31Samartosch } 1681bb71d31Samartosch 1691bb71d31Samartosch /// Compute the common dominator of two basic blocks. 1701bb71d31Samartosch /// 1711bb71d31Samartosch /// Both basic blocks are assumed to be reachable. common_dominator(&self, mut a: Block, mut b: Block) -> Block1721bb71d31Samartosch fn common_dominator(&self, mut a: Block, mut b: Block) -> Block { 1731bb71d31Samartosch loop { 1741bb71d31Samartosch match self.rpo_cmp_block(a, b) { 1751bb71d31Samartosch Ordering::Less => { 1761bb71d31Samartosch // `a` comes before `b` in the RPO. Move `b` up. 1771bb71d31Samartosch let idom = self.nodes[b].idom.expect("Unreachable basic block?"); 1781bb71d31Samartosch b = idom; 1791bb71d31Samartosch } 1801bb71d31Samartosch Ordering::Greater => { 1811bb71d31Samartosch // `b` comes before `a` in the RPO. Move `a` up. 1821bb71d31Samartosch let idom = self.nodes[a].idom.expect("Unreachable basic block?"); 1831bb71d31Samartosch a = idom; 1841bb71d31Samartosch } 1851bb71d31Samartosch Ordering::Equal => break, 1861bb71d31Samartosch } 1871bb71d31Samartosch } 1881bb71d31Samartosch 1891bb71d31Samartosch debug_assert_eq!(a, b, "Unreachable block passed to common_dominator?"); 1901bb71d31Samartosch 1911bb71d31Samartosch a 1921bb71d31Samartosch } 1931bb71d31Samartosch } 1941bb71d31Samartosch 1951bb71d31Samartosch impl SimpleDominatorTree { 1961bb71d31Samartosch /// Allocate a new blank dominator tree. Use `compute` to compute the dominator tree for a 1971bb71d31Samartosch /// function. new() -> Self1981bb71d31Samartosch pub fn new() -> Self { 1991bb71d31Samartosch Self { 2001bb71d31Samartosch nodes: SecondaryMap::new(), 2011bb71d31Samartosch postorder: Vec::new(), 2021bb71d31Samartosch dfs: Dfs::new(), 2031bb71d31Samartosch valid: false, 2041bb71d31Samartosch } 2051bb71d31Samartosch } 2061bb71d31Samartosch 2071bb71d31Samartosch /// Allocate and compute a dominator tree. with_function(func: &Function, cfg: &ControlFlowGraph) -> Self2081bb71d31Samartosch pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self { 2091bb71d31Samartosch let block_capacity = func.layout.block_capacity(); 2101bb71d31Samartosch let mut domtree = Self { 2111bb71d31Samartosch nodes: SecondaryMap::with_capacity(block_capacity), 2121bb71d31Samartosch postorder: Vec::with_capacity(block_capacity), 2131bb71d31Samartosch dfs: Dfs::new(), 2141bb71d31Samartosch valid: false, 2151bb71d31Samartosch }; 2161bb71d31Samartosch domtree.compute(func, cfg); 2171bb71d31Samartosch domtree 2181bb71d31Samartosch } 2191bb71d31Samartosch 2201bb71d31Samartosch /// Reset and compute a CFG post-order and dominator tree. compute(&mut self, func: &Function, cfg: &ControlFlowGraph)2211bb71d31Samartosch pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) { 2221bb71d31Samartosch let _tt = timing::domtree(); 2231bb71d31Samartosch debug_assert!(cfg.is_valid()); 2241bb71d31Samartosch self.compute_postorder(func); 2251bb71d31Samartosch self.compute_domtree(func, cfg); 2261bb71d31Samartosch self.valid = true; 2271bb71d31Samartosch } 2281bb71d31Samartosch 2291bb71d31Samartosch /// Clear the data structures used to represent the dominator tree. This will leave the tree in 2301bb71d31Samartosch /// a state where `is_valid()` returns false. clear(&mut self)2311bb71d31Samartosch pub fn clear(&mut self) { 2321bb71d31Samartosch self.nodes.clear(); 2331bb71d31Samartosch self.postorder.clear(); 2341bb71d31Samartosch self.valid = false; 2351bb71d31Samartosch } 2361bb71d31Samartosch 2371bb71d31Samartosch /// Check if the dominator tree is in a valid state. 2381bb71d31Samartosch /// 2391bb71d31Samartosch /// Note that this doesn't perform any kind of validity checks. It simply checks if the 2401bb71d31Samartosch /// `compute()` method has been called since the last `clear()`. It does not check that the 2411bb71d31Samartosch /// dominator tree is consistent with the CFG. is_valid(&self) -> bool2421bb71d31Samartosch pub fn is_valid(&self) -> bool { 2431bb71d31Samartosch self.valid 2441bb71d31Samartosch } 2451bb71d31Samartosch 2461bb71d31Samartosch /// Reset all internal data structures and compute a post-order of the control flow graph. 2471bb71d31Samartosch /// 2481bb71d31Samartosch /// This leaves `rpo_number == 1` for all reachable blocks, 0 for unreachable ones. compute_postorder(&mut self, func: &Function)2491bb71d31Samartosch fn compute_postorder(&mut self, func: &Function) { 2501bb71d31Samartosch self.clear(); 2511bb71d31Samartosch self.nodes.resize(func.dfg.num_blocks()); 2521bb71d31Samartosch self.postorder.extend(self.dfs.post_order_iter(func)); 2531bb71d31Samartosch } 2541bb71d31Samartosch 2551bb71d31Samartosch /// Build a dominator tree from a control flow graph using Keith D. Cooper's 2561bb71d31Samartosch /// "Simple, Fast Dominator Algorithm." compute_domtree(&mut self, func: &Function, cfg: &ControlFlowGraph)2571bb71d31Samartosch fn compute_domtree(&mut self, func: &Function, cfg: &ControlFlowGraph) { 2581bb71d31Samartosch // During this algorithm, `rpo_number` has the following values: 2591bb71d31Samartosch // 2601bb71d31Samartosch // 0: block is not reachable. 2611bb71d31Samartosch // 1: block is reachable, but has not yet been visited during the first pass. This is set by 2621bb71d31Samartosch // `compute_postorder`. 2631bb71d31Samartosch // 2+: block is reachable and has an assigned RPO number. 2641bb71d31Samartosch 2651bb71d31Samartosch // We'll be iterating over a reverse post-order of the CFG, skipping the entry block. 2661bb71d31Samartosch let (entry_block, postorder) = match self.postorder.as_slice().split_last() { 2671bb71d31Samartosch Some((&eb, rest)) => (eb, rest), 2681bb71d31Samartosch None => return, 2691bb71d31Samartosch }; 2701bb71d31Samartosch debug_assert_eq!(Some(entry_block), func.layout.entry_block()); 2711bb71d31Samartosch 2721bb71d31Samartosch // Do a first pass where we assign RPO numbers to all reachable nodes. 2731bb71d31Samartosch self.nodes[entry_block].rpo_number = 2 * STRIDE; 2741bb71d31Samartosch for (rpo_idx, &block) in postorder.iter().rev().enumerate() { 2751bb71d31Samartosch // Update the current node and give it an RPO number. 2761bb71d31Samartosch // The entry block got 2, the rest start at 3 by multiples of STRIDE to leave 2771bb71d31Samartosch // room for future dominator tree modifications. 2781bb71d31Samartosch // 2791bb71d31Samartosch // Since `compute_idom` will only look at nodes with an assigned RPO number, the 2801bb71d31Samartosch // function will never see an uninitialized predecessor. 2811bb71d31Samartosch // 2821bb71d31Samartosch // Due to the nature of the post-order traversal, every node we visit will have at 2831bb71d31Samartosch // least one predecessor that has previously been visited during this RPO. 2841bb71d31Samartosch self.nodes[block] = DomNode { 2851bb71d31Samartosch idom: self.compute_idom(block, cfg).into(), 2861bb71d31Samartosch rpo_number: (rpo_idx as u32 + 3) * STRIDE, 2871bb71d31Samartosch } 2881bb71d31Samartosch } 2891bb71d31Samartosch 2901bb71d31Samartosch // Now that we have RPO numbers for everything and initial immediate dominator estimates, 2911bb71d31Samartosch // iterate until convergence. 2921bb71d31Samartosch // 2931bb71d31Samartosch // If the function is free of irreducible control flow, this will exit after one iteration. 2941bb71d31Samartosch let mut changed = true; 2951bb71d31Samartosch while changed { 2961bb71d31Samartosch changed = false; 2971bb71d31Samartosch for &block in postorder.iter().rev() { 2981bb71d31Samartosch let idom = self.compute_idom(block, cfg).into(); 2991bb71d31Samartosch if self.nodes[block].idom != idom { 3001bb71d31Samartosch self.nodes[block].idom = idom; 3011bb71d31Samartosch changed = true; 3021bb71d31Samartosch } 3031bb71d31Samartosch } 3041bb71d31Samartosch } 3051bb71d31Samartosch } 3061bb71d31Samartosch 3071bb71d31Samartosch // Compute the immediate dominator for `block` using the current `idom` states for the reachable 3081bb71d31Samartosch // nodes. compute_idom(&self, block: Block, cfg: &ControlFlowGraph) -> Block3091bb71d31Samartosch fn compute_idom(&self, block: Block, cfg: &ControlFlowGraph) -> Block { 3101bb71d31Samartosch // Get an iterator with just the reachable, already visited predecessors to `block`. 3111bb71d31Samartosch // Note that during the first pass, `rpo_number` is 1 for reachable blocks that haven't 3121bb71d31Samartosch // been visited yet, 0 for unreachable blocks. 3131bb71d31Samartosch let mut reachable_preds = cfg 3141bb71d31Samartosch .pred_iter(block) 3151bb71d31Samartosch .filter(|&BlockPredecessor { block: pred, .. }| self.nodes[pred].rpo_number > 1) 3161bb71d31Samartosch .map(|pred| pred.block); 3171bb71d31Samartosch 3181bb71d31Samartosch // The RPO must visit at least one predecessor before this node. 3191bb71d31Samartosch let mut idom = reachable_preds 3201bb71d31Samartosch .next() 3211bb71d31Samartosch .expect("block node must have one reachable predecessor"); 3221bb71d31Samartosch 3231bb71d31Samartosch for pred in reachable_preds { 3241bb71d31Samartosch idom = self.common_dominator(idom, pred); 3251bb71d31Samartosch } 3261bb71d31Samartosch 3271bb71d31Samartosch idom 3281bb71d31Samartosch } 3291bb71d31Samartosch } 3301bb71d31Samartosch 3311bb71d31Samartosch #[cfg(test)] 3321bb71d31Samartosch mod tests { 3331bb71d31Samartosch use super::*; 3341bb71d31Samartosch use crate::cursor::{Cursor, FuncCursor}; 3351bb71d31Samartosch use crate::ir::types::*; 3361bb71d31Samartosch use crate::ir::{InstBuilder, TrapCode}; 3371bb71d31Samartosch 3381bb71d31Samartosch #[test] empty()3391bb71d31Samartosch fn empty() { 3401bb71d31Samartosch let func = Function::new(); 3411bb71d31Samartosch let cfg = ControlFlowGraph::with_function(&func); 3421bb71d31Samartosch debug_assert!(cfg.is_valid()); 3431bb71d31Samartosch let dtree = SimpleDominatorTree::with_function(&func, &cfg); 3441bb71d31Samartosch assert_eq!(0, dtree.nodes.keys().count()); 3451bb71d31Samartosch assert_eq!(dtree.cfg_postorder(), &[]); 3461bb71d31Samartosch } 3471bb71d31Samartosch 3481bb71d31Samartosch #[test] unreachable_node()3491bb71d31Samartosch fn unreachable_node() { 3501bb71d31Samartosch let mut func = Function::new(); 3511bb71d31Samartosch let block0 = func.dfg.make_block(); 3521bb71d31Samartosch let v0 = func.dfg.append_block_param(block0, I32); 3531bb71d31Samartosch let block1 = func.dfg.make_block(); 3541bb71d31Samartosch let block2 = func.dfg.make_block(); 3551bb71d31Samartosch let trap_block = func.dfg.make_block(); 3561bb71d31Samartosch 3571bb71d31Samartosch let mut cur = FuncCursor::new(&mut func); 3581bb71d31Samartosch 3591bb71d31Samartosch cur.insert_block(block0); 3601bb71d31Samartosch cur.ins().brif(v0, block2, &[], trap_block, &[]); 3611bb71d31Samartosch 3621bb71d31Samartosch cur.insert_block(trap_block); 3631bb71d31Samartosch cur.ins().trap(TrapCode::unwrap_user(1)); 3641bb71d31Samartosch 3651bb71d31Samartosch cur.insert_block(block1); 3661bb71d31Samartosch let v1 = cur.ins().iconst(I32, 1); 3671bb71d31Samartosch let v2 = cur.ins().iadd(v0, v1); 368*94ec88eaSChris Fallin cur.ins().jump(block0, &[v2.into()]); 3691bb71d31Samartosch 3701bb71d31Samartosch cur.insert_block(block2); 3711bb71d31Samartosch cur.ins().return_(&[v0]); 3721bb71d31Samartosch 3731bb71d31Samartosch let cfg = ControlFlowGraph::with_function(cur.func); 3741bb71d31Samartosch let dt = SimpleDominatorTree::with_function(cur.func, &cfg); 3751bb71d31Samartosch 3761bb71d31Samartosch // Fall-through-first, prune-at-source DFT: 3771bb71d31Samartosch // 3781bb71d31Samartosch // block0 { 3791bb71d31Samartosch // brif block2 { 3801bb71d31Samartosch // trap 3811bb71d31Samartosch // block2 { 3821bb71d31Samartosch // return 3831bb71d31Samartosch // } block2 3841bb71d31Samartosch // } block0 3851bb71d31Samartosch assert_eq!(dt.cfg_postorder(), &[block2, trap_block, block0]); 3861bb71d31Samartosch 3871bb71d31Samartosch let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); 3881bb71d31Samartosch assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); 3891bb71d31Samartosch assert!(!dt.dominates(block0, v2_def, &cur.func.layout)); 3901bb71d31Samartosch 3911bb71d31Samartosch assert!(dt.dominates(block0, block0, &cur.func.layout)); 3921bb71d31Samartosch assert!(!dt.dominates(block0, block1, &cur.func.layout)); 3931bb71d31Samartosch assert!(dt.dominates(block0, block2, &cur.func.layout)); 3941bb71d31Samartosch assert!(!dt.dominates(block1, block0, &cur.func.layout)); 3951bb71d31Samartosch assert!(dt.dominates(block1, block1, &cur.func.layout)); 3961bb71d31Samartosch assert!(!dt.dominates(block1, block2, &cur.func.layout)); 3971bb71d31Samartosch assert!(!dt.dominates(block2, block0, &cur.func.layout)); 3981bb71d31Samartosch assert!(!dt.dominates(block2, block1, &cur.func.layout)); 3991bb71d31Samartosch assert!(dt.dominates(block2, block2, &cur.func.layout)); 4001bb71d31Samartosch } 4011bb71d31Samartosch 4021bb71d31Samartosch #[test] non_zero_entry_block()4031bb71d31Samartosch fn non_zero_entry_block() { 4041bb71d31Samartosch let mut func = Function::new(); 4051bb71d31Samartosch let block0 = func.dfg.make_block(); 4061bb71d31Samartosch let block1 = func.dfg.make_block(); 4071bb71d31Samartosch let block2 = func.dfg.make_block(); 4081bb71d31Samartosch let block3 = func.dfg.make_block(); 4091bb71d31Samartosch let cond = func.dfg.append_block_param(block3, I32); 4101bb71d31Samartosch 4111bb71d31Samartosch let mut cur = FuncCursor::new(&mut func); 4121bb71d31Samartosch 4131bb71d31Samartosch cur.insert_block(block3); 4141bb71d31Samartosch let jmp_block3_block1 = cur.ins().jump(block1, &[]); 4151bb71d31Samartosch 4161bb71d31Samartosch cur.insert_block(block1); 4171bb71d31Samartosch let br_block1_block0_block2 = cur.ins().brif(cond, block0, &[], block2, &[]); 4181bb71d31Samartosch 4191bb71d31Samartosch cur.insert_block(block2); 4201bb71d31Samartosch cur.ins().jump(block0, &[]); 4211bb71d31Samartosch 4221bb71d31Samartosch cur.insert_block(block0); 4231bb71d31Samartosch 4241bb71d31Samartosch let cfg = ControlFlowGraph::with_function(cur.func); 4251bb71d31Samartosch let dt = SimpleDominatorTree::with_function(cur.func, &cfg); 4261bb71d31Samartosch 4271bb71d31Samartosch // Fall-through-first, prune-at-source DFT: 4281bb71d31Samartosch // 4291bb71d31Samartosch // block3 { 4301bb71d31Samartosch // block3:jump block1 { 4311bb71d31Samartosch // block1 { 4321bb71d31Samartosch // block1:brif block0 { 4331bb71d31Samartosch // block1:jump block2 { 4341bb71d31Samartosch // block2 { 4351bb71d31Samartosch // block2:jump block0 (seen) 4361bb71d31Samartosch // } block2 4371bb71d31Samartosch // } block1:jump block2 4381bb71d31Samartosch // block0 { 4391bb71d31Samartosch // } block0 4401bb71d31Samartosch // } block1:brif block0 4411bb71d31Samartosch // } block1 4421bb71d31Samartosch // } block3:jump block1 4431bb71d31Samartosch // } block3 4441bb71d31Samartosch 4451bb71d31Samartosch assert_eq!(dt.cfg_postorder(), &[block0, block2, block1, block3]); 4461bb71d31Samartosch 4471bb71d31Samartosch assert_eq!(cur.func.layout.entry_block().unwrap(), block3); 4481bb71d31Samartosch assert_eq!(dt.idom(block3), None); 4491bb71d31Samartosch assert_eq!(dt.idom(block1).unwrap(), block3); 4501bb71d31Samartosch assert_eq!(dt.idom(block2).unwrap(), block1); 4511bb71d31Samartosch assert_eq!(dt.idom(block0).unwrap(), block1); 4521bb71d31Samartosch 4531bb71d31Samartosch assert!(dt.dominates( 4541bb71d31Samartosch br_block1_block0_block2, 4551bb71d31Samartosch br_block1_block0_block2, 4561bb71d31Samartosch &cur.func.layout 4571bb71d31Samartosch )); 4581bb71d31Samartosch assert!(!dt.dominates(br_block1_block0_block2, jmp_block3_block1, &cur.func.layout)); 4591bb71d31Samartosch assert!(dt.dominates(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout)); 4601bb71d31Samartosch 4611bb71d31Samartosch assert_eq!( 4621bb71d31Samartosch dt.rpo_cmp(block3, block3, &cur.func.layout), 4631bb71d31Samartosch Ordering::Equal 4641bb71d31Samartosch ); 4651bb71d31Samartosch assert_eq!(dt.rpo_cmp(block3, block1, &cur.func.layout), Ordering::Less); 4661bb71d31Samartosch assert_eq!( 4671bb71d31Samartosch dt.rpo_cmp(block3, jmp_block3_block1, &cur.func.layout), 4681bb71d31Samartosch Ordering::Less 4691bb71d31Samartosch ); 4701bb71d31Samartosch assert_eq!( 4711bb71d31Samartosch dt.rpo_cmp(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout), 4721bb71d31Samartosch Ordering::Less 4731bb71d31Samartosch ); 4741bb71d31Samartosch } 4751bb71d31Samartosch 4761bb71d31Samartosch #[test] backwards_layout()4771bb71d31Samartosch fn backwards_layout() { 4781bb71d31Samartosch let mut func = Function::new(); 4791bb71d31Samartosch let block0 = func.dfg.make_block(); 4801bb71d31Samartosch let block1 = func.dfg.make_block(); 4811bb71d31Samartosch let block2 = func.dfg.make_block(); 4821bb71d31Samartosch 4831bb71d31Samartosch let mut cur = FuncCursor::new(&mut func); 4841bb71d31Samartosch 4851bb71d31Samartosch cur.insert_block(block0); 4861bb71d31Samartosch let jmp02 = cur.ins().jump(block2, &[]); 4871bb71d31Samartosch 4881bb71d31Samartosch cur.insert_block(block1); 4891bb71d31Samartosch let trap = cur.ins().trap(TrapCode::unwrap_user(5)); 4901bb71d31Samartosch 4911bb71d31Samartosch cur.insert_block(block2); 4921bb71d31Samartosch let jmp21 = cur.ins().jump(block1, &[]); 4931bb71d31Samartosch 4941bb71d31Samartosch let cfg = ControlFlowGraph::with_function(cur.func); 4951bb71d31Samartosch let dt = SimpleDominatorTree::with_function(cur.func, &cfg); 4961bb71d31Samartosch 4971bb71d31Samartosch assert_eq!(cur.func.layout.entry_block(), Some(block0)); 4981bb71d31Samartosch assert_eq!(dt.idom(block0), None); 4991bb71d31Samartosch assert_eq!(dt.idom(block1), Some(block2)); 5001bb71d31Samartosch assert_eq!(dt.idom(block2), Some(block0)); 5011bb71d31Samartosch 5021bb71d31Samartosch assert!(dt.dominates(block0, block0, &cur.func.layout)); 5031bb71d31Samartosch assert!(dt.dominates(block0, jmp02, &cur.func.layout)); 5041bb71d31Samartosch assert!(dt.dominates(block0, block1, &cur.func.layout)); 5051bb71d31Samartosch assert!(dt.dominates(block0, trap, &cur.func.layout)); 5061bb71d31Samartosch assert!(dt.dominates(block0, block2, &cur.func.layout)); 5071bb71d31Samartosch assert!(dt.dominates(block0, jmp21, &cur.func.layout)); 5081bb71d31Samartosch 5091bb71d31Samartosch assert!(!dt.dominates(jmp02, block0, &cur.func.layout)); 5101bb71d31Samartosch assert!(dt.dominates(jmp02, jmp02, &cur.func.layout)); 5111bb71d31Samartosch assert!(dt.dominates(jmp02, block1, &cur.func.layout)); 5121bb71d31Samartosch assert!(dt.dominates(jmp02, trap, &cur.func.layout)); 5131bb71d31Samartosch assert!(dt.dominates(jmp02, block2, &cur.func.layout)); 5141bb71d31Samartosch assert!(dt.dominates(jmp02, jmp21, &cur.func.layout)); 5151bb71d31Samartosch 5161bb71d31Samartosch assert!(!dt.dominates(block1, block0, &cur.func.layout)); 5171bb71d31Samartosch assert!(!dt.dominates(block1, jmp02, &cur.func.layout)); 5181bb71d31Samartosch assert!(dt.dominates(block1, block1, &cur.func.layout)); 5191bb71d31Samartosch assert!(dt.dominates(block1, trap, &cur.func.layout)); 5201bb71d31Samartosch assert!(!dt.dominates(block1, block2, &cur.func.layout)); 5211bb71d31Samartosch assert!(!dt.dominates(block1, jmp21, &cur.func.layout)); 5221bb71d31Samartosch 5231bb71d31Samartosch assert!(!dt.dominates(trap, block0, &cur.func.layout)); 5241bb71d31Samartosch assert!(!dt.dominates(trap, jmp02, &cur.func.layout)); 5251bb71d31Samartosch assert!(!dt.dominates(trap, block1, &cur.func.layout)); 5261bb71d31Samartosch assert!(dt.dominates(trap, trap, &cur.func.layout)); 5271bb71d31Samartosch assert!(!dt.dominates(trap, block2, &cur.func.layout)); 5281bb71d31Samartosch assert!(!dt.dominates(trap, jmp21, &cur.func.layout)); 5291bb71d31Samartosch 5301bb71d31Samartosch assert!(!dt.dominates(block2, block0, &cur.func.layout)); 5311bb71d31Samartosch assert!(!dt.dominates(block2, jmp02, &cur.func.layout)); 5321bb71d31Samartosch assert!(dt.dominates(block2, block1, &cur.func.layout)); 5331bb71d31Samartosch assert!(dt.dominates(block2, trap, &cur.func.layout)); 5341bb71d31Samartosch assert!(dt.dominates(block2, block2, &cur.func.layout)); 5351bb71d31Samartosch assert!(dt.dominates(block2, jmp21, &cur.func.layout)); 5361bb71d31Samartosch 5371bb71d31Samartosch assert!(!dt.dominates(jmp21, block0, &cur.func.layout)); 5381bb71d31Samartosch assert!(!dt.dominates(jmp21, jmp02, &cur.func.layout)); 5391bb71d31Samartosch assert!(dt.dominates(jmp21, block1, &cur.func.layout)); 5401bb71d31Samartosch assert!(dt.dominates(jmp21, trap, &cur.func.layout)); 5411bb71d31Samartosch assert!(!dt.dominates(jmp21, block2, &cur.func.layout)); 5421bb71d31Samartosch assert!(dt.dominates(jmp21, jmp21, &cur.func.layout)); 5431bb71d31Samartosch } 5441bb71d31Samartosch 5451bb71d31Samartosch #[test] insts_same_block()5461bb71d31Samartosch fn insts_same_block() { 5471bb71d31Samartosch let mut func = Function::new(); 5481bb71d31Samartosch let block0 = func.dfg.make_block(); 5491bb71d31Samartosch 5501bb71d31Samartosch let mut cur = FuncCursor::new(&mut func); 5511bb71d31Samartosch 5521bb71d31Samartosch cur.insert_block(block0); 5531bb71d31Samartosch let v1 = cur.ins().iconst(I32, 1); 5541bb71d31Samartosch let v2 = cur.ins().iadd(v1, v1); 5551bb71d31Samartosch let v3 = cur.ins().iadd(v2, v2); 5561bb71d31Samartosch cur.ins().return_(&[]); 5571bb71d31Samartosch 5581bb71d31Samartosch let cfg = ControlFlowGraph::with_function(cur.func); 5591bb71d31Samartosch let dt = SimpleDominatorTree::with_function(cur.func, &cfg); 5601bb71d31Samartosch 5611bb71d31Samartosch let v1_def = cur.func.dfg.value_def(v1).unwrap_inst(); 5621bb71d31Samartosch let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); 5631bb71d31Samartosch let v3_def = cur.func.dfg.value_def(v3).unwrap_inst(); 5641bb71d31Samartosch 5651bb71d31Samartosch assert!(dt.dominates(v1_def, v2_def, &cur.func.layout)); 5661bb71d31Samartosch assert!(dt.dominates(v2_def, v3_def, &cur.func.layout)); 5671bb71d31Samartosch assert!(dt.dominates(v1_def, v3_def, &cur.func.layout)); 5681bb71d31Samartosch 5691bb71d31Samartosch assert!(!dt.dominates(v2_def, v1_def, &cur.func.layout)); 5701bb71d31Samartosch assert!(!dt.dominates(v3_def, v2_def, &cur.func.layout)); 5711bb71d31Samartosch assert!(!dt.dominates(v3_def, v1_def, &cur.func.layout)); 5721bb71d31Samartosch 5731bb71d31Samartosch assert!(dt.dominates(v2_def, v2_def, &cur.func.layout)); 5741bb71d31Samartosch assert!(dt.dominates(block0, block0, &cur.func.layout)); 5751bb71d31Samartosch 5761bb71d31Samartosch assert!(dt.dominates(block0, v1_def, &cur.func.layout)); 5771bb71d31Samartosch assert!(dt.dominates(block0, v2_def, &cur.func.layout)); 5781bb71d31Samartosch assert!(dt.dominates(block0, v3_def, &cur.func.layout)); 5791bb71d31Samartosch 5801bb71d31Samartosch assert!(!dt.dominates(v1_def, block0, &cur.func.layout)); 5811bb71d31Samartosch assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); 5821bb71d31Samartosch assert!(!dt.dominates(v3_def, block0, &cur.func.layout)); 5831bb71d31Samartosch } 5841bb71d31Samartosch } 585