]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_data_structures/src/graph/dominators/mod.rs
bump version to 1.82.0+dfsg1-1~bpo12+pve2
[rustc.git] / compiler / rustc_data_structures / src / graph / dominators / mod.rs
CommitLineData
f035d41b
XL
1//! Finding the dominators in a control-flow graph.
2//!
a2a8927a
XL
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>
6//!
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>
3157f602 11
04c3a46a
FG
12use std::cmp::Ordering;
13
49aad941
FG
14use rustc_index::{Idx, IndexSlice, IndexVec};
15
04c3a46a 16use super::ControlFlowGraph;
3157f602 17
3157f602 18#[cfg(test)]
416331ca 19mod tests;
3157f602 20
a2a8927a
XL
21struct PreOrderFrame<Iter> {
22 pre_order_idx: PreorderIndex,
23 iter: Iter,
3157f602
XL
24}
25
a2a8927a 26rustc_index::newtype_index! {
4b012472 27 #[orderable]
9c376795 28 struct PreorderIndex {}
a2a8927a 29}
3157f602 30
ed00b5ec
FG
31#[derive(Clone, Debug)]
32pub struct Dominators<Node: Idx> {
33 kind: Kind<Node>,
34}
35
36#[derive(Clone, Debug)]
37enum Kind<Node: Idx> {
38 /// A representation optimized for a small path graphs.
39 Path,
40 General(Inner<Node>),
41}
42
43pub fn dominators<G: ControlFlowGraph>(g: &G) -> Dominators<G::Node> {
44 // We often encounter MIR bodies with 1 or 2 basic blocks. Special case the dominators
45 // computation and representation for those cases.
46 if is_small_path_graph(g) {
47 Dominators { kind: Kind::Path }
48 } else {
49 Dominators { kind: Kind::General(dominators_impl(g)) }
50 }
51}
52
53fn is_small_path_graph<G: ControlFlowGraph>(g: &G) -> bool {
54 if g.start_node().index() != 0 {
55 return false;
56 }
57 if g.num_nodes() == 1 {
58 return true;
59 }
60 if g.num_nodes() == 2 {
61 return g.successors(g.start_node()).any(|n| n.index() == 1);
62 }
63 false
64}
65
66fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
3157f602 67 // compute the post order index (rank) for each node
5869c6ff 68 let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
3157f602 69
a2a8927a
XL
70 // We allocate capacity for the full set of nodes, because most of the time
71 // most of the nodes *are* reachable.
72 let mut parent: IndexVec<PreorderIndex, PreorderIndex> =
73 IndexVec::with_capacity(graph.num_nodes());
74
75 let mut stack = vec![PreOrderFrame {
e8be2606 76 pre_order_idx: PreorderIndex::ZERO,
a2a8927a
XL
77 iter: graph.successors(graph.start_node()),
78 }];
79 let mut pre_order_to_real: IndexVec<PreorderIndex, G::Node> =
80 IndexVec::with_capacity(graph.num_nodes());
81 let mut real_to_pre_order: IndexVec<G::Node, Option<PreorderIndex>> =
82 IndexVec::from_elem_n(None, graph.num_nodes());
83 pre_order_to_real.push(graph.start_node());
e8be2606
FG
84 parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now.
85 real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO);
a2a8927a
XL
86 let mut post_order_idx = 0;
87
88 // Traverse the graph, collecting a number of things:
89 //
90 // * Preorder mapping (to it, and back to the actual ordering)
781aab86 91 // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product)
a2a8927a
XL
92 // * Parents for each vertex in the preorder tree
93 //
94 // These are all done here rather than through one of the 'standard'
95 // graph traversals to help make this fast.
96 'recurse: while let Some(frame) = stack.last_mut() {
31ef2f64 97 for successor in frame.iter.by_ref() {
a2a8927a
XL
98 if real_to_pre_order[successor].is_none() {
99 let pre_order_idx = pre_order_to_real.push(successor);
100 real_to_pre_order[successor] = Some(pre_order_idx);
101 parent.push(frame.pre_order_idx);
102 stack.push(PreOrderFrame { pre_order_idx, iter: graph.successors(successor) });
3157f602 103
a2a8927a 104 continue 'recurse;
3157f602
XL
105 }
106 }
a2a8927a
XL
107 post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx;
108 post_order_idx += 1;
109
110 stack.pop();
3157f602
XL
111 }
112
a2a8927a
XL
113 let reachable_vertices = pre_order_to_real.len();
114
e8be2606 115 let mut idom = IndexVec::from_elem_n(PreorderIndex::ZERO, reachable_vertices);
a2a8927a
XL
116 let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices);
117 let mut label = semi.clone();
118 let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices);
119 let mut lastlinked = None;
3157f602 120
a2a8927a
XL
121 // We loop over vertices in reverse preorder. This implements the pseudocode
122 // of the simple Lengauer-Tarjan algorithm. A few key facts are noted here
123 // which are helpful for understanding the code (full proofs and such are
124 // found in various papers, including one cited at the top of this file).
125 //
126 // For each vertex w (which is not the root),
127 // * semi[w] is a proper ancestor of the vertex w (i.e., semi[w] != w)
128 // * idom[w] is an ancestor of semi[w] (i.e., idom[w] may equal semi[w])
129 //
130 // An immediate dominator of w (idom[w]) is a vertex v where v dominates w
131 // and every other dominator of w dominates v. (Every vertex except the root has
132 // a unique immediate dominator.)
133 //
134 // A semidominator for a given vertex w (semi[w]) is the vertex v with minimum
135 // preorder number such that there exists a path from v to w in which all elements (other than w) have
136 // preorder numbers greater than w (i.e., this path is not the tree path to
137 // w).
138 for w in (PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices)).rev() {
139 // Optimization: process buckets just once, at the start of the
140 // iteration. Do not explicitly empty the bucket (even though it will
141 // not be used again), to save some instructions.
142 //
143 // The bucket here contains the vertices whose semidominator is the
144 // vertex w, which we are guaranteed to have found: all vertices who can
145 // be semidominated by w must have a preorder number exceeding w, so
146 // they have been placed in the bucket.
147 //
148 // We compute a partial set of immediate dominators here.
49aad941 149 for &v in bucket[w].iter() {
a2a8927a
XL
150 // This uses the result of Lemma 5 from section 2 from the original
151 // 1979 paper, to compute either the immediate or relative dominator
152 // for a given vertex v.
153 //
154 // eval returns a vertex y, for which semi[y] is minimum among
49aad941
FG
155 // vertices semi[v] +> y *> v. Note that semi[v] = w as we're in the
156 // w bucket.
a2a8927a
XL
157 //
158 // Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v].
159 // If semi[y] = semi[v], though, idom[v] = semi[v].
160 //
161 // Using this, we can either set idom[v] to be:
49aad941 162 // * semi[v] (i.e. w), if semi[y] is w
a2a8927a
XL
163 // * idom[y], otherwise
164 //
165 // We don't directly set to idom[y] though as it's not necessarily
166 // known yet. The second preorder traversal will cleanup by updating
167 // the idom for any that were missed in this pass.
168 let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
49aad941 169 idom[v] = if semi[y] < w { y } else { w };
3157f602
XL
170 }
171
a2a8927a
XL
172 // This loop computes the semi[w] for w.
173 semi[w] = w;
174 for v in graph.predecessors(pre_order_to_real[w]) {
9ffffee4
FG
175 // TL;DR: Reachable vertices may have unreachable predecessors, so ignore any of them.
176 //
177 // Ignore blocks which are not connected to the entry block.
178 //
179 // The algorithm that was used to traverse the graph and build the
180 // `pre_order_to_real` and `real_to_pre_order` vectors does so by
181 // starting from the entry block and following the successors.
182 // Therefore, any blocks not reachable from the entry block will be
183 // set to `None` in the `pre_order_to_real` vector.
184 //
185 // For example, in this graph, A and B should be skipped:
186 //
187 // ┌─────┐
188 // │ │
189 // └──┬──┘
190 // │
191 // ┌──▼──┐ ┌─────┐
192 // │ │ │ A │
193 // └──┬──┘ └──┬──┘
194 // │ │
195 // ┌───────┴───────┐ │
196 // │ │ │
197 // ┌──▼──┐ ┌──▼──┐ ┌──▼──┐
198 // │ │ │ │ │ B │
199 // └──┬──┘ └──┬──┘ └──┬──┘
200 // │ └──────┬─────┘
201 // ┌──▼──┐ │
202 // │ │ │
203 // └──┬──┘ ┌──▼──┐
204 // │ │ │
205 // │ └─────┘
206 // ┌──▼──┐
207 // │ │
208 // └──┬──┘
209 // │
210 // ┌──▼──┐
211 // │ │
212 // └─────┘
213 //
214 // ...this may be the case if a MirPass modifies the CFG to remove
215 // or rearrange certain blocks/edges.
add651ee 216 let Some(v) = real_to_pre_order[v] else { continue };
a2a8927a
XL
217
218 // eval returns a vertex x from which semi[x] is minimum among
219 // vertices semi[v] +> x *> v.
220 //
221 // From Lemma 4 from section 2, we know that the semidominator of a
222 // vertex w is the minimum (by preorder number) vertex of the
223 // following:
224 //
225 // * direct predecessors of w with preorder number less than w
226 // * semidominators of u such that u > w and there exists (v, w)
227 // such that u *> v
228 //
229 // This loop therefore identifies such a minima. Note that any
230 // semidominator path to w must have all but the first vertex go
231 // through vertices numbered greater than w, so the reverse preorder
232 // traversal we are using guarantees that all of the information we
233 // might need is available at this point.
234 //
235 // The eval call will give us semi[x], which is either:
236 //
237 // * v itself, if v has not yet been processed
238 // * A possible 'best' semidominator for w.
239 let x = eval(&mut parent, lastlinked, &semi, &mut label, v);
240 semi[w] = std::cmp::min(semi[w], semi[x]);
241 }
242 // semi[w] is now semidominator(w) and won't change any more.
243
244 // Optimization: Do not insert into buckets if parent[w] = semi[w], as
245 // we then immediately know the idom.
246 //
247 // If we don't yet know the idom directly, then push this vertex into
248 // our semidominator's bucket, where it will get processed at a later
249 // stage to compute its immediate dominator.
49aad941
FG
250 let z = parent[w];
251 if z != semi[w] {
a2a8927a
XL
252 bucket[semi[w]].push(w);
253 } else {
49aad941 254 idom[w] = z;
3157f602 255 }
a2a8927a
XL
256
257 // Optimization: We share the parent array between processed and not
258 // processed elements; lastlinked represents the divider.
259 lastlinked = Some(w);
3157f602 260 }
b7449926 261
a2a8927a
XL
262 // Finalize the idoms for any that were not fully settable during initial
263 // traversal.
264 //
265 // If idom[w] != semi[w] then we know that we've stored vertex y from above
266 // into idom[w]. It is known to be our 'relative dominator', which means
267 // that it's one of w's ancestors and has the same immediate dominator as w,
268 // so use that idom.
269 for w in PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices) {
270 if idom[w] != semi[w] {
271 idom[w] = idom[idom[w]];
272 }
273 }
274
275 let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
276 for (idx, node) in pre_order_to_real.iter_enumerated() {
277 immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
278 }
279
49aad941
FG
280 let start_node = graph.start_node();
281 immediate_dominators[start_node] = None;
282
283 let time = compute_access_time(start_node, &immediate_dominators);
284
ed00b5ec 285 Inner { post_order_rank, immediate_dominators, time }
a2a8927a
XL
286}
287
288/// Evaluate the link-eval virtual forest, providing the currently minimum semi
289/// value for the passed `node` (which may be itself).
290///
291/// This maintains that for every vertex v, `label[v]` is such that:
292///
293/// ```text
294/// semi[eval(v)] = min { semi[label[u]] | root_in_forest(v) +> u *> v }
295/// ```
296///
297/// where `+>` is a proper ancestor and `*>` is just an ancestor.
298#[inline]
299fn eval(
353b0b11 300 ancestor: &mut IndexSlice<PreorderIndex, PreorderIndex>,
a2a8927a 301 lastlinked: Option<PreorderIndex>,
353b0b11
FG
302 semi: &IndexSlice<PreorderIndex, PreorderIndex>,
303 label: &mut IndexSlice<PreorderIndex, PreorderIndex>,
a2a8927a
XL
304 node: PreorderIndex,
305) -> PreorderIndex {
306 if is_processed(node, lastlinked) {
307 compress(ancestor, lastlinked, semi, label, node);
308 label[node]
309 } else {
310 node
311 }
312}
313
314#[inline]
315fn is_processed(v: PreorderIndex, lastlinked: Option<PreorderIndex>) -> bool {
316 if let Some(ll) = lastlinked { v >= ll } else { false }
317}
318
319#[inline]
320fn compress(
353b0b11 321 ancestor: &mut IndexSlice<PreorderIndex, PreorderIndex>,
a2a8927a 322 lastlinked: Option<PreorderIndex>,
353b0b11
FG
323 semi: &IndexSlice<PreorderIndex, PreorderIndex>,
324 label: &mut IndexSlice<PreorderIndex, PreorderIndex>,
a2a8927a
XL
325 v: PreorderIndex,
326) {
327 assert!(is_processed(v, lastlinked));
5e7ed085
FG
328 // Compute the processed list of ancestors
329 //
330 // We use a heap stack here to avoid recursing too deeply, exhausting the
331 // stack space.
332 let mut stack: smallvec::SmallVec<[_; 8]> = smallvec::smallvec![v];
333 let mut u = ancestor[v];
334 while is_processed(u, lastlinked) {
335 stack.push(u);
336 u = ancestor[u];
337 }
338
339 // Then in reverse order, popping the stack
340 for &[v, u] in stack.array_windows().rev() {
a2a8927a
XL
341 if semi[label[u]] < semi[label[v]] {
342 label[v] = label[u];
343 }
344 ancestor[v] = ancestor[u];
345 }
3157f602
XL
346}
347
9ffffee4 348/// Tracks the list of dominators for each node.
3157f602 349#[derive(Clone, Debug)]
ed00b5ec 350struct Inner<N: Idx> {
3157f602 351 post_order_rank: IndexVec<N, usize>,
9ffffee4
FG
352 // Even though we track only the immediate dominator of each node, it's
353 // possible to get its full list of dominators by looking up the dominator
ed00b5ec 354 // of each dominator.
3157f602 355 immediate_dominators: IndexVec<N, Option<N>>,
49aad941 356 time: IndexVec<N, Time>,
3157f602
XL
357}
358
359impl<Node: Idx> Dominators<Node> {
49aad941 360 /// Returns true if node is reachable from the start node.
3157f602 361 pub fn is_reachable(&self, node: Node) -> bool {
ed00b5ec
FG
362 match &self.kind {
363 Kind::Path => true,
364 Kind::General(g) => g.time[node].start != 0,
365 }
3157f602
XL
366 }
367
49aad941
FG
368 /// Returns the immediate dominator of node, if any.
369 pub fn immediate_dominator(&self, node: Node) -> Option<Node> {
ed00b5ec
FG
370 match &self.kind {
371 Kind::Path => {
372 if 0 < node.index() {
373 Some(Node::new(node.index() - 1))
374 } else {
375 None
376 }
377 }
378 Kind::General(g) => g.immediate_dominators[node],
379 }
3157f602 380 }
29967ef6
XL
381
382 /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
383 /// relationship, the dominator will always precede the dominated. (The relative ordering
384 /// of two unrelated nodes will also be consistent, but otherwise the order has no
385 /// meaning.) This method cannot be used to determine if either Node dominates the other.
781aab86 386 pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
ed00b5ec
FG
387 match &self.kind {
388 Kind::Path => lhs.index().cmp(&rhs.index()),
389 Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]),
390 }
29967ef6 391 }
49aad941
FG
392
393 /// Returns true if `a` dominates `b`.
394 ///
395 /// # Panics
396 ///
397 /// Panics if `b` is unreachable.
c0240ec0 398 #[inline]
49aad941 399 pub fn dominates(&self, a: Node, b: Node) -> bool {
ed00b5ec
FG
400 match &self.kind {
401 Kind::Path => a.index() <= b.index(),
402 Kind::General(g) => {
403 let a = g.time[a];
404 let b = g.time[b];
405 assert!(b.start != 0, "node {b:?} is not reachable");
406 a.start <= b.start && b.finish <= a.finish
407 }
3157f602
XL
408 }
409 }
410}
49aad941
FG
411
412/// Describes the number of vertices discovered at the time when processing of a particular vertex
413/// started and when it finished. Both values are zero for unreachable vertices.
414#[derive(Copy, Clone, Default, Debug)]
415struct Time {
416 start: u32,
417 finish: u32,
418}
419
420fn compute_access_time<N: Idx>(
421 start_node: N,
422 immediate_dominators: &IndexSlice<N, Option<N>>,
423) -> IndexVec<N, Time> {
424 // Transpose the dominator tree edges, so that child nodes of vertex v are stored in
425 // node[edges[v].start..edges[v].end].
426 let mut edges: IndexVec<N, std::ops::Range<u32>> =
427 IndexVec::from_elem(0..0, immediate_dominators);
428 for &idom in immediate_dominators.iter() {
429 if let Some(idom) = idom {
430 edges[idom].end += 1;
431 }
432 }
433 let mut m = 0;
434 for e in edges.iter_mut() {
435 m += e.end;
436 e.start = m;
437 e.end = m;
438 }
439 let mut node = IndexVec::from_elem_n(Idx::new(0), m.try_into().unwrap());
440 for (i, &idom) in immediate_dominators.iter_enumerated() {
441 if let Some(idom) = idom {
442 edges[idom].start -= 1;
443 node[edges[idom].start] = i;
444 }
445 }
446
447 // Perform a depth-first search of the dominator tree. Record the number of vertices discovered
448 // when vertex v is discovered first as time[v].start, and when its processing is finished as
449 // time[v].finish.
450 let mut time: IndexVec<N, Time> = IndexVec::from_elem(Time::default(), immediate_dominators);
451 let mut stack = Vec::new();
452
453 let mut discovered = 1;
454 stack.push(start_node);
455 time[start_node].start = discovered;
456
457 while let Some(&i) = stack.last() {
458 let e = &mut edges[i];
459 if e.start == e.end {
460 // Finish processing vertex i.
461 time[i].finish = discovered;
462 stack.pop();
463 } else {
464 let j = node[e.start];
465 e.start += 1;
466 // Start processing vertex j.
467 discovered += 1;
468 time[j].start = discovered;
469 stack.push(j);
470 }
471 }
472
473 time
474}