Skip to content

Commit 7897a2a

Browse files
committed
Optimize dominators for small path graphs
Generalizes the small dominators approach from rust-lang#107449.
1 parent 02bbed7 commit 7897a2a

File tree

1 file changed

+65
-10
lines changed
  • compiler/rustc_data_structures/src/graph/dominators

1 file changed

+65
-10
lines changed

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

+65-10
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,42 @@ rustc_index::newtype_index! {
2626
struct PreorderIndex {}
2727
}
2828

29-
pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
29+
#[derive(Clone, Debug)]
30+
pub struct Dominators<Node: Idx> {
31+
kind: Kind<Node>,
32+
}
33+
34+
#[derive(Clone, Debug)]
35+
enum Kind<Node: Idx> {
36+
/// A representation optimized for a small path graphs.
37+
Path(usize),
38+
General(Inner<Node>),
39+
}
40+
41+
pub fn dominators<G: ControlFlowGraph>(g: &G) -> Dominators<G::Node> {
42+
// We often encounter MIR bodies with 1 or 2 basic blocks. Special case the dominators
43+
// computation and representation for those cases.
44+
if is_small_path_graph(g) {
45+
Dominators { kind: Kind::Path(g.num_nodes()) }
46+
} else {
47+
Dominators { kind: Kind::General(dominators_impl(g)) }
48+
}
49+
}
50+
51+
fn is_small_path_graph<G: ControlFlowGraph>(g: &G) -> bool {
52+
if g.start_node().index() != 0 {
53+
return false;
54+
}
55+
if g.num_nodes() == 1 {
56+
return true;
57+
}
58+
if g.num_nodes() == 2 {
59+
return g.successors(g.start_node()).any(|n| n.index() == 1);
60+
}
61+
false
62+
}
63+
64+
fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
3065
// compute the post order index (rank) for each node
3166
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
3267

@@ -245,7 +280,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
245280

246281
let time = compute_access_time(start_node, &immediate_dominators);
247282

248-
Dominators { post_order_rank, immediate_dominators, time }
283+
Inner { post_order_rank, immediate_dominators, time }
249284
}
250285

251286
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -310,7 +345,7 @@ fn compress(
310345

311346
/// Tracks the list of dominators for each node.
312347
#[derive(Clone, Debug)]
313-
pub struct Dominators<N: Idx> {
348+
struct Inner<N: Idx> {
314349
post_order_rank: IndexVec<N, usize>,
315350
// Even though we track only the immediate dominator of each node, it's
316351
// possible to get its full list of dominators by looking up the dominator
@@ -322,12 +357,24 @@ pub struct Dominators<N: Idx> {
322357
impl<Node: Idx> Dominators<Node> {
323358
/// Returns true if node is reachable from the start node.
324359
pub fn is_reachable(&self, node: Node) -> bool {
325-
self.time[node].start != 0
360+
match &self.kind {
361+
Kind::Path(_) => true,
362+
Kind::General(g) => g.time[node].start != 0,
363+
}
326364
}
327365

328366
/// Returns the immediate dominator of node, if any.
329367
pub fn immediate_dominator(&self, node: Node) -> Option<Node> {
330-
self.immediate_dominators[node]
368+
match &self.kind {
369+
Kind::Path(n) => {
370+
if 0 < node.index() && node.index() < *n {
371+
Some(Node::new(node.index() - 1))
372+
} else {
373+
None
374+
}
375+
}
376+
Kind::General(g) => g.immediate_dominators[node],
377+
}
331378
}
332379

333380
/// Provides an iterator over each dominator up the CFG, for the given Node.
@@ -342,7 +389,10 @@ impl<Node: Idx> Dominators<Node> {
342389
/// of two unrelated nodes will also be consistent, but otherwise the order has no
343390
/// meaning.) This method cannot be used to determine if either Node dominates the other.
344391
pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
345-
self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs])
392+
match &self.kind {
393+
Kind::Path(_) => lhs.index().cmp(&rhs.index()),
394+
Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]),
395+
}
346396
}
347397

348398
/// Returns true if `a` dominates `b`.
@@ -351,10 +401,15 @@ impl<Node: Idx> Dominators<Node> {
351401
///
352402
/// Panics if `b` is unreachable.
353403
pub fn dominates(&self, a: Node, b: Node) -> bool {
354-
let a = self.time[a];
355-
let b = self.time[b];
356-
assert!(b.start != 0, "node {b:?} is not reachable");
357-
a.start <= b.start && b.finish <= a.finish
404+
match &self.kind {
405+
Kind::Path(_) => a.index() <= b.index(),
406+
Kind::General(g) => {
407+
let a = g.time[a];
408+
let b = g.time[b];
409+
assert!(b.start != 0, "node {b:?} is not reachable");
410+
a.start <= b.start && b.finish <= a.finish
411+
}
412+
}
358413
}
359414
}
360415

0 commit comments

Comments
 (0)