1832666c4SRyan Hunt //! A Dominator Tree represented as mappings of Blocks to their immediate dominator. 2747ad3c4Slazypassion 3747ad3c4Slazypassion use crate::entity::SecondaryMap; 4832666c4SRyan Hunt use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; 53a14fa39SPaul Nodet use crate::ir::{Block, Function, Layout, ProgramPoint}; 6747ad3c4Slazypassion use crate::packed_option::PackedOption; 7747ad3c4Slazypassion use crate::timing; 8bb8fa40eSbjorn3 use alloc::vec::Vec; 9747ad3c4Slazypassion use core::cmp; 10747ad3c4Slazypassion use core::cmp::Ordering; 11747ad3c4Slazypassion use core::mem; 12747ad3c4Slazypassion 131bb71d31Samartosch mod simple; 141bb71d31Samartosch 151bb71d31Samartosch pub use simple::SimpleDominatorTree; 161bb71d31Samartosch 171bb71d31Samartosch /// Spanning tree node, used during domtree computation. 181bb71d31Samartosch #[derive(Clone, Default)] 191bb71d31Samartosch struct SpanningTreeNode { 201bb71d31Samartosch /// This node's block in function CFG. 211bb71d31Samartosch block: PackedOption<Block>, 221bb71d31Samartosch /// Node's ancestor in the spanning tree. 231bb71d31Samartosch /// Gets invalidated during semi-dominator computation. 241bb71d31Samartosch ancestor: u32, 251bb71d31Samartosch /// The smallest semi value discovered on any semi-dominator path 261bb71d31Samartosch /// that went through the node up till the moment. 271bb71d31Samartosch /// Gets updated in the course of semi-dominator computation. 281bb71d31Samartosch label: u32, 291bb71d31Samartosch /// Semidominator value for the node. 301bb71d31Samartosch semi: u32, 311bb71d31Samartosch /// Immediate dominator value for the node. 321bb71d31Samartosch /// Initialized to node's ancestor in the spanning tree. 331bb71d31Samartosch idom: u32, 341bb71d31Samartosch } 351bb71d31Samartosch 361bb71d31Samartosch /// DFS preorder number for unvisited nodes and the virtual root in the spanning tree. 371bb71d31Samartosch const NOT_VISITED: u32 = 0; 381bb71d31Samartosch 391bb71d31Samartosch /// Spanning tree, in CFG preorder. 401bb71d31Samartosch /// Node 0 is the virtual root and doesn't have a corresponding block. 411bb71d31Samartosch /// It's not required because function's CFG in Cranelift always have 421bb71d31Samartosch /// a singular root, but helps to avoid additional checks. 431bb71d31Samartosch /// Numbering nodes from 0 also follows the convention in 443a14fa39SPaul Nodet /// `SimpleDominatorTree`. 451bb71d31Samartosch #[derive(Clone, Default)] 461bb71d31Samartosch struct SpanningTree { 471bb71d31Samartosch nodes: Vec<SpanningTreeNode>, 481bb71d31Samartosch } 491bb71d31Samartosch 501bb71d31Samartosch impl SpanningTree { new() -> Self511bb71d31Samartosch fn new() -> Self { 521bb71d31Samartosch // Include the virtual root. 531bb71d31Samartosch Self { 541bb71d31Samartosch nodes: vec![Default::default()], 551bb71d31Samartosch } 561bb71d31Samartosch } 571bb71d31Samartosch with_capacity(capacity: usize) -> Self581bb71d31Samartosch fn with_capacity(capacity: usize) -> Self { 591bb71d31Samartosch // Include the virtual root. 601bb71d31Samartosch let mut nodes = Vec::with_capacity(capacity + 1); 611bb71d31Samartosch nodes.push(Default::default()); 621bb71d31Samartosch Self { nodes } 631bb71d31Samartosch } 641bb71d31Samartosch len(&self) -> usize651bb71d31Samartosch fn len(&self) -> usize { 661bb71d31Samartosch self.nodes.len() 671bb71d31Samartosch } 681bb71d31Samartosch reserve(&mut self, capacity: usize)691bb71d31Samartosch fn reserve(&mut self, capacity: usize) { 701bb71d31Samartosch // Virtual root should be already included. 711bb71d31Samartosch self.nodes.reserve(capacity); 721bb71d31Samartosch } 731bb71d31Samartosch clear(&mut self)741bb71d31Samartosch fn clear(&mut self) { 751bb71d31Samartosch self.nodes.resize(1, Default::default()); 761bb71d31Samartosch } 771bb71d31Samartosch 781bb71d31Samartosch /// Returns pre_number for the new node. push(&mut self, ancestor: u32, block: Block) -> u32791bb71d31Samartosch fn push(&mut self, ancestor: u32, block: Block) -> u32 { 801bb71d31Samartosch // Virtual root should be already included. 811bb71d31Samartosch debug_assert!(!self.nodes.is_empty()); 821bb71d31Samartosch 831bb71d31Samartosch let pre_number = self.nodes.len() as u32; 841bb71d31Samartosch 851bb71d31Samartosch self.nodes.push(SpanningTreeNode { 861bb71d31Samartosch block: block.into(), 878cc276b0SAlex Crichton ancestor, 881bb71d31Samartosch label: pre_number, 891bb71d31Samartosch semi: pre_number, 901bb71d31Samartosch idom: ancestor, 911bb71d31Samartosch }); 921bb71d31Samartosch 931bb71d31Samartosch pre_number 941bb71d31Samartosch } 951bb71d31Samartosch } 961bb71d31Samartosch 97*0889323aSSSD impl core::ops::Index<u32> for SpanningTree { 981bb71d31Samartosch type Output = SpanningTreeNode; 991bb71d31Samartosch index(&self, idx: u32) -> &Self::Output1001bb71d31Samartosch fn index(&self, idx: u32) -> &Self::Output { 1011bb71d31Samartosch &self.nodes[idx as usize] 1021bb71d31Samartosch } 1031bb71d31Samartosch } 1041bb71d31Samartosch 105*0889323aSSSD impl core::ops::IndexMut<u32> for SpanningTree { index_mut(&mut self, idx: u32) -> &mut Self::Output1061bb71d31Samartosch fn index_mut(&mut self, idx: u32) -> &mut Self::Output { 1071bb71d31Samartosch &mut self.nodes[idx as usize] 1081bb71d31Samartosch } 1091bb71d31Samartosch } 1101bb71d31Samartosch 1111bb71d31Samartosch /// Traversal event to compute both preorder spanning tree 1121bb71d31Samartosch /// and postorder block list. Can't use `Dfs` from traversals.rs 1131bb71d31Samartosch /// here because of the need for parent links. 1141bb71d31Samartosch enum TraversalEvent { 1151bb71d31Samartosch Enter(u32, Block), 1161bb71d31Samartosch Exit(Block), 1171bb71d31Samartosch } 118747ad3c4Slazypassion 119832666c4SRyan Hunt /// Dominator tree node. We keep one of these per block. 120747ad3c4Slazypassion #[derive(Clone, Default)] 1211bb71d31Samartosch struct DominatorTreeNode { 1221bb71d31Samartosch /// Immediate dominator for the block, `None` for unreachable blocks. 123a6c4f9a0Samartosch idom: PackedOption<Block>, 1241bb71d31Samartosch /// Preorder traversal number, zero for unreachable blocks. 1251bb71d31Samartosch pre_number: u32, 1263a14fa39SPaul Nodet 1273a14fa39SPaul Nodet /// First child node in the domtree. 1283a14fa39SPaul Nodet child: PackedOption<Block>, 1293a14fa39SPaul Nodet 1303a14fa39SPaul Nodet /// Next sibling node in the domtree. This linked list is ordered according to the CFG RPO. 1313a14fa39SPaul Nodet sibling: PackedOption<Block>, 1323a14fa39SPaul Nodet 1333a14fa39SPaul Nodet /// Sequence number for this node in a pre-order traversal of the dominator tree. 1343a14fa39SPaul Nodet /// Unreachable blocks have number 0, the entry block is 1. 1353a14fa39SPaul Nodet dom_pre_number: u32, 1363a14fa39SPaul Nodet 1373a14fa39SPaul Nodet /// Maximum `dom_pre_number` for the sub-tree of the dominator tree that is rooted at this node. 1383a14fa39SPaul Nodet /// This is always >= `dom_pre_number`. 1393a14fa39SPaul Nodet dom_pre_max: u32, 140747ad3c4Slazypassion } 141747ad3c4Slazypassion 1421bb71d31Samartosch /// The dominator tree for a single function, 1431bb71d31Samartosch /// computed using Semi-NCA algorithm. 144747ad3c4Slazypassion pub struct DominatorTree { 1451bb71d31Samartosch /// DFS spanning tree. 1461bb71d31Samartosch stree: SpanningTree, 1471bb71d31Samartosch /// List of CFG blocks in postorder. 148832666c4SRyan Hunt postorder: Vec<Block>, 1491bb71d31Samartosch /// Dominator tree nodes. 1501bb71d31Samartosch nodes: SecondaryMap<Block, DominatorTreeNode>, 151747ad3c4Slazypassion 1521bb71d31Samartosch /// Stack for building the spanning tree. 1531bb71d31Samartosch dfs_worklist: Vec<TraversalEvent>, 1541bb71d31Samartosch /// Stack used for processing semidominator paths 1551bb71d31Samartosch /// in link-eval procedure. 1561bb71d31Samartosch eval_worklist: Vec<u32>, 157747ad3c4Slazypassion 158747ad3c4Slazypassion valid: bool, 159747ad3c4Slazypassion } 160747ad3c4Slazypassion 161747ad3c4Slazypassion /// Methods for querying the dominator tree. 162747ad3c4Slazypassion impl DominatorTree { 163832666c4SRyan Hunt /// Is `block` reachable from the entry block? is_reachable(&self, block: Block) -> bool164832666c4SRyan Hunt pub fn is_reachable(&self, block: Block) -> bool { 1651bb71d31Samartosch self.nodes[block].pre_number != NOT_VISITED 166747ad3c4Slazypassion } 167747ad3c4Slazypassion 168832666c4SRyan Hunt /// Get the CFG post-order of blocks that was used to compute the dominator tree. 169747ad3c4Slazypassion /// 170747ad3c4Slazypassion /// Note that this post-order is not updated automatically when the CFG is modified. It is 171747ad3c4Slazypassion /// computed from scratch and cached by `compute()`. cfg_postorder(&self) -> &[Block]172832666c4SRyan Hunt pub fn cfg_postorder(&self) -> &[Block] { 173747ad3c4Slazypassion debug_assert!(self.is_valid()); 174747ad3c4Slazypassion &self.postorder 175747ad3c4Slazypassion } 176747ad3c4Slazypassion 1773e0b7e50SKirpal Grewal /// Get an iterator over CFG reverse post-order of blocks used to compute the dominator tree. 1783e0b7e50SKirpal Grewal /// 1793e0b7e50SKirpal Grewal /// Note that the post-order is not updated automatically when the CFG is modified. It is 1803e0b7e50SKirpal Grewal /// computed from scratch and cached by `compute()`. cfg_rpo(&self) -> impl Iterator<Item = &Block>1813e0b7e50SKirpal Grewal pub fn cfg_rpo(&self) -> impl Iterator<Item = &Block> { 1823e0b7e50SKirpal Grewal debug_assert!(self.is_valid()); 1833e0b7e50SKirpal Grewal self.postorder.iter().rev() 1843e0b7e50SKirpal Grewal } 1853e0b7e50SKirpal Grewal 186832666c4SRyan Hunt /// Returns the immediate dominator of `block`. 187747ad3c4Slazypassion /// 188a6c4f9a0Samartosch /// `block_a` is said to *dominate* `block_b` if all control flow paths from the function 189a6c4f9a0Samartosch /// entry to `block_b` must go through `block_a`. 190747ad3c4Slazypassion /// 191832666c4SRyan Hunt /// The *immediate dominator* is the dominator that is closest to `block`. All other dominators 192747ad3c4Slazypassion /// also dominate the immediate dominator. 193747ad3c4Slazypassion /// 194832666c4SRyan Hunt /// This returns `None` if `block` is not reachable from the entry block, or if it is the entry block 195747ad3c4Slazypassion /// which has no dominators. idom(&self, block: Block) -> Option<Block>196a6c4f9a0Samartosch pub fn idom(&self, block: Block) -> Option<Block> { 197832666c4SRyan Hunt self.nodes[block].idom.into() 198747ad3c4Slazypassion } 199747ad3c4Slazypassion 200747ad3c4Slazypassion /// Returns `true` if `a` dominates `b`. 201747ad3c4Slazypassion /// 202747ad3c4Slazypassion /// This means that every control-flow path from the function entry to `b` must go through `a`. 203747ad3c4Slazypassion /// 204747ad3c4Slazypassion /// Dominance is ill defined for unreachable blocks. This function can always determine 205832666c4SRyan Hunt /// dominance for instructions in the same block, but otherwise returns `false` if either block 206747ad3c4Slazypassion /// is unreachable. 207747ad3c4Slazypassion /// 208747ad3c4Slazypassion /// An instruction is considered to dominate itself. 209a6c4f9a0Samartosch /// 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>,210747ad3c4Slazypassion pub fn dominates<A, B>(&self, a: A, b: B, layout: &Layout) -> bool 211747ad3c4Slazypassion where 212a81c2068Sbjorn3 A: Into<ProgramPoint>, 213a81c2068Sbjorn3 B: Into<ProgramPoint>, 214747ad3c4Slazypassion { 215747ad3c4Slazypassion let a = a.into(); 216747ad3c4Slazypassion let b = b.into(); 217747ad3c4Slazypassion match a { 218a6c4f9a0Samartosch ProgramPoint::Block(block_a) => match b { 219a6c4f9a0Samartosch ProgramPoint::Block(block_b) => self.block_dominates(block_a, block_b), 220a6c4f9a0Samartosch ProgramPoint::Inst(inst_b) => { 221a6c4f9a0Samartosch let block_b = layout 222a6c4f9a0Samartosch .inst_block(inst_b) 223a6c4f9a0Samartosch .expect("Instruction not in layout."); 224a6c4f9a0Samartosch self.block_dominates(block_a, block_b) 225747ad3c4Slazypassion } 226a6c4f9a0Samartosch }, 227a81c2068Sbjorn3 ProgramPoint::Inst(inst_a) => { 228a6c4f9a0Samartosch let block_a: Block = layout 229832666c4SRyan Hunt .inst_block(inst_a) 230832666c4SRyan Hunt .expect("Instruction not in layout."); 231a6c4f9a0Samartosch match b { 232a6c4f9a0Samartosch ProgramPoint::Block(block_b) => { 233a6c4f9a0Samartosch block_a != block_b && self.block_dominates(block_a, block_b) 234a6c4f9a0Samartosch } 235a6c4f9a0Samartosch ProgramPoint::Inst(inst_b) => { 236a6c4f9a0Samartosch let block_b = layout 237a6c4f9a0Samartosch .inst_block(inst_b) 238a6c4f9a0Samartosch .expect("Instruction not in layout."); 239a6c4f9a0Samartosch if block_a == block_b { 240a6c4f9a0Samartosch layout.pp_cmp(a, b) != Ordering::Greater 241a6c4f9a0Samartosch } else { 242a6c4f9a0Samartosch self.block_dominates(block_a, block_b) 243a6c4f9a0Samartosch } 244a6c4f9a0Samartosch } 245747ad3c4Slazypassion } 246747ad3c4Slazypassion } 247747ad3c4Slazypassion } 248747ad3c4Slazypassion } 249747ad3c4Slazypassion 250a6c4f9a0Samartosch /// Returns `true` if `block_a` dominates `block_b`. 251a6c4f9a0Samartosch /// 252a6c4f9a0Samartosch /// A block is considered to dominate itself. 2533a14fa39SPaul Nodet /// This uses preorder numbers for O(1) constant time performance. block_dominates(&self, block_a: Block, block_b: Block) -> bool2543a14fa39SPaul Nodet pub fn block_dominates(&self, block_a: Block, block_b: Block) -> bool { 2553a14fa39SPaul Nodet let na = &self.nodes[block_a]; 2563a14fa39SPaul Nodet let nb = &self.nodes[block_b]; 2573a14fa39SPaul Nodet na.dom_pre_number <= nb.dom_pre_number && na.dom_pre_max >= nb.dom_pre_max 258747ad3c4Slazypassion } 259a6c4f9a0Samartosch 2603a14fa39SPaul Nodet /// Get an iterator over the direct children of `block` in the dominator tree. 2613a14fa39SPaul Nodet /// 2623a14fa39SPaul Nodet /// These are the blocks whose immediate dominator is `block`, ordered according 2633a14fa39SPaul Nodet /// to the CFG reverse post-order. children(&self, block: Block) -> ChildIter<'_>2643a14fa39SPaul Nodet pub fn children(&self, block: Block) -> ChildIter<'_> { 2653a14fa39SPaul Nodet ChildIter { 2663a14fa39SPaul Nodet domtree: self, 2673a14fa39SPaul Nodet next: self.nodes[block].child, 2683a14fa39SPaul Nodet } 269747ad3c4Slazypassion } 270747ad3c4Slazypassion } 271747ad3c4Slazypassion 272747ad3c4Slazypassion impl DominatorTree { 273747ad3c4Slazypassion /// Allocate a new blank dominator tree. Use `compute` to compute the dominator tree for a 274747ad3c4Slazypassion /// function. new() -> Self275747ad3c4Slazypassion pub fn new() -> Self { 276747ad3c4Slazypassion Self { 2771bb71d31Samartosch stree: SpanningTree::new(), 278747ad3c4Slazypassion nodes: SecondaryMap::new(), 279747ad3c4Slazypassion postorder: Vec::new(), 2801bb71d31Samartosch dfs_worklist: Vec::new(), 2811bb71d31Samartosch eval_worklist: Vec::new(), 282747ad3c4Slazypassion valid: false, 283747ad3c4Slazypassion } 284747ad3c4Slazypassion } 285747ad3c4Slazypassion 286747ad3c4Slazypassion /// Allocate and compute a dominator tree. with_function(func: &Function, cfg: &ControlFlowGraph) -> Self287747ad3c4Slazypassion pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self { 288832666c4SRyan Hunt let block_capacity = func.layout.block_capacity(); 2894b085b9cSSean Stangl let mut domtree = Self { 2901bb71d31Samartosch stree: SpanningTree::with_capacity(block_capacity), 291832666c4SRyan Hunt nodes: SecondaryMap::with_capacity(block_capacity), 292832666c4SRyan Hunt postorder: Vec::with_capacity(block_capacity), 2931bb71d31Samartosch dfs_worklist: Vec::new(), 2941bb71d31Samartosch eval_worklist: Vec::new(), 2954b085b9cSSean Stangl valid: false, 2964b085b9cSSean Stangl }; 297747ad3c4Slazypassion domtree.compute(func, cfg); 298747ad3c4Slazypassion domtree 299747ad3c4Slazypassion } 300747ad3c4Slazypassion 3011bb71d31Samartosch /// Reset and compute a CFG post-order and dominator tree, 3021bb71d31Samartosch /// using Semi-NCA algorithm, described in the paper: 3031bb71d31Samartosch /// 3041bb71d31Samartosch /// Linear-Time Algorithms for Dominators and Related Problems. 3051bb71d31Samartosch /// Loukas Georgiadis, Princeton University, November 2005. 3061bb71d31Samartosch /// 3071bb71d31Samartosch /// The same algorithm is used by Julia, SpiderMonkey and LLVM, 3081bb71d31Samartosch /// the implementation is heavily inspired by them. compute(&mut self, func: &Function, cfg: &ControlFlowGraph)309747ad3c4Slazypassion pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) { 310747ad3c4Slazypassion let _tt = timing::domtree(); 311747ad3c4Slazypassion debug_assert!(cfg.is_valid()); 3121bb71d31Samartosch 3131bb71d31Samartosch self.clear(); 3141bb71d31Samartosch self.compute_spanning_tree(func); 3151bb71d31Samartosch self.compute_domtree(cfg); 3163a14fa39SPaul Nodet self.compute_domtree_preorder(); 3171bb71d31Samartosch 318747ad3c4Slazypassion self.valid = true; 319747ad3c4Slazypassion } 320747ad3c4Slazypassion 321747ad3c4Slazypassion /// Clear the data structures used to represent the dominator tree. This will leave the tree in 322747ad3c4Slazypassion /// a state where `is_valid()` returns false. clear(&mut self)323747ad3c4Slazypassion pub fn clear(&mut self) { 3241bb71d31Samartosch self.stree.clear(); 325747ad3c4Slazypassion self.nodes.clear(); 326747ad3c4Slazypassion self.postorder.clear(); 327747ad3c4Slazypassion self.valid = false; 328747ad3c4Slazypassion } 329747ad3c4Slazypassion 330747ad3c4Slazypassion /// Check if the dominator tree is in a valid state. 331747ad3c4Slazypassion /// 332747ad3c4Slazypassion /// Note that this doesn't perform any kind of validity checks. It simply checks if the 333747ad3c4Slazypassion /// `compute()` method has been called since the last `clear()`. It does not check that the 334747ad3c4Slazypassion /// dominator tree is consistent with the CFG. is_valid(&self) -> bool335747ad3c4Slazypassion pub fn is_valid(&self) -> bool { 336747ad3c4Slazypassion self.valid 337747ad3c4Slazypassion } 338747ad3c4Slazypassion 3391bb71d31Samartosch /// Reset all internal data structures, build spanning tree 3401bb71d31Samartosch /// and compute a post-order of the control flow graph. compute_spanning_tree(&mut self, func: &Function)3411bb71d31Samartosch fn compute_spanning_tree(&mut self, func: &Function) { 342832666c4SRyan Hunt self.nodes.resize(func.dfg.num_blocks()); 3431bb71d31Samartosch self.stree.reserve(func.dfg.num_blocks()); 3441bb71d31Samartosch 3451bb71d31Samartosch if let Some(block) = func.layout.entry_block() { 3461bb71d31Samartosch self.dfs_worklist.push(TraversalEvent::Enter(0, block)); 347747ad3c4Slazypassion } 348747ad3c4Slazypassion 3491bb71d31Samartosch loop { 3501bb71d31Samartosch match self.dfs_worklist.pop() { 3511bb71d31Samartosch Some(TraversalEvent::Enter(parent, block)) => { 3521bb71d31Samartosch let node = &mut self.nodes[block]; 3531bb71d31Samartosch if node.pre_number != NOT_VISITED { 3541bb71d31Samartosch continue; 355747ad3c4Slazypassion } 356747ad3c4Slazypassion 3571bb71d31Samartosch self.dfs_worklist.push(TraversalEvent::Exit(block)); 3581bb71d31Samartosch 3591bb71d31Samartosch let pre_number = self.stree.push(parent, block); 3601bb71d31Samartosch node.pre_number = pre_number; 3611bb71d31Samartosch 3621bb71d31Samartosch // Use the same traversal heuristics as in traversals.rs. 3631bb71d31Samartosch self.dfs_worklist.extend( 3641bb71d31Samartosch func.block_successors(block) 3651bb71d31Samartosch // Heuristic: chase the children in reverse. This puts 3661bb71d31Samartosch // the first successor block first in the postorder, all 3671bb71d31Samartosch // other things being equal, which tends to prioritize 3681bb71d31Samartosch // loop backedges over out-edges, putting the edge-block 3691bb71d31Samartosch // closer to the loop body and minimizing live-ranges in 3701bb71d31Samartosch // linear instruction space. This heuristic doesn't have 3711bb71d31Samartosch // any effect on the computation of dominators, and is 3721bb71d31Samartosch // purely for other consumers of the postorder we cache 3731bb71d31Samartosch // here. 3741bb71d31Samartosch .rev() 3751bb71d31Samartosch // A simple optimization: push less items to the stack. 3761bb71d31Samartosch .filter(|successor| self.nodes[*successor].pre_number == NOT_VISITED) 3771bb71d31Samartosch .map(|successor| TraversalEvent::Enter(pre_number, successor)), 3781bb71d31Samartosch ); 379747ad3c4Slazypassion } 3801bb71d31Samartosch Some(TraversalEvent::Exit(block)) => self.postorder.push(block), 3811bb71d31Samartosch None => break, 382747ad3c4Slazypassion } 383747ad3c4Slazypassion } 384747ad3c4Slazypassion } 385747ad3c4Slazypassion 3861bb71d31Samartosch /// Eval-link procedure from the paper. 3871bb71d31Samartosch /// For a predecessor V of node W returns V if V < W, otherwise the minimum of sdom(U), 3881bb71d31Samartosch /// where U > W and U is on a semi-dominator path for W in CFG. 3891bb71d31Samartosch /// Use path compression to bring complexity down to O(m*log(n)). eval(&mut self, v: u32, last_linked: u32) -> u323901bb71d31Samartosch fn eval(&mut self, v: u32, last_linked: u32) -> u32 { 3911bb71d31Samartosch if self.stree[v].ancestor < last_linked { 3921bb71d31Samartosch return self.stree[v].label; 3931bb71d31Samartosch } 3941bb71d31Samartosch 3951bb71d31Samartosch // Follow semi-dominator path. 3961bb71d31Samartosch let mut root = v; 3971bb71d31Samartosch loop { 3981bb71d31Samartosch self.eval_worklist.push(root); 3991bb71d31Samartosch root = self.stree[root].ancestor; 4001bb71d31Samartosch 4011bb71d31Samartosch if self.stree[root].ancestor < last_linked { 4021bb71d31Samartosch break; 4031bb71d31Samartosch } 4041bb71d31Samartosch } 4051bb71d31Samartosch 4061bb71d31Samartosch let mut prev = root; 4071bb71d31Samartosch let root = self.stree[prev].ancestor; 4081bb71d31Samartosch 4091bb71d31Samartosch // Perform path compression. Point all ancestors to the root 4101bb71d31Samartosch // and propagate minimal sdom(U) value from ancestors to children. 4111bb71d31Samartosch while let Some(curr) = self.eval_worklist.pop() { 4121bb71d31Samartosch if self.stree[prev].label < self.stree[curr].label { 4131bb71d31Samartosch self.stree[curr].label = self.stree[prev].label; 4141bb71d31Samartosch } 4151bb71d31Samartosch 4161bb71d31Samartosch self.stree[curr].ancestor = root; 4171bb71d31Samartosch prev = curr; 4181bb71d31Samartosch } 4191bb71d31Samartosch 4201bb71d31Samartosch self.stree[v].label 4211bb71d31Samartosch } 4221bb71d31Samartosch compute_domtree(&mut self, cfg: &ControlFlowGraph)4231bb71d31Samartosch fn compute_domtree(&mut self, cfg: &ControlFlowGraph) { 4241bb71d31Samartosch // Compute semi-dominators. 4251bb71d31Samartosch for w in (1..self.stree.len() as u32).rev() { 4261bb71d31Samartosch let w_node = &mut self.stree[w]; 4271bb71d31Samartosch let block = w_node.block.expect("Virtual root must have been excluded"); 4281bb71d31Samartosch let mut semi = w_node.ancestor; 4291bb71d31Samartosch 4301bb71d31Samartosch let last_linked = w + 1; 4311bb71d31Samartosch 4321bb71d31Samartosch for pred in cfg 433832666c4SRyan Hunt .pred_iter(block) 4341bb71d31Samartosch .map(|pred: BlockPredecessor| pred.block) 4351bb71d31Samartosch { 4361bb71d31Samartosch // Skip unreachable nodes. 4371bb71d31Samartosch if self.nodes[pred].pre_number == NOT_VISITED { 4381bb71d31Samartosch continue; 439747ad3c4Slazypassion } 440747ad3c4Slazypassion 4411bb71d31Samartosch let semi_candidate = self.eval(self.nodes[pred].pre_number, last_linked); 442*0889323aSSSD semi = core::cmp::min(semi, semi_candidate); 4431bb71d31Samartosch } 4441bb71d31Samartosch 4451bb71d31Samartosch let w_node = &mut self.stree[w]; 4461bb71d31Samartosch w_node.label = semi; 4471bb71d31Samartosch w_node.semi = semi; 4481bb71d31Samartosch } 4491bb71d31Samartosch 4501bb71d31Samartosch // Compute immediate dominators. 4511bb71d31Samartosch for v in 1..self.stree.len() as u32 { 4521bb71d31Samartosch let semi = self.stree[v].semi; 4531bb71d31Samartosch let block = self.stree[v] 4541bb71d31Samartosch .block 4551bb71d31Samartosch .expect("Virtual root must have been excluded"); 4561bb71d31Samartosch let mut idom = self.stree[v].idom; 4571bb71d31Samartosch 4581bb71d31Samartosch while idom > semi { 4591bb71d31Samartosch idom = self.stree[idom].idom; 4601bb71d31Samartosch } 4611bb71d31Samartosch 4621bb71d31Samartosch self.stree[v].idom = idom; 4631bb71d31Samartosch 4641bb71d31Samartosch self.nodes[block].idom = self.stree[idom].block; 4651bb71d31Samartosch } 466747ad3c4Slazypassion } 467747ad3c4Slazypassion 4683a14fa39SPaul Nodet /// Compute dominator tree preorder information. 469747ad3c4Slazypassion /// 4703a14fa39SPaul Nodet /// This populates child/sibling links and preorder numbers for fast dominance checks. compute_domtree_preorder(&mut self)4713a14fa39SPaul Nodet fn compute_domtree_preorder(&mut self) { 472747ad3c4Slazypassion // Step 1: Populate the child and sibling links. 473747ad3c4Slazypassion // 474747ad3c4Slazypassion // By following the CFG post-order and pushing to the front of the lists, we make sure that 475747ad3c4Slazypassion // sibling lists are ordered according to the CFG reverse post-order. 4763a14fa39SPaul Nodet for &block in &self.postorder { 4773a14fa39SPaul Nodet if let Some(idom) = self.idom(block) { 478832666c4SRyan Hunt let sib = mem::replace(&mut self.nodes[idom].child, block.into()); 479832666c4SRyan Hunt self.nodes[block].sibling = sib; 480747ad3c4Slazypassion } else { 481832666c4SRyan Hunt // The only block without an immediate dominator is the entry. 4823a14fa39SPaul Nodet self.dfs_worklist.push(TraversalEvent::Enter(0, block)); 483747ad3c4Slazypassion } 484747ad3c4Slazypassion } 485747ad3c4Slazypassion 486747ad3c4Slazypassion // Step 2. Assign pre-order numbers from a DFS of the dominator tree. 4873a14fa39SPaul Nodet debug_assert!(self.dfs_worklist.len() <= 1); 488747ad3c4Slazypassion let mut n = 0; 4893a14fa39SPaul Nodet while let Some(event) = self.dfs_worklist.pop() { 4903a14fa39SPaul Nodet if let TraversalEvent::Enter(_, block) = event { 491747ad3c4Slazypassion n += 1; 492832666c4SRyan Hunt let node = &mut self.nodes[block]; 4933a14fa39SPaul Nodet node.dom_pre_number = n; 4943a14fa39SPaul Nodet node.dom_pre_max = n; 4953a14fa39SPaul Nodet if let Some(sibling) = node.sibling.expand() { 4963a14fa39SPaul Nodet self.dfs_worklist.push(TraversalEvent::Enter(0, sibling)); 497747ad3c4Slazypassion } 4983a14fa39SPaul Nodet if let Some(child) = node.child.expand() { 4993a14fa39SPaul Nodet self.dfs_worklist.push(TraversalEvent::Enter(0, child)); 5003a14fa39SPaul Nodet } 501747ad3c4Slazypassion } 502747ad3c4Slazypassion } 503747ad3c4Slazypassion 5043a14fa39SPaul Nodet // Step 3. Propagate the `dom_pre_max` numbers up the tree. 505747ad3c4Slazypassion // The CFG post-order is topologically ordered w.r.t. dominance so a node comes after all 506747ad3c4Slazypassion // its dominator tree children. 5073a14fa39SPaul Nodet for &block in &self.postorder { 5083a14fa39SPaul Nodet if let Some(idom) = self.idom(block) { 5093a14fa39SPaul Nodet let pre_max = cmp::max(self.nodes[block].dom_pre_max, self.nodes[idom].dom_pre_max); 5103a14fa39SPaul Nodet self.nodes[idom].dom_pre_max = pre_max; 511747ad3c4Slazypassion } 512747ad3c4Slazypassion } 513747ad3c4Slazypassion } 514747ad3c4Slazypassion } 515747ad3c4Slazypassion 51607f335dcSRyan Hunt /// An iterator that enumerates the direct children of a block in the dominator tree. 517747ad3c4Slazypassion pub struct ChildIter<'a> { 5183a14fa39SPaul Nodet domtree: &'a DominatorTree, 519832666c4SRyan Hunt next: PackedOption<Block>, 520747ad3c4Slazypassion } 521747ad3c4Slazypassion 522747ad3c4Slazypassion impl<'a> Iterator for ChildIter<'a> { 523832666c4SRyan Hunt type Item = Block; 524747ad3c4Slazypassion next(&mut self) -> Option<Block>525832666c4SRyan Hunt fn next(&mut self) -> Option<Block> { 526747ad3c4Slazypassion let n = self.next.expand(); 527832666c4SRyan Hunt if let Some(block) = n { 5283a14fa39SPaul Nodet self.next = self.domtree.nodes[block].sibling; 529747ad3c4Slazypassion } 530747ad3c4Slazypassion n 531747ad3c4Slazypassion } 532747ad3c4Slazypassion } 533747ad3c4Slazypassion 534747ad3c4Slazypassion #[cfg(test)] 535747ad3c4Slazypassion mod tests { 536747ad3c4Slazypassion use super::*; 537747ad3c4Slazypassion use crate::cursor::{Cursor, FuncCursor}; 538747ad3c4Slazypassion use crate::ir::types::*; 5399ce3ffe1SAlex Crichton use crate::ir::{InstBuilder, TrapCode}; 540747ad3c4Slazypassion 541747ad3c4Slazypassion #[test] empty()542747ad3c4Slazypassion fn empty() { 543747ad3c4Slazypassion let func = Function::new(); 544747ad3c4Slazypassion let cfg = ControlFlowGraph::with_function(&func); 545747ad3c4Slazypassion debug_assert!(cfg.is_valid()); 546747ad3c4Slazypassion let dtree = DominatorTree::with_function(&func, &cfg); 547747ad3c4Slazypassion assert_eq!(0, dtree.nodes.keys().count()); 548747ad3c4Slazypassion assert_eq!(dtree.cfg_postorder(), &[]); 549747ad3c4Slazypassion } 550747ad3c4Slazypassion 551747ad3c4Slazypassion #[test] unreachable_node()552747ad3c4Slazypassion fn unreachable_node() { 553747ad3c4Slazypassion let mut func = Function::new(); 554832666c4SRyan Hunt let block0 = func.dfg.make_block(); 555832666c4SRyan Hunt let v0 = func.dfg.append_block_param(block0, I32); 556832666c4SRyan Hunt let block1 = func.dfg.make_block(); 557832666c4SRyan Hunt let block2 = func.dfg.make_block(); 558a5698cedSTrevor Elliott let trap_block = func.dfg.make_block(); 559747ad3c4Slazypassion 560747ad3c4Slazypassion let mut cur = FuncCursor::new(&mut func); 561747ad3c4Slazypassion 562832666c4SRyan Hunt cur.insert_block(block0); 563a5698cedSTrevor Elliott cur.ins().brif(v0, block2, &[], trap_block, &[]); 564a5698cedSTrevor Elliott 565a5698cedSTrevor Elliott cur.insert_block(trap_block); 5669fc41baeSAlex Crichton cur.ins().trap(TrapCode::unwrap_user(1)); 567747ad3c4Slazypassion 568832666c4SRyan Hunt cur.insert_block(block1); 569747ad3c4Slazypassion let v1 = cur.ins().iconst(I32, 1); 570747ad3c4Slazypassion let v2 = cur.ins().iadd(v0, v1); 57194ec88eaSChris Fallin cur.ins().jump(block0, &[v2.into()]); 572747ad3c4Slazypassion 573832666c4SRyan Hunt cur.insert_block(block2); 574747ad3c4Slazypassion cur.ins().return_(&[v0]); 575747ad3c4Slazypassion 576747ad3c4Slazypassion let cfg = ControlFlowGraph::with_function(cur.func); 577747ad3c4Slazypassion let dt = DominatorTree::with_function(cur.func, &cfg); 578747ad3c4Slazypassion 579747ad3c4Slazypassion // Fall-through-first, prune-at-source DFT: 580747ad3c4Slazypassion // 581832666c4SRyan Hunt // block0 { 582a5698cedSTrevor Elliott // brif block2 { 583747ad3c4Slazypassion // trap 584832666c4SRyan Hunt // block2 { 585747ad3c4Slazypassion // return 586832666c4SRyan Hunt // } block2 587832666c4SRyan Hunt // } block0 5888abfe928STrevor Elliott assert_eq!(dt.cfg_postorder(), &[block2, trap_block, block0]); 589747ad3c4Slazypassion 590747ad3c4Slazypassion let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); 591832666c4SRyan Hunt assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); 592832666c4SRyan Hunt assert!(!dt.dominates(block0, v2_def, &cur.func.layout)); 593747ad3c4Slazypassion 5943a14fa39SPaul Nodet assert!(dt.block_dominates(block0, block0)); 5953a14fa39SPaul Nodet assert!(!dt.block_dominates(block0, block1)); 5963a14fa39SPaul Nodet assert!(dt.block_dominates(block0, block2)); 5973a14fa39SPaul Nodet assert!(!dt.block_dominates(block1, block0)); 5983a14fa39SPaul Nodet assert!(dt.block_dominates(block1, block1)); 5993a14fa39SPaul Nodet assert!(!dt.block_dominates(block1, block2)); 6003a14fa39SPaul Nodet assert!(!dt.block_dominates(block2, block0)); 6013a14fa39SPaul Nodet assert!(!dt.block_dominates(block2, block1)); 6023a14fa39SPaul Nodet assert!(dt.block_dominates(block2, block2)); 603747ad3c4Slazypassion } 604747ad3c4Slazypassion 605747ad3c4Slazypassion #[test] non_zero_entry_block()606747ad3c4Slazypassion fn non_zero_entry_block() { 607747ad3c4Slazypassion let mut func = Function::new(); 608832666c4SRyan Hunt let block0 = func.dfg.make_block(); 609832666c4SRyan Hunt let block1 = func.dfg.make_block(); 610832666c4SRyan Hunt let block2 = func.dfg.make_block(); 611832666c4SRyan Hunt let block3 = func.dfg.make_block(); 612832666c4SRyan Hunt let cond = func.dfg.append_block_param(block3, I32); 613747ad3c4Slazypassion 614747ad3c4Slazypassion let mut cur = FuncCursor::new(&mut func); 615747ad3c4Slazypassion 616832666c4SRyan Hunt cur.insert_block(block3); 617832666c4SRyan Hunt let jmp_block3_block1 = cur.ins().jump(block1, &[]); 618747ad3c4Slazypassion 619832666c4SRyan Hunt cur.insert_block(block1); 620a5698cedSTrevor Elliott let br_block1_block0_block2 = cur.ins().brif(cond, block0, &[], block2, &[]); 621747ad3c4Slazypassion 622832666c4SRyan Hunt cur.insert_block(block2); 623832666c4SRyan Hunt cur.ins().jump(block0, &[]); 624747ad3c4Slazypassion 625832666c4SRyan Hunt cur.insert_block(block0); 626747ad3c4Slazypassion 627747ad3c4Slazypassion let cfg = ControlFlowGraph::with_function(cur.func); 628747ad3c4Slazypassion let dt = DominatorTree::with_function(cur.func, &cfg); 629747ad3c4Slazypassion 630747ad3c4Slazypassion // Fall-through-first, prune-at-source DFT: 631747ad3c4Slazypassion // 632832666c4SRyan Hunt // block3 { 633832666c4SRyan Hunt // block3:jump block1 { 634832666c4SRyan Hunt // block1 { 635a5698cedSTrevor Elliott // block1:brif block0 { 636832666c4SRyan Hunt // block1:jump block2 { 637832666c4SRyan Hunt // block2 { 638832666c4SRyan Hunt // block2:jump block0 (seen) 639832666c4SRyan Hunt // } block2 640832666c4SRyan Hunt // } block1:jump block2 641832666c4SRyan Hunt // block0 { 642832666c4SRyan Hunt // } block0 643a5698cedSTrevor Elliott // } block1:brif block0 644832666c4SRyan Hunt // } block1 645832666c4SRyan Hunt // } block3:jump block1 646832666c4SRyan Hunt // } block3 647747ad3c4Slazypassion 648a139ed6dSTrevor Elliott assert_eq!(dt.cfg_postorder(), &[block0, block2, block1, block3]); 649747ad3c4Slazypassion 650832666c4SRyan Hunt assert_eq!(cur.func.layout.entry_block().unwrap(), block3); 651832666c4SRyan Hunt assert_eq!(dt.idom(block3), None); 652a6c4f9a0Samartosch assert_eq!(dt.idom(block1).unwrap(), block3); 653a6c4f9a0Samartosch assert_eq!(dt.idom(block2).unwrap(), block1); 654a6c4f9a0Samartosch assert_eq!(dt.idom(block0).unwrap(), block1); 655747ad3c4Slazypassion 656a5698cedSTrevor Elliott assert!(dt.dominates( 657a5698cedSTrevor Elliott br_block1_block0_block2, 658a5698cedSTrevor Elliott br_block1_block0_block2, 659a5698cedSTrevor Elliott &cur.func.layout 660a5698cedSTrevor Elliott )); 661a5698cedSTrevor Elliott assert!(!dt.dominates(br_block1_block0_block2, jmp_block3_block1, &cur.func.layout)); 662a5698cedSTrevor Elliott assert!(dt.dominates(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout)); 663747ad3c4Slazypassion } 664747ad3c4Slazypassion 665747ad3c4Slazypassion #[test] backwards_layout()666747ad3c4Slazypassion fn backwards_layout() { 667747ad3c4Slazypassion let mut func = Function::new(); 668832666c4SRyan Hunt let block0 = func.dfg.make_block(); 669832666c4SRyan Hunt let block1 = func.dfg.make_block(); 670832666c4SRyan Hunt let block2 = func.dfg.make_block(); 671747ad3c4Slazypassion 672747ad3c4Slazypassion let mut cur = FuncCursor::new(&mut func); 673747ad3c4Slazypassion 674832666c4SRyan Hunt cur.insert_block(block0); 675832666c4SRyan Hunt let jmp02 = cur.ins().jump(block2, &[]); 676747ad3c4Slazypassion 677832666c4SRyan Hunt cur.insert_block(block1); 6789fc41baeSAlex Crichton let trap = cur.ins().trap(TrapCode::unwrap_user(5)); 679747ad3c4Slazypassion 680832666c4SRyan Hunt cur.insert_block(block2); 681832666c4SRyan Hunt let jmp21 = cur.ins().jump(block1, &[]); 682747ad3c4Slazypassion 683747ad3c4Slazypassion let cfg = ControlFlowGraph::with_function(cur.func); 684747ad3c4Slazypassion let dt = DominatorTree::with_function(cur.func, &cfg); 685747ad3c4Slazypassion 686832666c4SRyan Hunt assert_eq!(cur.func.layout.entry_block(), Some(block0)); 687832666c4SRyan Hunt assert_eq!(dt.idom(block0), None); 688a6c4f9a0Samartosch assert_eq!(dt.idom(block1), Some(block2)); 689a6c4f9a0Samartosch assert_eq!(dt.idom(block2), Some(block0)); 690747ad3c4Slazypassion 691832666c4SRyan Hunt assert!(dt.dominates(block0, block0, &cur.func.layout)); 692832666c4SRyan Hunt assert!(dt.dominates(block0, jmp02, &cur.func.layout)); 693832666c4SRyan Hunt assert!(dt.dominates(block0, block1, &cur.func.layout)); 694832666c4SRyan Hunt assert!(dt.dominates(block0, trap, &cur.func.layout)); 695832666c4SRyan Hunt assert!(dt.dominates(block0, block2, &cur.func.layout)); 696832666c4SRyan Hunt assert!(dt.dominates(block0, jmp21, &cur.func.layout)); 697747ad3c4Slazypassion 698832666c4SRyan Hunt assert!(!dt.dominates(jmp02, block0, &cur.func.layout)); 699747ad3c4Slazypassion assert!(dt.dominates(jmp02, jmp02, &cur.func.layout)); 700832666c4SRyan Hunt assert!(dt.dominates(jmp02, block1, &cur.func.layout)); 701747ad3c4Slazypassion assert!(dt.dominates(jmp02, trap, &cur.func.layout)); 702832666c4SRyan Hunt assert!(dt.dominates(jmp02, block2, &cur.func.layout)); 703747ad3c4Slazypassion assert!(dt.dominates(jmp02, jmp21, &cur.func.layout)); 704747ad3c4Slazypassion 705832666c4SRyan Hunt assert!(!dt.dominates(block1, block0, &cur.func.layout)); 706832666c4SRyan Hunt assert!(!dt.dominates(block1, jmp02, &cur.func.layout)); 707832666c4SRyan Hunt assert!(dt.dominates(block1, block1, &cur.func.layout)); 708832666c4SRyan Hunt assert!(dt.dominates(block1, trap, &cur.func.layout)); 709832666c4SRyan Hunt assert!(!dt.dominates(block1, block2, &cur.func.layout)); 710832666c4SRyan Hunt assert!(!dt.dominates(block1, jmp21, &cur.func.layout)); 711747ad3c4Slazypassion 712832666c4SRyan Hunt assert!(!dt.dominates(trap, block0, &cur.func.layout)); 713747ad3c4Slazypassion assert!(!dt.dominates(trap, jmp02, &cur.func.layout)); 714832666c4SRyan Hunt assert!(!dt.dominates(trap, block1, &cur.func.layout)); 715747ad3c4Slazypassion assert!(dt.dominates(trap, trap, &cur.func.layout)); 716832666c4SRyan Hunt assert!(!dt.dominates(trap, block2, &cur.func.layout)); 717747ad3c4Slazypassion assert!(!dt.dominates(trap, jmp21, &cur.func.layout)); 718747ad3c4Slazypassion 719832666c4SRyan Hunt assert!(!dt.dominates(block2, block0, &cur.func.layout)); 720832666c4SRyan Hunt assert!(!dt.dominates(block2, jmp02, &cur.func.layout)); 721832666c4SRyan Hunt assert!(dt.dominates(block2, block1, &cur.func.layout)); 722832666c4SRyan Hunt assert!(dt.dominates(block2, trap, &cur.func.layout)); 723832666c4SRyan Hunt assert!(dt.dominates(block2, block2, &cur.func.layout)); 724832666c4SRyan Hunt assert!(dt.dominates(block2, jmp21, &cur.func.layout)); 725747ad3c4Slazypassion 726832666c4SRyan Hunt assert!(!dt.dominates(jmp21, block0, &cur.func.layout)); 727747ad3c4Slazypassion assert!(!dt.dominates(jmp21, jmp02, &cur.func.layout)); 728832666c4SRyan Hunt assert!(dt.dominates(jmp21, block1, &cur.func.layout)); 729747ad3c4Slazypassion assert!(dt.dominates(jmp21, trap, &cur.func.layout)); 730832666c4SRyan Hunt assert!(!dt.dominates(jmp21, block2, &cur.func.layout)); 731747ad3c4Slazypassion assert!(dt.dominates(jmp21, jmp21, &cur.func.layout)); 732747ad3c4Slazypassion } 733a6c4f9a0Samartosch 734a6c4f9a0Samartosch #[test] insts_same_block()735a6c4f9a0Samartosch fn insts_same_block() { 736a6c4f9a0Samartosch let mut func = Function::new(); 737a6c4f9a0Samartosch let block0 = func.dfg.make_block(); 738a6c4f9a0Samartosch 739a6c4f9a0Samartosch let mut cur = FuncCursor::new(&mut func); 740a6c4f9a0Samartosch 741a6c4f9a0Samartosch cur.insert_block(block0); 742a6c4f9a0Samartosch let v1 = cur.ins().iconst(I32, 1); 743a6c4f9a0Samartosch let v2 = cur.ins().iadd(v1, v1); 744a6c4f9a0Samartosch let v3 = cur.ins().iadd(v2, v2); 745a6c4f9a0Samartosch cur.ins().return_(&[]); 746a6c4f9a0Samartosch 747a6c4f9a0Samartosch let cfg = ControlFlowGraph::with_function(cur.func); 748a6c4f9a0Samartosch let dt = DominatorTree::with_function(cur.func, &cfg); 749a6c4f9a0Samartosch 750a6c4f9a0Samartosch let v1_def = cur.func.dfg.value_def(v1).unwrap_inst(); 751a6c4f9a0Samartosch let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); 752a6c4f9a0Samartosch let v3_def = cur.func.dfg.value_def(v3).unwrap_inst(); 753a6c4f9a0Samartosch 754a6c4f9a0Samartosch assert!(dt.dominates(v1_def, v2_def, &cur.func.layout)); 755a6c4f9a0Samartosch assert!(dt.dominates(v2_def, v3_def, &cur.func.layout)); 756a6c4f9a0Samartosch assert!(dt.dominates(v1_def, v3_def, &cur.func.layout)); 757a6c4f9a0Samartosch 758a6c4f9a0Samartosch assert!(!dt.dominates(v2_def, v1_def, &cur.func.layout)); 759a6c4f9a0Samartosch assert!(!dt.dominates(v3_def, v2_def, &cur.func.layout)); 760a6c4f9a0Samartosch assert!(!dt.dominates(v3_def, v1_def, &cur.func.layout)); 761a6c4f9a0Samartosch 762a6c4f9a0Samartosch assert!(dt.dominates(v2_def, v2_def, &cur.func.layout)); 763a6c4f9a0Samartosch assert!(dt.dominates(block0, block0, &cur.func.layout)); 764a6c4f9a0Samartosch 765a6c4f9a0Samartosch assert!(dt.dominates(block0, v1_def, &cur.func.layout)); 766a6c4f9a0Samartosch assert!(dt.dominates(block0, v2_def, &cur.func.layout)); 767a6c4f9a0Samartosch assert!(dt.dominates(block0, v3_def, &cur.func.layout)); 768a6c4f9a0Samartosch 769a6c4f9a0Samartosch assert!(!dt.dominates(v1_def, block0, &cur.func.layout)); 770a6c4f9a0Samartosch assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); 771a6c4f9a0Samartosch assert!(!dt.dominates(v3_def, block0, &cur.func.layout)); 772a6c4f9a0Samartosch } 773747ad3c4Slazypassion } 774