Start node has no immediate dominator

Change the immediate_dominator return type to Option, and use None to
indicate that node has no immediate dominator.

Also fix the issue where the start node would be returned as its own
immediate dominator.
This commit is contained in:
Tomasz Miąsko 2023-05-14 00:00:00 +00:00
parent 3603a84a3d
commit f16d2b1629
3 changed files with 23 additions and 15 deletions

View File

@ -164,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if let Some(root) = post_contract_node.get(&bb) { if let Some(root) = post_contract_node.get(&bb) {
break *root; break *root;
} }
let parent = doms.immediate_dominator(bb); let parent = doms.immediate_dominator(bb).unwrap();
dom_path.push(bb); dom_path.push(bb);
if !self.body.basic_blocks[parent].is_cleanup { if !self.body.basic_blocks[parent].is_cleanup {
break bb; break bb;

View File

@ -242,7 +242,9 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]); immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
} }
Dominators { post_order_rank, immediate_dominators } let start_node = graph.start_node();
immediate_dominators[start_node] = None;
Dominators { start_node, post_order_rank, immediate_dominators }
} }
/// Evaluate the link-eval virtual forest, providing the currently minimum semi /// Evaluate the link-eval virtual forest, providing the currently minimum semi
@ -308,6 +310,7 @@ fn compress(
/// Tracks the list of dominators for each node. /// Tracks the list of dominators for each node.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Dominators<N: Idx> { pub struct Dominators<N: Idx> {
start_node: N,
post_order_rank: IndexVec<N, usize>, post_order_rank: IndexVec<N, usize>,
// Even though we track only the immediate dominator of each node, it's // Even though we track only the immediate dominator of each node, it's
// possible to get its full list of dominators by looking up the dominator // possible to get its full list of dominators by looking up the dominator
@ -316,14 +319,14 @@ pub struct Dominators<N: Idx> {
} }
impl<Node: Idx> Dominators<Node> { impl<Node: Idx> Dominators<Node> {
/// Whether the given Node has an immediate dominator. /// Returns true if node is reachable from the start node.
pub fn is_reachable(&self, node: Node) -> bool { pub fn is_reachable(&self, node: Node) -> bool {
self.immediate_dominators[node].is_some() node == self.start_node || self.immediate_dominators[node].is_some()
} }
pub fn immediate_dominator(&self, node: Node) -> Node { /// Returns the immediate dominator of node, if any.
assert!(self.is_reachable(node), "node {node:?} is not reachable"); pub fn immediate_dominator(&self, node: Node) -> Option<Node> {
self.immediate_dominators[node].unwrap() self.immediate_dominators[node]
} }
/// Provides an iterator over each dominator up the CFG, for the given Node. /// Provides an iterator over each dominator up the CFG, for the given Node.
@ -357,12 +360,7 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(node) = self.node { if let Some(node) = self.node {
let dom = self.dominators.immediate_dominator(node); self.node = self.dominators.immediate_dominator(node);
if dom == node {
self.node = None; // reached the root
} else {
self.node = Some(dom);
}
Some(node) Some(node)
} else { } else {
None None

View File

@ -8,7 +8,7 @@ fn diamond() {
let dominators = dominators(&graph); let dominators = dominators(&graph);
let immediate_dominators = &dominators.immediate_dominators; let immediate_dominators = &dominators.immediate_dominators;
assert_eq!(immediate_dominators[0], Some(0)); assert_eq!(immediate_dominators[0], None);
assert_eq!(immediate_dominators[1], Some(0)); assert_eq!(immediate_dominators[1], Some(0));
assert_eq!(immediate_dominators[2], Some(0)); assert_eq!(immediate_dominators[2], Some(0));
assert_eq!(immediate_dominators[3], Some(0)); assert_eq!(immediate_dominators[3], Some(0));
@ -30,7 +30,7 @@ fn paper() {
assert_eq!(immediate_dominators[3], Some(6)); assert_eq!(immediate_dominators[3], Some(6));
assert_eq!(immediate_dominators[4], Some(6)); assert_eq!(immediate_dominators[4], Some(6));
assert_eq!(immediate_dominators[5], Some(6)); assert_eq!(immediate_dominators[5], Some(6));
assert_eq!(immediate_dominators[6], Some(6)); assert_eq!(immediate_dominators[6], None);
} }
#[test] #[test]
@ -43,3 +43,13 @@ fn paper_slt() {
dominators(&graph); dominators(&graph);
} }
#[test]
fn immediate_dominator() {
let graph = TestGraph::new(1, &[(1, 2), (2, 3)]);
let dominators = dominators(&graph);
assert_eq!(dominators.immediate_dominator(0), None);
assert_eq!(dominators.immediate_dominator(1), None);
assert_eq!(dominators.immediate_dominator(2), Some(1));
assert_eq!(dominators.immediate_dominator(3), Some(2));
}