about summary refs log tree commit diff
path: root/compiler/rustc_data_structures/src
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2021-05-08 19:13:11 -0400
committerMark Rousskov <mark.simulacrum@gmail.com>2021-12-06 15:05:22 -0500
commit7d12767dc590e544d500d034f466a7b2d0d82d57 (patch)
tree89192910e26234a052422139e9d3ca0cf42127a8 /compiler/rustc_data_structures/src
parent92186cb5c9228f64c7f7c832a0b61aa05e14802d (diff)
downloadrust-7d12767dc590e544d500d034f466a7b2d0d82d57.tar.gz
rust-7d12767dc590e544d500d034f466a7b2d0d82d57.zip
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.
Diffstat (limited to 'compiler/rustc_data_structures/src')
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs91
1 files changed, 38 insertions, 53 deletions
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 074b5a16c12..b819b7f419a 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -34,60 +34,53 @@ fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Domin
     }
 
     let mut visited = BitSet::new_empty(graph.num_nodes());
-    let mut parent: IndexVec<G::Node, Option<G::Node>> =
-        IndexVec::from_elem_n(None, graph.num_nodes());
-    let mut pre_order_index: IndexVec<G::Node, Option<usize>> =
-        IndexVec::from_elem_n(None, graph.num_nodes());
-    let mut pre_order_nodes = Vec::with_capacity(rpo.len());
+    let mut parent: IndexVec<usize, Option<usize>> = IndexVec::from_elem_n(None, rpo.len());
 
-    let mut stack = vec![PreOrderFrame {
-        node: graph.start_node(),
-        iter: graph.successors(graph.start_node()),
-    }];
+    let mut stack = vec![PreOrderFrame { node: 0, iter: graph.successors(graph.start_node()) }];
     visited.insert(graph.start_node());
-    let mut idx = 0;
-    pre_order_index[graph.start_node()] = Some(0);
-    idx += 1;
-    pre_order_nodes.push(graph.start_node());
+    let mut pre_order_to_real = Vec::with_capacity(rpo.len());
+    let mut real_to_pre_order: IndexVec<G::Node, Option<usize>> =
+        IndexVec::from_elem_n(None, graph.num_nodes());
+    pre_order_to_real.push(graph.start_node());
+    real_to_pre_order[graph.start_node()] = Some(0);
+    let mut idx = 1;
 
     'recurse: while let Some(frame) = stack.last_mut() {
         while let Some(successor) = frame.iter.next() {
             if visited.insert(successor) {
-                parent[successor] = Some(frame.node);
-                pre_order_index[successor] = Some(idx);
-                pre_order_nodes.push(successor);
-                idx += 1;
+                parent[idx] = Some(frame.node);
+                pre_order_to_real.push(successor);
+                real_to_pre_order[successor] = Some(idx);
 
-                stack.push(PreOrderFrame { node: successor, iter: graph.successors(successor) });
+                stack.push(PreOrderFrame { node: idx, iter: graph.successors(successor) });
+                idx += 1;
                 continue 'recurse;
             }
         }
         stack.pop();
     }
 
-    let mut idom = IndexVec::from_elem_n(graph.start_node(), graph.num_nodes());
-    let mut semi = IndexVec::from_fn_n(std::convert::identity, graph.num_nodes());
+    let mut idom = IndexVec::from_elem_n(0, pre_order_to_real.len());
+    let mut semi = IndexVec::from_fn_n(std::convert::identity, pre_order_to_real.len());
     let mut label = semi.clone();
-    let mut bucket = IndexVec::from_elem_n(vec![], graph.num_nodes());
+    let mut bucket = IndexVec::from_elem_n(vec![], pre_order_to_real.len());
     let mut lastlinked = None;
 
