Skip to content

Commit 25f084d

Browse files
committed
Auto merge of rust-lang#111596 - cjgillot:dominator-bucket, r=Mark-Simulacrum
Process current bucket instead of parent's bucket when starting loop for dominators. The linked paper by Georgiadis suggests in §2.2.3 to process `bucket[w]` when beginning the loop, instead of `bucket[parent[w]]` when finishing it. In the test case, we correctly computed `idom[2] = 0` and `sdom[3] = 1`, but the algorithm returned `idom[3] = 1`, instead of the correct value 0, because of the path 0-7-2-3. This provoked LLVM ICE in rust-lang#111061 (comment). LLVM checks that SSA assignments dominate uses using its own implementation of Lengauer-Tarjan, and saw case where rustc was breaking the dominance property. r? `@Mark-Simulacrum`
2 parents e86fd62 + 84339a6 commit 25f084d

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

Diff for: compiler/rustc_data_structures/src/graph/dominators/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -109,28 +109,27 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
109109
// they have been placed in the bucket.
110110
//
111111
// We compute a partial set of immediate dominators here.
112-
let z = parent[w];
113-
for &v in bucket[z].iter() {
112+
for &v in bucket[w].iter() {
114113
// This uses the result of Lemma 5 from section 2 from the original
115114
// 1979 paper, to compute either the immediate or relative dominator
116115
// for a given vertex v.
117116
//
118117
// eval returns a vertex y, for which semi[y] is minimum among
119-
// vertices semi[v] +> y *> v. Note that semi[v] = z as we're in the
120-
// z bucket.
118+
// vertices semi[v] +> y *> v. Note that semi[v] = w as we're in the
119+
// w bucket.
121120
//
122121
// Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v].
123122
// If semi[y] = semi[v], though, idom[v] = semi[v].
124123
//
125124
// Using this, we can either set idom[v] to be:
126-
// * semi[v] (i.e. z), if semi[y] is z
125+
// * semi[v] (i.e. w), if semi[y] is w
127126
// * idom[y], otherwise
128127
//
129128
// We don't directly set to idom[y] though as it's not necessarily
130129
// known yet. The second preorder traversal will cleanup by updating
131130
// the idom for any that were missed in this pass.
132131
let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
133-
idom[v] = if semi[y] < z { y } else { z };
132+
idom[v] = if semi[y] < w { y } else { w };
134133
}
135134

136135
// This loop computes the semi[w] for w.
@@ -213,10 +212,11 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
213212
// If we don't yet know the idom directly, then push this vertex into
214213
// our semidominator's bucket, where it will get processed at a later
215214
// stage to compute its immediate dominator.
216-
if parent[w] != semi[w] {
215+
let z = parent[w];
216+
if z != semi[w] {
217217
bucket[semi[w]].push(w);
218218
} else {
219-
idom[w] = parent[w];
219+
idom[w] = z;
220220
}
221221

222222
// Optimization: We share the parent array between processed and not

Diff for: compiler/rustc_data_structures/src/graph/dominators/tests.rs

+27
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,30 @@ fn immediate_dominator() {
5353
assert_eq!(dominators.immediate_dominator(2), Some(1));
5454
assert_eq!(dominators.immediate_dominator(3), Some(2));
5555
}
56+
57+
#[test]
58+
fn transitive_dominator() {
59+
let graph = TestGraph::new(
60+
0,
61+
&[
62+
// First tree branch.
63+
(0, 1),
64+
(1, 2),
65+
(2, 3),
66+
(3, 4),
67+
// Second tree branch.
68+
(1, 5),
69+
(5, 6),
70+
// Third tree branch.
71+
(0, 7),
72+
// These links make 0 the dominator for 2 and 3.
73+
(7, 2),
74+
(5, 3),
75+
],
76+
);
77+
78+
let dom_tree = dominators(&graph);
79+
let immediate_dominators = &dom_tree.immediate_dominators;
80+
assert_eq!(immediate_dominators[2], Some(0));
81+
assert_eq!(immediate_dominators[3], Some(0)); // This used to return Some(1).
82+
}

0 commit comments

Comments
 (0)