Skip to content

Commit 7d12767

Browse files
Use preorder indices for data structures
This largely avoids remapping from and to the 'real' indices, with the exception of predecessor lookup and the final merge back, and is conceptually better.
1 parent 92186cb commit 7d12767

File tree

1 file changed

+38
-53
lines changed
  • compiler/rustc_data_structures/src/graph/dominators

1 file changed

+38
-53
lines changed

compiler/rustc_data_structures/src/graph/dominators/mod.rs

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -34,60 +34,53 @@ fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Domin
3434
}
3535

3636
let mut visited = BitSet::new_empty(graph.num_nodes());
37-
let mut parent: IndexVec<G::Node, Option<G::Node>> =
38-
IndexVec::from_elem_n(None, graph.num_nodes());
39-
let mut pre_order_index: IndexVec<G::Node, Option<usize>> =
40-
IndexVec::from_elem_n(None, graph.num_nodes());
41-
let mut pre_order_nodes = Vec::with_capacity(rpo.len());
37+
let mut parent: IndexVec<usize, Option<usize>> = IndexVec::from_elem_n(None, rpo.len());
4238

43-
let mut stack = vec![PreOrderFrame {
44-
node: graph.start_node(),
45-
iter: graph.successors(graph.start_node()),
46-
}];
39+
let mut stack = vec![PreOrderFrame { node: 0, iter: graph.successors(graph.start_node()) }];
4740
visited.insert(graph.start_node());
48-
let mut idx = 0;
49-
pre_order_index[graph.start_node()] = Some(0);
50-
idx += 1;
51-
pre_order_nodes.push(graph.start_node());
41+
let mut pre_order_to_real = Vec::with_capacity(rpo.len());
42+
let mut real_to_pre_order: IndexVec<G::Node, Option<usize>> =
43+
IndexVec::from_elem_n(None, graph.num_nodes());
44+
pre_order_to_real.push(graph.start_node());
45+
real_to_pre_order[graph.start_node()] = Some(0);
46+
let mut idx = 1;
5247

5348
'recurse: while let Some(frame) = stack.last_mut() {
5449
while let Some(successor) = frame.iter.next() {
5550
if visited.insert(successor) {
56-
parent[successor] = Some(frame.node);
57-
pre_order_index[successor] = Some(idx);
58-
pre_order_nodes.push(successor);
59-
idx += 1;
51+
parent[idx] = Some(frame.node);
52+
pre_order_to_real.push(successor);
53+
real_to_pre_order[successor] = Some(idx);
6054

61-
stack.push(PreOrderFrame { node: successor, iter: graph.successors(successor) });
55+
stack.push(PreOrderFrame { node: idx, iter: graph.successors(successor) });
56+
idx += 1;
6257
continue 'recurse;
6358
}
6459
}
6560
stack.pop();
6661
}
6762

68-
let mut idom = IndexVec::from_elem_n(graph.start_node(), graph.num_nodes());
69-
let mut semi = IndexVec::from_fn_n(std::convert::identity, graph.num_nodes());
63+
let mut idom = IndexVec::from_elem_n(0, pre_order_to_real.len());
64+
let mut semi = IndexVec::from_fn_n(std::convert::identity, pre_order_to_real.len());
7065
let mut label = semi.clone();
71-
let mut bucket = IndexVec::from_elem_n(vec![], graph.num_nodes());
66+
let mut bucket = IndexVec::from_elem_n(vec![], pre_order_to_real.len());
7267
let mut lastlinked = None;
7368