-    for &w in pre_order_nodes[1..].iter().rev() {
-        // Optimization: process buckets just once. We need not explicitly empty
-        // the bucket here, but mem::take is pretty cheap.
+    for w in (1..pre_order_to_real.len()).rev() {
+        // Optimization: process buckets just once, at the start of the
+        // iteration. Do not explicitly empty the bucket (even though it will
+        // not be used again), to save some instructions.
         let z = parent[w].unwrap();
-        for v in std::mem::take(&mut bucket[z]) {
-            let y = eval(&pre_order_index, &mut parent, lastlinked, &semi, &mut label, v);
-            idom[v] = if pre_order_index[semi[y]] < pre_order_index[z] { y } else { z };
+        for &v in bucket[z].iter() {
+            let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
+            idom[v] = if semi[y] < z { y } else { z };
         }
 
         semi[w] = w;
-        for v in graph.predecessors(w) {
-            let x = eval(&pre_order_index, &mut parent, lastlinked, &semi, &mut label, v);
-            semi[w] = if pre_order_index[semi[w]].unwrap() < pre_order_index[semi[x]].unwrap() {
-                semi[w]
-            } else {
-                semi[x]
-            };
+        for v in graph.predecessors(pre_order_to_real[w]) {
+            let v = real_to_pre_order[v].unwrap();
+            let x = eval(&mut parent, lastlinked, &semi, &mut label, v);
+            semi[w] = std::cmp::min(semi[w], semi[x]);
         }
         // semi[w] is now semidominator(w).
 
@@ -103,59 +96,51 @@ fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Domin
         // processed elements; lastlinked represents the divider.
         lastlinked = Some(w);
     }
-    for &w in pre_order_nodes.iter().skip(1) {
+    for w in 1..pre_order_to_real.len() {
         if idom[w] != semi[w] {
             idom[w] = idom[idom[w]];
         }
     }
 
     let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
-    for (node, idom_slot) in immediate_dominators.iter_enumerated_mut() {
-        if pre_order_index[node].is_some() {
-            *idom_slot = Some(idom[node]);
-        }
+    for (idx, node) in pre_order_to_real.iter().enumerate() {
+        immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
     }
 
     Dominators { post_order_rank, immediate_dominators }
 }
 
 fn eval<N: Idx>(
-    pre_order_index: &IndexVec<N, Option<usize>>,
     ancestor: &mut IndexVec<N, Option<N>>,
     lastlinked: Option<N>,
     semi: &IndexVec<N, N>,
     label: &mut IndexVec<N, N>,
     node: N,
 ) -> N {
-    if is_processed(pre_order_index, node, lastlinked) {
-        compress(pre_order_index, ancestor, lastlinked, semi, label, node);
+    if is_processed(node, lastlinked) {
+        compress(ancestor, lastlinked, semi, label, node);
         label[node]
     } else {
         node
     }
 }
 
-fn is_processed<N: Idx>(
-    pre_order_index: &IndexVec<N, Option<usize>>,
-    v: N,
-    lastlinked: Option<N>,
-) -> bool {
-    if let Some(ll) = lastlinked { pre_order_index[v] >= pre_order_index[ll] } else { false }
+fn is_processed<N: Idx>(v: N, lastlinked: Option<N>) -> bool {
+    if let Some(ll) = lastlinked { v >= ll } else { false }
 }
 
 fn compress<N: Idx>(
-    pre_order_index: &IndexVec<N, Option<usize>>,
     ancestor: &mut IndexVec<N, Option<N>>,
     lastlinked: Option<N>,
     semi: &IndexVec<N, N>,
     label: &mut IndexVec<N, N>,
     v: N,
 ) {
-    assert!(is_processed(pre_order_index, v, lastlinked));
+    assert!(is_processed(v, lastlinked));
     let u = ancestor[v].unwrap();
-    if is_processed(pre_order_index, u, lastlinked) {
-        compress(pre_order_index, ancestor, lastlinked, semi, label, u);
-        if pre_order_index[semi[label[u]]] < pre_order_index[semi[label[v]]] {
+    if is_processed(u, lastlinked) {
+        compress(ancestor, lastlinked, semi, label, u);
+        if semi[label[u]] < semi[label[v]] {
             label[v] = label[u];
         }
         ancestor[v] = ancestor[u];