1 //! Finding the dominators in a control-flow graph.
3 //! Algorithm based on Loukas Georgiadis,
4 //! "Linear-Time Algorithms for Dominators and Related Problems",
5 //! <ftp://ftp.cs.princeton.edu/techreports/2005/737.pdf>
7 //! Additionally useful is the original Lengauer-Tarjan paper on this subject,
8 //! "A Fast Algorithm for Finding Dominators in a Flowgraph"
9 //! Thomas Lengauer and Robert Endre Tarjan.
10 //! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
12 use super::ControlFlowGraph;
13 use rustc_index::vec::{Idx, IndexVec};
14 use std::cmp::Ordering;
19 struct PreOrderFrame<Iter> {
20 pre_order_idx: PreorderIndex,
24 rustc_index::newtype_index! {
25 struct PreorderIndex { .. }
28 pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
29 // compute the post order index (rank) for each node
30 let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
32 // We allocate capacity for the full set of nodes, because most of the time
33 // most of the nodes *are* reachable.
34 let mut parent: IndexVec<PreorderIndex, PreorderIndex> =
35 IndexVec::with_capacity(graph.num_nodes());
37 let mut stack = vec![PreOrderFrame {
38 pre_order_idx: PreorderIndex::new(0),
39 iter: graph.successors(graph.start_node()),
41 let mut pre_order_to_real: IndexVec<PreorderIndex, G::Node> =
42 IndexVec::with_capacity(graph.num_nodes());
43 let mut real_to_pre_order: IndexVec<G::Node, Option<PreorderIndex>> =
44 IndexVec::from_elem_n(None, graph.num_nodes());
45 pre_order_to_real.push(graph.start_node());
46 parent.push(PreorderIndex::new(0)); // the parent of the root node is the root for now.
47 real_to_pre_order[graph.start_node()] = Some(PreorderIndex::new(0));
48 let mut post_order_idx = 0;
50 // Traverse the graph, collecting a number of things:
52 // * Preorder mapping (to it, and back to the actual ordering)
53 // * Postorder mapping (used exclusively for rank_partial_cmp on the final product)
54 // * Parents for each vertex in the preorder tree
56 // These are all done here rather than through one of the 'standard'
57 // graph traversals to help make this fast.
58 'recurse: while let Some(frame) = stack.last_mut() {
59 while let Some(successor) = frame.iter.next() {
60 if real_to_pre_order[successor].is_none() {
61 let pre_order_idx = pre_order_to_real.push(successor);
62 real_to_pre_order[successor] = Some(pre_order_idx);
63 parent.push(frame.pre_order_idx);
64 stack.push(PreOrderFrame { pre_order_idx, iter: graph.successors(successor) });
69 post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx;
75 let reachable_vertices = pre_order_to_real.len();
77 let mut idom = IndexVec::from_elem_n(PreorderIndex::new(0), reachable_vertices);
78 let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices);
79 let mut label = semi.clone();
80 let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices);
81 let mut lastlinked = None;
83 // We loop over vertices in reverse preorder. This implements the pseudocode
84 // of the simple Lengauer-Tarjan algorithm. A few key facts are noted here
85 // which are helpful for understanding the code (full proofs and such are
86 // found in various papers, including one cited at the top of this file).
88 // For each vertex w (which is not the root),
89 // * semi[w] is a proper ancestor of the vertex w (i.e., semi[w] != w)
90 // * idom[w] is an ancestor of semi[w] (i.e., idom[w] may equal semi[w])
92 // An immediate dominator of w (idom[w]) is a vertex v where v dominates w
93 // and every other dominator of w dominates v. (Every vertex except the root has
94 // a unique immediate dominator.)
96 // A semidominator for a given vertex w (semi[w]) is the vertex v with minimum
97 // preorder number such that there exists a path from v to w in which all elements (other than w) have
98 // preorder numbers greater than w (i.e., this path is not the tree path to
100 for w in (PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices)).rev() {
101 // Optimization: process buckets just once, at the start of the
102 // iteration. Do not explicitly empty the bucket (even though it will
103 // not be used again), to save some instructions.
105 // The bucket here contains the vertices whose semidominator is the
106 // vertex w, which we are guaranteed to have found: all vertices who can
107 // be semidominated by w must have a preorder number exceeding w, so
108 // they have been placed in the bucket.
110 // We compute a partial set of immediate dominators here.
112 for &v in bucket[z].iter() {
113 // This uses the result of Lemma 5 from section 2 from the original
114 // 1979 paper, to compute either the immediate or relative dominator
115 // for a given vertex v.
117 // eval returns a vertex y, for which semi[y] is minimum among
118 // vertices semi[v] +> y *> v. Note that semi[v] = z as we're in the
121 // Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v].
122 // If semi[y] = semi[v], though, idom[v] = semi[v].
124 // Using this, we can either set idom[v] to be:
125 // * semi[v] (i.e. z), if semi[y] is z
126 // * idom[y], otherwise
128 // We don't directly set to idom[y] though as it's not necessarily
129 // known yet. The second preorder traversal will cleanup by updating
130 // the idom for any that were missed in this pass.
131 let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
132 idom[v] = if semi[y] < z { y } else { z };
135 // This loop computes the semi[w] for w.
137 for v in graph.predecessors(pre_order_to_real[w]) {
138 let v = real_to_pre_order[v].unwrap();
140 // eval returns a vertex x from which semi[x] is minimum among
141 // vertices semi[v] +> x *> v.
143 // From Lemma 4 from section 2, we know that the semidominator of a
144 // vertex w is the minimum (by preorder number) vertex of the
147 // * direct predecessors of w with preorder number less than w
148 // * semidominators of u such that u > w and there exists (v, w)
151 // This loop therefore identifies such a minima. Note that any
152 // semidominator path to w must have all but the first vertex go
153 // through vertices numbered greater than w, so the reverse preorder
154 // traversal we are using guarantees that all of the information we
155 // might need is available at this point.
157 // The eval call will give us semi[x], which is either:
159 // * v itself, if v has not yet been processed
160 // * A possible 'best' semidominator for w.
161 let x = eval(&mut parent, lastlinked, &semi, &mut label, v);
162 semi[w] = std::cmp::min(semi[w], semi[x]);
164 // semi[w] is now semidominator(w) and won't change any more.
166 // Optimization: Do not insert into buckets if parent[w] = semi[w], as
167 // we then immediately know the idom.
169 // If we don't yet know the idom directly, then push this vertex into
170 // our semidominator's bucket, where it will get processed at a later
171 // stage to compute its immediate dominator.
172 if parent[w] != semi[w] {
173 bucket[semi[w]].push(w);
178 // Optimization: We share the parent array between processed and not
179 // processed elements; lastlinked represents the divider.
180 lastlinked = Some(w);
183 // Finalize the idoms for any that were not fully settable during initial
186 // If idom[w] != semi[w] then we know that we've stored vertex y from above
187 // into idom[w]. It is known to be our 'relative dominator', which means
188 // that it's one of w's ancestors and has the same immediate dominator as w,
190 for w in PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices) {
191 if idom[w] != semi[w] {
192 idom[w] = idom[idom[w]];
196 let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
197 for (idx, node) in pre_order_to_real.iter_enumerated() {
198 immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
201 Dominators { post_order_rank, immediate_dominators }
204 /// Evaluate the link-eval virtual forest, providing the currently minimum semi
205 /// value for the passed `node` (which may be itself).
207 /// This maintains that for every vertex v, `label[v]` is such that:
210 /// semi[eval(v)] = min { semi[label[u]] | root_in_forest(v) +> u *> v }
213 /// where `+>` is a proper ancestor and `*>` is just an ancestor.
216 ancestor: &mut IndexVec<PreorderIndex, PreorderIndex>,
217 lastlinked: Option<PreorderIndex>,
218 semi: &IndexVec<PreorderIndex, PreorderIndex>,
219 label: &mut IndexVec<PreorderIndex, PreorderIndex>,
222 if is_processed(node, lastlinked) {
223 compress(ancestor, lastlinked, semi, label, node);
231 fn is_processed(v: PreorderIndex, lastlinked: Option<PreorderIndex>) -> bool {
232 if let Some(ll) = lastlinked { v >= ll } else { false }
237 ancestor: &mut IndexVec<PreorderIndex, PreorderIndex>,
238 lastlinked: Option<PreorderIndex>,
239 semi: &IndexVec<PreorderIndex, PreorderIndex>,
240 label: &mut IndexVec<PreorderIndex, PreorderIndex>,
243 assert!(is_processed(v, lastlinked));
245 if is_processed(u, lastlinked) {
246 compress(ancestor, lastlinked, semi, label, u);
247 if semi[label[u]] < semi[label[v]] {
250 ancestor[v] = ancestor[u];
254 #[derive(Clone, Debug)]
255 pub struct Dominators<N: Idx> {
256 post_order_rank: IndexVec<N, usize>,
257 immediate_dominators: IndexVec<N, Option<N>>,
260 impl<Node: Idx> Dominators<Node> {
261 pub fn dummy() -> Self {
262 Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() }
265 pub fn is_reachable(&self, node: Node) -> bool {
266 self.immediate_dominators[node].is_some()
269 pub fn immediate_dominator(&self, node: Node) -> Node {
270 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
271 self.immediate_dominators[node].unwrap()
274 pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
275 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
276 Iter { dominators: self, node: Some(node) }
279 pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
280 // FIXME -- could be optimized by using post-order-rank
281 self.dominators(node).any(|n| n == dom)
284 /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
285 /// relationship, the dominator will always precede the dominated. (The relative ordering
286 /// of two unrelated nodes will also be consistent, but otherwise the order has no
287 /// meaning.) This method cannot be used to determine if either Node dominates the other.
288 pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
289 self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
293 pub struct Iter<'dom, Node: Idx> {
294 dominators: &'dom Dominators<Node>,
298 impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
301 fn next(&mut self) -> Option<Self::Item> {
302 if let Some(node) = self.node {
303 let dom = self.dominators.immediate_dominator(node);
305 self.node = None; // reached the root
307 self.node = Some(dom);