| /* |
| * Derives from the dominator tree implementation in regalloc.rs, which is |
| * licensed under the Apache Public License 2.0 with LLVM Exception. See: |
| * https://github.com/bytecodealliance/regalloc.rs |
| */ |
| |
| // This is an implementation of the algorithm described in |
| // |
| // A Simple, Fast Dominance Algorithm |
| // Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy |
| // Department of Computer Science, Rice University, Houston, Texas, USA |
| // TR-06-33870 |
| // https://www.cs.rice.edu/~keith/EMBED/dom.pdf |
| |
| use alloc::vec; |
| use alloc::vec::Vec; |
| |
| use crate::Block; |
| |
| // Helper |
| fn merge_sets( |
| idom: &[Block], // map from Block to Block |
| block_to_rpo: &[Option<u32>], |
| mut node1: Block, |
| mut node2: Block, |
| ) -> Block { |
| while node1 != node2 { |
| if node1.is_invalid() || node2.is_invalid() { |
| return Block::invalid(); |
| } |
| let rpo1 = block_to_rpo[node1.index()].unwrap(); |
| let rpo2 = block_to_rpo[node2.index()].unwrap(); |
| if rpo1 > rpo2 { |
| node1 = idom[node1.index()]; |
| } else if rpo2 > rpo1 { |
| node2 = idom[node2.index()]; |
| } |
| } |
| debug_assert!(node1 == node2); |
| node1 |
| } |
| |
| pub fn calculate<'a, PredFn: Fn(Block) -> &'a [Block]>( |
| num_blocks: usize, |
| preds: PredFn, |
| post_ord: &[Block], |
| start: Block, |
| ) -> Vec<Block> { |
| // We have post_ord, which is the postorder sequence. |
| |
| // Compute maps from RPO to block number and vice-versa. |
| let mut block_to_rpo = vec![None; num_blocks]; |
| block_to_rpo.resize(num_blocks, None); |
| for (i, rpo_block) in post_ord.iter().rev().enumerate() { |
| block_to_rpo[rpo_block.index()] = Some(i as u32); |
| } |
| |
| let mut idom = vec![Block::invalid(); num_blocks]; |
| |
| // The start node must have itself as a parent. |
| idom[start.index()] = start; |
| |
| let mut changed = true; |
| while changed { |
| changed = false; |
| // Consider blocks in reverse postorder. Skip any that are unreachable. |
| for &node in post_ord.iter().rev() { |
| let rponum = block_to_rpo[node.index()].unwrap(); |
| |
| let mut parent = Block::invalid(); |
| for &pred in preds(node).iter() { |
| let pred_rpo = match block_to_rpo[pred.index()] { |
| Some(r) => r, |
| None => { |
| // Skip unreachable preds. |
| continue; |
| } |
| }; |
| if pred_rpo < rponum { |
| parent = pred; |
| break; |
| } |
| } |
| |
| if parent.is_valid() { |
| for &pred in preds(node).iter() { |
| if pred == parent { |
| continue; |
| } |
| if idom[pred.index()].is_invalid() { |
| continue; |
| } |
| parent = merge_sets(&idom, &block_to_rpo[..], parent, pred); |
| } |
| } |
| |
| if parent.is_valid() && parent != idom[node.index()] { |
| idom[node.index()] = parent; |
| changed = true; |
| } |
| } |
| } |
| |
| // Now set the start node's dominator-tree parent to "invalid"; |
| // this allows the loop in `dominates` to terminate. |
| idom[start.index()] = Block::invalid(); |
| |
| idom |
| } |
| |
| pub fn dominates(idom: &[Block], a: Block, mut b: Block) -> bool { |
| loop { |
| if a == b { |
| return true; |
| } |
| if b.is_invalid() { |
| return false; |
| } |
| b = idom[b.index()]; |
| } |
| } |