1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use super::iterate::reverse_post_order;
use super::ControlFlowGraph;
use rustc_index::vec::{Idx, IndexVec};
use std::cmp::Ordering;
#[cfg(test)]
mod tests;
pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
let start_node = graph.start_node();
let rpo = reverse_post_order(&graph, start_node);
dominators_given_rpo(graph, &rpo)
}
fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Dominators<G::Node> {
let start_node = graph.start_node();
assert_eq!(rpo[0], start_node);
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
for (index, node) in rpo.iter().rev().cloned().enumerate() {
post_order_rank[node] = index;
}
let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
immediate_dominators[start_node] = Some(start_node);
let mut changed = true;
while changed {
changed = false;
for &node in &rpo[1..] {
let mut new_idom = None;
for pred in graph.predecessors(node) {
if immediate_dominators[pred].is_some() {
new_idom = Some(if let Some(new_idom) = new_idom {
intersect(&post_order_rank, &immediate_dominators, new_idom, pred)
} else {
pred
});
}
}
if new_idom != immediate_dominators[node] {
immediate_dominators[node] = new_idom;
changed = true;
}
}
}
Dominators { post_order_rank, immediate_dominators }
}
fn intersect<Node: Idx>(
post_order_rank: &IndexVec<Node, usize>,
immediate_dominators: &IndexVec<Node, Option<Node>>,
mut node1: Node,
mut node2: Node,
) -> Node {
while node1 != node2 {
while post_order_rank[node1] < post_order_rank[node2] {
node1 = immediate_dominators[node1].unwrap();
}
while post_order_rank[node2] < post_order_rank[node1] {
node2 = immediate_dominators[node2].unwrap();
}
}
node1
}
#[derive(Clone, Debug)]
pub struct Dominators<N: Idx> {
post_order_rank: IndexVec<N, usize>,
immediate_dominators: IndexVec<N, Option<N>>,
}
impl<Node: Idx> Dominators<Node> {
pub fn dummy() -> Self {
Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() }
}
pub fn is_reachable(&self, node: Node) -> bool {
self.immediate_dominators[node].is_some()
}
pub fn immediate_dominator(&self, node: Node) -> Node {
assert!(self.is_reachable(node), "node {:?} is not reachable", node);
self.immediate_dominators[node].unwrap()
}
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
assert!(self.is_reachable(node), "node {:?} is not reachable", node);
Iter { dominators: self, node: Some(node) }
}
pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
self.dominators(node).any(|n| n == dom)
}
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
}
}
pub struct Iter<'dom, Node: Idx> {
dominators: &'dom Dominators<Node>,
node: Option<Node>,
}
impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
type Item = Node;
fn next(&mut self) -> Option<Self::Item> {
if let Some(node) = self.node {
let dom = self.dominators.immediate_dominator(node);
if dom == node {
self.node = None;
} else {
self.node = Some(dom);
}
Some(node)
} else {
None
}
}
}