1use crate::entity::SecondaryMap;
4use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
5use crate::ir::{Block, Function, Layout, ProgramPoint};
6use crate::packed_option::PackedOption;
7use crate::timing;
8use alloc::vec::Vec;
9use core::cmp;
10use core::cmp::Ordering;
11use core::mem;
12
13mod simple;
14
15pub use simple::SimpleDominatorTree;
16
17#[derive(Clone, Default)]
19struct SpanningTreeNode {
20 block: PackedOption<Block>,
22 ancestor: u32,
25 label: u32,
29 semi: u32,
31 idom: u32,
34}
35
36const NOT_VISITED: u32 = 0;
38
39#[derive(Clone, Default)]
46struct SpanningTree {
47 nodes: Vec<SpanningTreeNode>,
48}
49
50impl SpanningTree {
51 fn new() -> Self {
52 Self {
54 nodes: vec![Default::default()],
55 }
56 }
57
58 fn with_capacity(capacity: usize) -> Self {
59 let mut nodes = Vec::with_capacity(capacity + 1);
61 nodes.push(Default::default());
62 Self { nodes }
63 }
64
65 fn len(&self) -> usize {
66 self.nodes.len()
67 }
68
69 fn reserve(&mut self, capacity: usize) {
70 self.nodes.reserve(capacity);
72 }
73
74 fn clear(&mut self) {
75 self.nodes.resize(1, Default::default());
76 }
77
78 fn push(&mut self, ancestor: u32, block: Block) -> u32 {
80 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
97impl std::ops::Index<u32> for SpanningTree {
98 type Output = SpanningTreeNode;
99
100 fn index(&self, idx: u32) -> &Self::Output {
101 &self.nodes[idx as usize]
102 }
103}
104
105impl std::ops::IndexMut<u32> for SpanningTree {
106 fn index_mut(&mut self, idx: u32) -> &mut Self::Output {
107 &mut self.nodes[idx as usize]
108 }
109}
110
111enum TraversalEvent {
115 Enter(u32, Block),
116 Exit(Block),
117}
118
119#[derive(Clone, Default)]
121struct DominatorTreeNode {
122 idom: PackedOption<Block>,
124 pre_number: u32,
126
127 child: PackedOption<Block>,
129
130 sibling: PackedOption<Block>,
132
133 dom_pre_number: u32,
136
137 dom_pre_max: u32,
140}
141
142pub struct DominatorTree {
145 stree: SpanningTree,
147 postorder: Vec<Block>,
149 nodes: SecondaryMap<Block, DominatorTreeNode>,
151
152 dfs_worklist: Vec<TraversalEvent>,
154 eval_worklist: Vec<u32>,
157
158 valid: bool,
159}
160
161impl DominatorTree {
163 pub fn is_reachable(&self, block: Block) -> bool {
165 self.nodes[block].pre_number != NOT_VISITED
166 }
167
168 pub fn cfg_postorder(&self) -> &[Block] {
173 debug_assert!(self.is_valid());
174 &self.postorder
175 }
176
177 pub fn cfg_rpo(&self) -> impl Iterator<Item = &Block> {
182 debug_assert!(self.is_valid());
183 self.postorder.iter().rev()
184 }
185
186 pub fn idom(&self, block: Block) -> Option<Block> {
197 self.nodes[block].idom.into()
198 }
199
200 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 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 pub fn children(&self, block: Block) -> ChildIter<'_> {
265 ChildIter {
266 domtree: self,
267 next: self.nodes[block].child,
268 }
269 }
270}
271
272impl DominatorTree {
273 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 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 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 pub fn clear(&mut self) {
324 self.stree.clear();
325 self.nodes.clear();
326 self.postorder.clear();
327 self.valid = false;
328 }
329
330 pub fn is_valid(&self) -> bool {
336 self.valid
337 }
338
339 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 self.dfs_worklist.extend(
364 func.block_successors(block)
365 .rev()
375 .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 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 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 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
423 fn compute_domtree(&mut self, cfg: &ControlFlowGraph) {
424 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 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 = std::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 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 fn compute_domtree_preorder(&mut self) {
472 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 self.dfs_worklist.push(TraversalEvent::Enter(0, block));
483 }
484 }
485
486 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 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
516pub struct ChildIter<'a> {
518 domtree: &'a DominatorTree,
519 next: PackedOption<Block>,
520}
521
522impl<'a> Iterator for ChildIter<'a> {
523 type Item = Block;
524
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)]
535mod tests {
536 use super::*;
537 use crate::cursor::{Cursor, FuncCursor};
538 use crate::ir::types::*;
539 use crate::ir::{InstBuilder, TrapCode};
540
541 #[test]
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]
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 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]
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 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]
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]
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}