1 //! A Dominator Tree represented as mappings of Blocks to their immediate dominator. 2 3 use crate::entity::SecondaryMap; 4 use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; 5 use crate::ir::{Block, Function, Layout, ProgramPoint}; 6 use crate::packed_option::PackedOption; 7 use crate::timing; 8 use alloc::vec::Vec; 9 use core::cmp; 10 use core::cmp::Ordering; 11 use core::mem; 12 13 mod simple; 14 15 pub use simple::SimpleDominatorTree; 16 17 /// Spanning tree node, used during domtree computation. 18 #[derive(Clone, Default)] 19 struct SpanningTreeNode { 20 /// This node's block in function CFG. 21 block: PackedOption<Block>, 22 /// Node's ancestor in the spanning tree. 23 /// Gets invalidated during semi-dominator computation. 24 ancestor: u32, 25 /// The smallest semi value discovered on any semi-dominator path 26 /// that went through the node up till the moment. 27 /// Gets updated in the course of semi-dominator computation. 28 label: u32, 29 /// Semidominator value for the node. 30 semi: u32, 31 /// Immediate dominator value for the node. 32 /// Initialized to node's ancestor in the spanning tree. 33 idom: u32, 34 } 35 36 /// DFS preorder number for unvisited nodes and the virtual root in the spanning tree. 37 const NOT_VISITED: u32 = 0; 38 39 /// Spanning tree, in CFG preorder. 40 /// Node 0 is the virtual root and doesn't have a corresponding block. 41 /// It's not required because function's CFG in Cranelift always have 42 /// a singular root, but helps to avoid additional checks. 43 /// Numbering nodes from 0 also follows the convention in 44 /// `SimpleDominatorTree`. 45 #[derive(Clone, Default)] 46 struct SpanningTree { 47 nodes: Vec<SpanningTreeNode>, 48 } 49 50 impl SpanningTree { new() -> Self51 fn new() -> Self { 52 // Include the virtual root. 53 Self { 54 nodes: vec![Default::default()], 55 } 56 } 57 with_capacity(capacity: usize) -> Self58 fn with_capacity(capacity: usize) -> Self { 59 // Include the virtual root. 60 let mut nodes = Vec::with_capacity(capacity + 1); 61 nodes.push(Default::default()); 62 Self { nodes } 63 } 64 len(&self) -> usize65 fn len(&self) -> usize { 66 self.nodes.len() 67 } 68 reserve(&mut self, capacity: usize)69 fn reserve(&mut self, capacity: usize) { 70 // Virtual root should be already included. 71 self.nodes.reserve(capacity); 72 } 73 clear(&mut self)74 fn clear(&mut self) { 75 self.nodes.resize(1, Default::default()); 76 } 77 78 /// Returns pre_number for the new node. push(&mut self, ancestor: u32, block: Block) -> u3279 fn push(&mut self, ancestor: u32, block: Block) -> u32 { 80 // Virtual root should be already included. 81 debug_assert!(!self.nodes.is_empty()); 82 83 let pre_number = self.nodes.len() as u32; 84 85 self.nodes.push(SpanningTreeNode { 86 block: block.into(), 87 ancestor, 88 label: pre_number, 89 semi: pre_number, 90 idom: ancestor, 91 }); 92 93 pre_number 94 } 95 } 96 97 impl core::ops::Index<u32> for SpanningTree { 98 type Output = SpanningTreeNode; 99 index(&self, idx: u32) -> &Self::Output100 fn index(&self, idx: u32) -> &Self::Output { 101 &self.nodes[idx as usize] 102 } 103 } 104 105 impl core::ops::IndexMut<u32> for SpanningTree { index_mut(&mut self, idx: u32) -> &mut Self::Output106 fn index_mut(&mut self, idx: u32) -> &mut Self::Output { 107 &mut self.nodes[idx as usize] 108 } 109 } 110 111 /// Traversal event to compute both preorder spanning tree 112 /// and postorder block list. Can't use `Dfs` from traversals.rs 113 /// here because of the need for parent links. 114 enum TraversalEvent { 115 Enter(u32, Block), 116 Exit(Block), 117 } 118 119 /// Dominator tree node. We keep one of these per block. 120 #[derive(Clone, Default)] 121 struct DominatorTreeNode { 122 /// Immediate dominator for the block, `None` for unreachable blocks. 123 idom: PackedOption<Block>, 124 /// Preorder traversal number, zero for unreachable blocks. 125 pre_number: u32, 126 127 /// First child node in the domtree. 128 child: PackedOption<Block>, 129 130 /// Next sibling node in the domtree. This linked list is ordered according to the CFG RPO. 131 sibling: PackedOption<Block>, 132 133 /// Sequence number for this node in a pre-order traversal of the dominator tree. 134 /// Unreachable blocks have number 0, the entry block is 1. 135 dom_pre_number: u32, 136 137 /// Maximum `dom_pre_number` for the sub-tree of the dominator tree that is rooted at this node. 138 /// This is always >= `dom_pre_number`. 139 dom_pre_max: u32, 140 } 141 142 /// The dominator tree for a single function, 143 /// computed using Semi-NCA algorithm. 144 pub struct DominatorTree { 145 /// DFS spanning tree. 146 stree: SpanningTree, 147 /// List of CFG blocks in postorder. 148 postorder: Vec<Block>, 149 /// Dominator tree nodes. 150 nodes: SecondaryMap<Block, DominatorTreeNode>, 151 152 /// Stack for building the spanning tree. 153 dfs_worklist: Vec<TraversalEvent>, 154 /// Stack used for processing semidominator paths 155 /// in link-eval procedure. 156 eval_worklist: Vec<u32>, 157 158 valid: bool, 159 } 160 161 /// Methods for querying the dominator tree. 162 impl DominatorTree { 163 /// Is `block` reachable from the entry block? is_reachable(&self, block: Block) -> bool164 pub fn is_reachable(&self, block: Block) -> bool { 165 self.nodes[block].pre_number != NOT_VISITED 166 } 167 168 /// Get the CFG post-order of blocks that was used to compute the dominator tree. 169 /// 170 /// Note that this post-order is not updated automatically when the CFG is modified. It is 171 /// computed from scratch and cached by `compute()`. cfg_postorder(&self) -> &[Block]172 pub fn cfg_postorder(&self) -> &[Block] { 173 debug_assert!(self.is_valid()); 174 &self.postorder 175 } 176 177 /// Get an iterator over CFG reverse post-order of blocks used to compute the dominator tree. 178 /// 179 /// Note that the post-order is not updated automatically when the CFG is modified. It is 180 /// computed from scratch and cached by `compute()`. cfg_rpo(&self) -> impl Iterator<Item = &Block>181 pub fn cfg_rpo(&self) -> impl Iterator<Item = &Block> { 182 debug_assert!(self.is_valid()); 183 self.postorder.iter().rev() 184 } 185 186 /// Returns the immediate dominator of `block`. 187 /// 188 /// `block_a` is said to *dominate* `block_b` if all control flow paths from the function 189 /// entry to `block_b` must go through `block_a`. 190 /// 191 /// The *immediate dominator* is the dominator that is closest to `block`. All other dominators 192 /// also dominate the immediate dominator. 193 /// 194 /// This returns `None` if `block` is not reachable from the entry block, or if it is the entry block 195 /// which has no dominators. idom(&self, block: Block) -> Option<Block>196 pub fn idom(&self, block: Block) -> Option<Block> { 197 self.nodes[block].idom.into() 198 } 199 200 /// Returns `true` if `a` dominates `b`. 201 /// 202 /// This means that every control-flow path from the function entry to `b` must go through `a`. 203 /// 204 /// Dominance is ill defined for unreachable blocks. This function can always determine 205 /// dominance for instructions in the same block, but otherwise returns `false` if either block 206 /// is unreachable. 207 /// 208 /// An instruction is considered to dominate itself. 209 /// 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>,210 pub fn dominates<A, B>(&self, a: A, b: B, layout: &Layout) -> bool 211 where 212 A: Into<ProgramPoint>, 213 B: Into<ProgramPoint>, 214 { 215 let a = a.into(); 216 let b = b.into(); 217 match a { 218 ProgramPoint::Block(block_a) => match b { 219 ProgramPoint::Block(block_b) => self.block_dominates(block_a, block_b), 220 ProgramPoint::Inst(inst_b) => { 221 let block_b = layout 222 .inst_block(inst_b) 223 .expect("Instruction not in layout."); 224 self.block_dominates(block_a, block_b) 225 } 226 }, 227 ProgramPoint::Inst(inst_a) => { 228 let block_a: Block = layout 229 .inst_block(inst_a) 230 .expect("Instruction not in layout."); 231 match b { 232 ProgramPoint::Block(block_b) => { 233 block_a != block_b && self.block_dominates(block_a, block_b) 234 } 235 ProgramPoint::Inst(inst_b) => { 236 let block_b = layout 237 .inst_block(inst_b) 238 .expect("Instruction not in layout."); 239 if block_a == block_b { 240 layout.pp_cmp(a, b) != Ordering::Greater 241 } else { 242 self.block_dominates(block_a, block_b) 243 } 244 } 245 } 246 } 247 } 248 } 249 250 /// Returns `true` if `block_a` dominates `block_b`. 251 /// 252 /// A block is considered to dominate itself. 253 /// This uses preorder numbers for O(1) constant time performance. block_dominates(&self, block_a: Block, block_b: Block) -> bool254 pub fn block_dominates(&self, block_a: Block, block_b: Block) -> bool { 255 let na = &self.nodes[block_a]; 256 let nb = &self.nodes[block_b]; 257 na.dom_pre_number <= nb.dom_pre_number && na.dom_pre_max >= nb.dom_pre_max 258 } 259 260 /// Get an iterator over the direct children of `block` in the dominator tree. 261 /// 262 /// These are the blocks whose immediate dominator is `block`, ordered according 263 /// to the CFG reverse post-order. children(&self, block: Block) -> ChildIter<'_>264 pub fn children(&self, block: Block) -> ChildIter<'_> { 265 ChildIter { 266 domtree: self, 267 next: self.nodes[block].child, 268 } 269 } 270 } 271 272 impl DominatorTree { 273 /// Allocate a new blank dominator tree. Use `compute` to compute the dominator tree for a 274 /// function. new() -> Self275 pub fn new() -> Self { 276 Self { 277 stree: SpanningTree::new(), 278 nodes: SecondaryMap::new(), 279 postorder: Vec::new(), 280 dfs_worklist: Vec::new(), 281 eval_worklist: Vec::new(), 282 valid: false, 283 } 284 } 285 286 /// Allocate and compute a dominator tree. with_function(func: &Function, cfg: &ControlFlowGraph) -> Self287 pub fn with_function(func: &Function, cfg: &ControlFlowGraph) -> Self { 288 let block_capacity = func.layout.block_capacity(); 289 let mut domtree = Self { 290 stree: SpanningTree::with_capacity(block_capacity), 291 nodes: SecondaryMap::with_capacity(block_capacity), 292 postorder: Vec::with_capacity(block_capacity), 293 dfs_worklist: Vec::new(), 294 eval_worklist: Vec::new(), 295 valid: false, 296 }; 297 domtree.compute(func, cfg); 298 domtree 299 } 300 301 /// Reset and compute a CFG post-order and dominator tree, 302 /// using Semi-NCA algorithm, described in the paper: 303 /// 304 /// Linear-Time Algorithms for Dominators and Related Problems. 305 /// Loukas Georgiadis, Princeton University, November 2005. 306 /// 307 /// The same algorithm is used by Julia, SpiderMonkey and LLVM, 308 /// the implementation is heavily inspired by them. compute(&mut self, func: &Function, cfg: &ControlFlowGraph)309 pub fn compute(&mut self, func: &Function, cfg: &ControlFlowGraph) { 310 let _tt = timing::domtree(); 311 debug_assert!(cfg.is_valid()); 312 313 self.clear(); 314 self.compute_spanning_tree(func); 315 self.compute_domtree(cfg); 316 self.compute_domtree_preorder(); 317 318 self.valid = true; 319 } 320 321 /// Clear the data structures used to represent the dominator tree. This will leave the tree in 322 /// a state where `is_valid()` returns false. clear(&mut self)323 pub fn clear(&mut self) { 324 self.stree.clear(); 325 self.nodes.clear(); 326 self.postorder.clear(); 327 self.valid = false; 328 } 329 330 /// Check if the dominator tree is in a valid state. 331 /// 332 /// Note that this doesn't perform any kind of validity checks. It simply checks if the 333 /// `compute()` method has been called since the last `clear()`. It does not check that the 334 /// dominator tree is consistent with the CFG. is_valid(&self) -> bool335 pub fn is_valid(&self) -> bool { 336 self.valid 337 } 338 339 /// Reset all internal data structures, build spanning tree 340 /// and compute a post-order of the control flow graph. compute_spanning_tree(&mut self, func: &Function)341 fn compute_spanning_tree(&mut self, func: &Function) { 342 self.nodes.resize(func.dfg.num_blocks()); 343 self.stree.reserve(func.dfg.num_blocks()); 344 345 if let Some(block) = func.layout.entry_block() { 346 self.dfs_worklist.push(TraversalEvent::Enter(0, block)); 347 } 348 349 loop { 350 match self.dfs_worklist.pop() { 351 Some(TraversalEvent::Enter(parent, block)) => { 352 let node = &mut self.nodes[block]; 353 if node.pre_number != NOT_VISITED { 354 continue; 355 } 356 357 self.dfs_worklist.push(TraversalEvent::Exit(block)); 358 359 let pre_number = self.stree.push(parent, block); 360 node.pre_number = pre_number; 361 362 // Use the same traversal heuristics as in traversals.rs. 363 self.dfs_worklist.extend( 364 func.block_successors(block) 365 // Heuristic: chase the children in reverse. This puts 366 // the first successor block first in the postorder, all 367 // other things being equal, which tends to prioritize 368 // loop backedges over out-edges, putting the edge-block 369 // closer to the loop body and minimizing live-ranges in 370 // linear instruction space. This heuristic doesn't have 371 // any effect on the computation of dominators, and is 372 // purely for other consumers of the postorder we cache 373 // here. 374 .rev() 375 // A simple optimization: push less items to the stack. 376 .filter(|successor| self.nodes[*successor].pre_number == NOT_VISITED) 377 .map(|successor| TraversalEvent::Enter(pre_number, successor)), 378 ); 379 } 380 Some(TraversalEvent::Exit(block)) => self.postorder.push(block), 381 None => break, 382 } 383 } 384 } 385 386 /// Eval-link procedure from the paper. 387 /// For a predecessor V of node W returns V if V < W, otherwise the minimum of sdom(U), 388 /// where U > W and U is on a semi-dominator path for W in CFG. 389 /// Use path compression to bring complexity down to O(m*log(n)). eval(&mut self, v: u32, last_linked: u32) -> u32390 fn eval(&mut self, v: u32, last_linked: u32) -> u32 { 391 if self.stree[v].ancestor < last_linked { 392 return self.stree[v].label; 393 } 394 395 // Follow semi-dominator path. 396 let mut root = v; 397 loop { 398 self.eval_worklist.push(root); 399 root = self.stree[root].ancestor; 400 401 if self.stree[root].ancestor < last_linked { 402 break; 403 } 404 } 405 406 let mut prev = root; 407 let root = self.stree[prev].ancestor; 408 409 // Perform path compression. Point all ancestors to the root 410 // and propagate minimal sdom(U) value from ancestors to children. 411 while let Some(curr) = self.eval_worklist.pop() { 412 if self.stree[prev].label < self.stree[curr].label { 413 self.stree[curr].label = self.stree[prev].label; 414 } 415 416 self.stree[curr].ancestor = root; 417 prev = curr; 418 } 419 420 self.stree[v].label 421 } 422 compute_domtree(&mut self, cfg: &ControlFlowGraph)423 fn compute_domtree(&mut self, cfg: &ControlFlowGraph) { 424 // Compute semi-dominators. 425 for w in (1..self.stree.len() as u32).rev() { 426 let w_node = &mut self.stree[w]; 427 let block = w_node.block.expect("Virtual root must have been excluded"); 428 let mut semi = w_node.ancestor; 429 430 let last_linked = w + 1; 431 432 for pred in cfg 433 .pred_iter(block) 434 .map(|pred: BlockPredecessor| pred.block) 435 { 436 // Skip unreachable nodes. 437 if self.nodes[pred].pre_number == NOT_VISITED { 438 continue; 439 } 440 441 let semi_candidate = self.eval(self.nodes[pred].pre_number, last_linked); 442 semi = core::cmp::min(semi, semi_candidate); 443 } 444 445 let w_node = &mut self.stree[w]; 446 w_node.label = semi; 447 w_node.semi = semi; 448 } 449 450 // Compute immediate dominators. 451 for v in 1..self.stree.len() as u32 { 452 let semi = self.stree[v].semi; 453 let block = self.stree[v] 454 .block 455 .expect("Virtual root must have been excluded"); 456 let mut idom = self.stree[v].idom; 457 458 while idom > semi { 459 idom = self.stree[idom].idom; 460 } 461 462 self.stree[v].idom = idom; 463 464 self.nodes[block].idom = self.stree[idom].block; 465 } 466 } 467 468 /// Compute dominator tree preorder information. 469 /// 470 /// This populates child/sibling links and preorder numbers for fast dominance checks. compute_domtree_preorder(&mut self)471 fn compute_domtree_preorder(&mut self) { 472 // Step 1: Populate the child and sibling links. 473 // 474 // By following the CFG post-order and pushing to the front of the lists, we make sure that 475 // sibling lists are ordered according to the CFG reverse post-order. 476 for &block in &self.postorder { 477 if let Some(idom) = self.idom(block) { 478 let sib = mem::replace(&mut self.nodes[idom].child, block.into()); 479 self.nodes[block].sibling = sib; 480 } else { 481 // The only block without an immediate dominator is the entry. 482 self.dfs_worklist.push(TraversalEvent::Enter(0, block)); 483 } 484 } 485 486 // Step 2. Assign pre-order numbers from a DFS of the dominator tree. 487 debug_assert!(self.dfs_worklist.len() <= 1); 488 let mut n = 0; 489 while let Some(event) = self.dfs_worklist.pop() { 490 if let TraversalEvent::Enter(_, block) = event { 491 n += 1; 492 let node = &mut self.nodes[block]; 493 node.dom_pre_number = n; 494 node.dom_pre_max = n; 495 if let Some(sibling) = node.sibling.expand() { 496 self.dfs_worklist.push(TraversalEvent::Enter(0, sibling)); 497 } 498 if let Some(child) = node.child.expand() { 499 self.dfs_worklist.push(TraversalEvent::Enter(0, child)); 500 } 501 } 502 } 503 504 // Step 3. Propagate the `dom_pre_max` numbers up the tree. 505 // The CFG post-order is topologically ordered w.r.t. dominance so a node comes after all 506 // its dominator tree children. 507 for &block in &self.postorder { 508 if let Some(idom) = self.idom(block) { 509 let pre_max = cmp::max(self.nodes[block].dom_pre_max, self.nodes[idom].dom_pre_max); 510 self.nodes[idom].dom_pre_max = pre_max; 511 } 512 } 513 } 514 } 515 516 /// An iterator that enumerates the direct children of a block in the dominator tree. 517 pub struct ChildIter<'a> { 518 domtree: &'a DominatorTree, 519 next: PackedOption<Block>, 520 } 521 522 impl<'a> Iterator for ChildIter<'a> { 523 type Item = Block; 524 next(&mut self) -> Option<Block>525 fn next(&mut self) -> Option<Block> { 526 let n = self.next.expand(); 527 if let Some(block) = n { 528 self.next = self.domtree.nodes[block].sibling; 529 } 530 n 531 } 532 } 533 534 #[cfg(test)] 535 mod tests { 536 use super::*; 537 use crate::cursor::{Cursor, FuncCursor}; 538 use crate::ir::types::*; 539 use crate::ir::{InstBuilder, TrapCode}; 540 541 #[test] empty()542 fn empty() { 543 let func = Function::new(); 544 let cfg = ControlFlowGraph::with_function(&func); 545 debug_assert!(cfg.is_valid()); 546 let dtree = DominatorTree::with_function(&func, &cfg); 547 assert_eq!(0, dtree.nodes.keys().count()); 548 assert_eq!(dtree.cfg_postorder(), &[]); 549 } 550 551 #[test] unreachable_node()552 fn unreachable_node() { 553 let mut func = Function::new(); 554 let block0 = func.dfg.make_block(); 555 let v0 = func.dfg.append_block_param(block0, I32); 556 let block1 = func.dfg.make_block(); 557 let block2 = func.dfg.make_block(); 558 let trap_block = func.dfg.make_block(); 559 560 let mut cur = FuncCursor::new(&mut func); 561 562 cur.insert_block(block0); 563 cur.ins().brif(v0, block2, &[], trap_block, &[]); 564 565 cur.insert_block(trap_block); 566 cur.ins().trap(TrapCode::unwrap_user(1)); 567 568 cur.insert_block(block1); 569 let v1 = cur.ins().iconst(I32, 1); 570 let v2 = cur.ins().iadd(v0, v1); 571 cur.ins().jump(block0, &[v2.into()]); 572 573 cur.insert_block(block2); 574 cur.ins().return_(&[v0]); 575 576 let cfg = ControlFlowGraph::with_function(cur.func); 577 let dt = DominatorTree::with_function(cur.func, &cfg); 578 579 // Fall-through-first, prune-at-source DFT: 580 // 581 // block0 { 582 // brif block2 { 583 // trap 584 // block2 { 585 // return 586 // } block2 587 // } block0 588 assert_eq!(dt.cfg_postorder(), &[block2, trap_block, block0]); 589 590 let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); 591 assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); 592 assert!(!dt.dominates(block0, v2_def, &cur.func.layout)); 593 594 assert!(dt.block_dominates(block0, block0)); 595 assert!(!dt.block_dominates(block0, block1)); 596 assert!(dt.block_dominates(block0, block2)); 597 assert!(!dt.block_dominates(block1, block0)); 598 assert!(dt.block_dominates(block1, block1)); 599 assert!(!dt.block_dominates(block1, block2)); 600 assert!(!dt.block_dominates(block2, block0)); 601 assert!(!dt.block_dominates(block2, block1)); 602 assert!(dt.block_dominates(block2, block2)); 603 } 604 605 #[test] non_zero_entry_block()606 fn non_zero_entry_block() { 607 let mut func = Function::new(); 608 let block0 = func.dfg.make_block(); 609 let block1 = func.dfg.make_block(); 610 let block2 = func.dfg.make_block(); 611 let block3 = func.dfg.make_block(); 612 let cond = func.dfg.append_block_param(block3, I32); 613 614 let mut cur = FuncCursor::new(&mut func); 615 616 cur.insert_block(block3); 617 let jmp_block3_block1 = cur.ins().jump(block1, &[]); 618 619 cur.insert_block(block1); 620 let br_block1_block0_block2 = cur.ins().brif(cond, block0, &[], block2, &[]); 621 622 cur.insert_block(block2); 623 cur.ins().jump(block0, &[]); 624 625 cur.insert_block(block0); 626 627 let cfg = ControlFlowGraph::with_function(cur.func); 628 let dt = DominatorTree::with_function(cur.func, &cfg); 629 630 // Fall-through-first, prune-at-source DFT: 631 // 632 // block3 { 633 // block3:jump block1 { 634 // block1 { 635 // block1:brif block0 { 636 // block1:jump block2 { 637 // block2 { 638 // block2:jump block0 (seen) 639 // } block2 640 // } block1:jump block2 641 // block0 { 642 // } block0 643 // } block1:brif block0 644 // } block1 645 // } block3:jump block1 646 // } block3 647 648 assert_eq!(dt.cfg_postorder(), &[block0, block2, block1, block3]); 649 650 assert_eq!(cur.func.layout.entry_block().unwrap(), block3); 651 assert_eq!(dt.idom(block3), None); 652 assert_eq!(dt.idom(block1).unwrap(), block3); 653 assert_eq!(dt.idom(block2).unwrap(), block1); 654 assert_eq!(dt.idom(block0).unwrap(), block1); 655 656 assert!(dt.dominates( 657 br_block1_block0_block2, 658 br_block1_block0_block2, 659 &cur.func.layout 660 )); 661 assert!(!dt.dominates(br_block1_block0_block2, jmp_block3_block1, &cur.func.layout)); 662 assert!(dt.dominates(jmp_block3_block1, br_block1_block0_block2, &cur.func.layout)); 663 } 664 665 #[test] backwards_layout()666 fn backwards_layout() { 667 let mut func = Function::new(); 668 let block0 = func.dfg.make_block(); 669 let block1 = func.dfg.make_block(); 670 let block2 = func.dfg.make_block(); 671 672 let mut cur = FuncCursor::new(&mut func); 673 674 cur.insert_block(block0); 675 let jmp02 = cur.ins().jump(block2, &[]); 676 677 cur.insert_block(block1); 678 let trap = cur.ins().trap(TrapCode::unwrap_user(5)); 679 680 cur.insert_block(block2); 681 let jmp21 = cur.ins().jump(block1, &[]); 682 683 let cfg = ControlFlowGraph::with_function(cur.func); 684 let dt = DominatorTree::with_function(cur.func, &cfg); 685 686 assert_eq!(cur.func.layout.entry_block(), Some(block0)); 687 assert_eq!(dt.idom(block0), None); 688 assert_eq!(dt.idom(block1), Some(block2)); 689 assert_eq!(dt.idom(block2), Some(block0)); 690 691 assert!(dt.dominates(block0, block0, &cur.func.layout)); 692 assert!(dt.dominates(block0, jmp02, &cur.func.layout)); 693 assert!(dt.dominates(block0, block1, &cur.func.layout)); 694 assert!(dt.dominates(block0, trap, &cur.func.layout)); 695 assert!(dt.dominates(block0, block2, &cur.func.layout)); 696 assert!(dt.dominates(block0, jmp21, &cur.func.layout)); 697 698 assert!(!dt.dominates(jmp02, block0, &cur.func.layout)); 699 assert!(dt.dominates(jmp02, jmp02, &cur.func.layout)); 700 assert!(dt.dominates(jmp02, block1, &cur.func.layout)); 701 assert!(dt.dominates(jmp02, trap, &cur.func.layout)); 702 assert!(dt.dominates(jmp02, block2, &cur.func.layout)); 703 assert!(dt.dominates(jmp02, jmp21, &cur.func.layout)); 704 705 assert!(!dt.dominates(block1, block0, &cur.func.layout)); 706 assert!(!dt.dominates(block1, jmp02, &cur.func.layout)); 707 assert!(dt.dominates(block1, block1, &cur.func.layout)); 708 assert!(dt.dominates(block1, trap, &cur.func.layout)); 709 assert!(!dt.dominates(block1, block2, &cur.func.layout)); 710 assert!(!dt.dominates(block1, jmp21, &cur.func.layout)); 711 712 assert!(!dt.dominates(trap, block0, &cur.func.layout)); 713 assert!(!dt.dominates(trap, jmp02, &cur.func.layout)); 714 assert!(!dt.dominates(trap, block1, &cur.func.layout)); 715 assert!(dt.dominates(trap, trap, &cur.func.layout)); 716 assert!(!dt.dominates(trap, block2, &cur.func.layout)); 717 assert!(!dt.dominates(trap, jmp21, &cur.func.layout)); 718 719 assert!(!dt.dominates(block2, block0, &cur.func.layout)); 720 assert!(!dt.dominates(block2, jmp02, &cur.func.layout)); 721 assert!(dt.dominates(block2, block1, &cur.func.layout)); 722 assert!(dt.dominates(block2, trap, &cur.func.layout)); 723 assert!(dt.dominates(block2, block2, &cur.func.layout)); 724 assert!(dt.dominates(block2, jmp21, &cur.func.layout)); 725 726 assert!(!dt.dominates(jmp21, block0, &cur.func.layout)); 727 assert!(!dt.dominates(jmp21, jmp02, &cur.func.layout)); 728 assert!(dt.dominates(jmp21, block1, &cur.func.layout)); 729 assert!(dt.dominates(jmp21, trap, &cur.func.layout)); 730 assert!(!dt.dominates(jmp21, block2, &cur.func.layout)); 731 assert!(dt.dominates(jmp21, jmp21, &cur.func.layout)); 732 } 733 734 #[test] insts_same_block()735 fn insts_same_block() { 736 let mut func = Function::new(); 737 let block0 = func.dfg.make_block(); 738 739 let mut cur = FuncCursor::new(&mut func); 740 741 cur.insert_block(block0); 742 let v1 = cur.ins().iconst(I32, 1); 743 let v2 = cur.ins().iadd(v1, v1); 744 let v3 = cur.ins().iadd(v2, v2); 745 cur.ins().return_(&[]); 746 747 let cfg = ControlFlowGraph::with_function(cur.func); 748 let dt = DominatorTree::with_function(cur.func, &cfg); 749 750 let v1_def = cur.func.dfg.value_def(v1).unwrap_inst(); 751 let v2_def = cur.func.dfg.value_def(v2).unwrap_inst(); 752 let v3_def = cur.func.dfg.value_def(v3).unwrap_inst(); 753 754 assert!(dt.dominates(v1_def, v2_def, &cur.func.layout)); 755 assert!(dt.dominates(v2_def, v3_def, &cur.func.layout)); 756 assert!(dt.dominates(v1_def, v3_def, &cur.func.layout)); 757 758 assert!(!dt.dominates(v2_def, v1_def, &cur.func.layout)); 759 assert!(!dt.dominates(v3_def, v2_def, &cur.func.layout)); 760 assert!(!dt.dominates(v3_def, v1_def, &cur.func.layout)); 761 762 assert!(dt.dominates(v2_def, v2_def, &cur.func.layout)); 763 assert!(dt.dominates(block0, block0, &cur.func.layout)); 764 765 assert!(dt.dominates(block0, v1_def, &cur.func.layout)); 766 assert!(dt.dominates(block0, v2_def, &cur.func.layout)); 767 assert!(dt.dominates(block0, v3_def, &cur.func.layout)); 768 769 assert!(!dt.dominates(v1_def, block0, &cur.func.layout)); 770 assert!(!dt.dominates(v2_def, block0, &cur.func.layout)); 771 assert!(!dt.dominates(v3_def, block0, &cur.func.layout)); 772 } 773 } 774