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