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