74-
for &w in pre_order_nodes[1..].iter().rev() {
75-
// Optimization: process buckets just once. We need not explicitly empty
76-
// the bucket here, but mem::take is pretty cheap.
69+
for w in (1..pre_order_to_real.len()).rev() {
70+
// Optimization: process buckets just once, at the start of the
71+
// iteration. Do not explicitly empty the bucket (even though it will
72+
// not be used again), to save some instructions.
7773
let z = parent[w].unwrap();
78-
for v in std::mem::take(&mut bucket[z]) {
79-
let y = eval(&pre_order_index, &mut parent, lastlinked, &semi, &mut label, v);
80-
idom[v] = if pre_order_index[semi[y]] < pre_order_index[z] { y } else { z };
74+
for &v in bucket[z].iter() {
75+
let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
76+
idom[v] = if semi[y] < z { y } else { z };
8177
}
8278

8379
semi[w] = w;
84-
for v in graph.predecessors(w) {
85-
let x = eval(&pre_order_index, &mut parent, lastlinked, &semi, &mut label, v);
86-
semi[w] = if pre_order_index[semi[w]].unwrap() < pre_order_index[semi[x]].unwrap() {
87-
semi[w]
88-
} else {
89-
semi[x]
90-
};
80+
for v in graph.predecessors(pre_order_to_real[w]) {
81+
let v = real_to_pre_order[v].unwrap();
82+
let x = eval(&mut parent, lastlinked, &semi, &mut label, v);
83+
semi[w] = std::cmp::min(semi[w], semi[x]);
9184
}
9285
// semi[w] is now semidominator(w).
9386

@@ -103,59 +96,51 @@ fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Domin
10396
// processed elements; lastlinked represents the divider.
10497
lastlinked = Some(w);
10598
}
106-
for &w in pre_order_nodes.iter().skip(1) {
99+
for w in 1..pre_order_to_real.len() {
107100
if idom[w] != semi[w] {
108101
idom[w] = idom[idom[w]];
109102
}
110103
}
111104

112105
let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
113-
for (node, idom_slot) in immediate_dominators.iter_enumerated_mut() {
114-
if pre_order_index[node].is_some() {
115-
*idom_slot = Some(idom[node]);
116-
}
106+
for (idx, node) in pre_order_to_real.iter().enumerate() {
107+
immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
117108
}
118109

119110
Dominators { post_order_rank, immediate_dominators }
120111
}
121112

122113
fn eval<N: Idx>(
123-
pre_order_index: &IndexVec<N, Option<usize>>,
124114
ancestor: &mut IndexVec<N, Option<N>>,
125115
lastlinked: Option<N>,
126116
semi: &IndexVec<N, N>,
127117
label: &mut IndexVec<N, N>,
128118
node: N,
129119
) -> N {
130-
if is_processed(pre_order_index, node, lastlinked) {
131-
compress(pre_order_index, ancestor, lastlinked, semi, label, node);
120+
if is_processed(node, lastlinked) {
121+
compress(ancestor, lastlinked, semi, label, node);
132122
label[node]
133123
} else {
134124
node
135125
}
136126
}
137127

138-
fn is_processed<N: Idx>(
139-
pre_order_index: &IndexVec<N, Option<usize>>,
140-
v: N,
141-
lastlinked: Option<N>,
142-
) -> bool {
143-
if let Some(ll) = lastlinked { pre_order_index[v] >= pre_order_index[ll] } else { false }
128+
fn is_processed<N: Idx>(v: N, lastlinked: Option<N>) -> bool {
129+
if let Some(ll) = lastlinked { v >= ll } else { false }
144130
}
145131

146132
fn compress<N: Idx>(
147-
pre_order_index: &IndexVec<N, Option<usize>>,
148133
ancestor: &mut IndexVec<N, Option<N>>,
149134
lastlinked: Option<N>,
150135
semi: &IndexVec<N, N>,
151136
label: &mut IndexVec<N, N>,
152137
v: N,
153138
) {
154-
assert!(is_processed(pre_order_index, v, lastlinked));
139+
assert!(is_processed(v, lastlinked));
155140
let u = ancestor[v].unwrap();
156-
if is_processed(pre_order_index, u, lastlinked) {
157-
compress(pre_order_index, ancestor, lastlinked, semi, label, u);
158-
if pre_order_index[semi[label[u]]] < pre_order_index[semi[label[v]]] {
141+
if is_processed(u, lastlinked) {
142+
compress(ancestor, lastlinked, semi, label, u);
143+
if semi[label[u]] < semi[label[v]] {
159144
label[v] = label[u];
160145
}
161146
ancestor[v] = ancestor[u];

0 commit comments

Comments
 (0)