diff options
| author | bors <bors@rust-lang.org> | 2023-10-08 12:38:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-10-08 12:38:14 +0000 |
| commit | 4f4a413fe6931d0ad9d3ac6bd20ff36398961e64 (patch) | |
| tree | ec69e5d1582f1cc6931a0f2e672e9593cc1478c7 /compiler/rustc_data_structures/src/graph | |
| parent | 1e3c8f196b2753b3e463bc6be2dc446f36653279 (diff) | |
| parent | eaafb256f8e729338603476ab1e54b804efead91 (diff) | |
| download | rust-4f4a413fe6931d0ad9d3ac6bd20ff36398961e64.tar.gz rust-4f4a413fe6931d0ad9d3ac6bd20ff36398961e64.zip | |
Auto merge of #116454 - tmiasko:small-dominators, r=cjgillot
Generalize small dominators optimization * Use small dominators optimization from 640ede7b0a1840415cb6ec881c2210302bfeba18 more generally. * Merge `DefLocation` and `LocationExtended` since they serve the same purpose.
Diffstat (limited to 'compiler/rustc_data_structures/src/graph')
| -rw-r--r-- | compiler/rustc_data_structures/src/graph/dominators/mod.rs | 76 | ||||
| -rw-r--r-- | compiler/rustc_data_structures/src/graph/dominators/tests.rs | 45 |
2 files changed, 86 insertions, 35 deletions
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 4075481e561..9685ad24a97 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -26,7 +26,42 @@ rustc_index::newtype_index! { struct PreorderIndex {} } -pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> { +#[derive(Clone, Debug)] +pub struct Dominators<Node: Idx> { + kind: Kind<Node>, +} + +#[derive(Clone, Debug)] +enum Kind<Node: Idx> { + /// A representation optimized for a small path graphs. + Path, + General(Inner<Node>), +} + +pub fn dominators<G: ControlFlowGraph>(g: &G) -> Dominators<G::Node> { + // We often encounter MIR bodies with 1 or 2 basic blocks. Special case the dominators + // computation and representation for those cases. + if is_small_path_graph(g) { + Dominators { kind: Kind::Path } + } else { + Dominators { kind: Kind::General(dominators_impl(g)) } + } +} + +fn is_small_path_graph<G: ControlFlowGraph>(g: &G) -> bool { + if g.start_node().index() != 0 { + return false; + } + if g.num_nodes() == 1 { + return true; + } + if g.num_nodes() == 2 { + return g.successors(g.start_node()).any(|n| n.index() == 1); + } + false +} + +fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> { // compute the post order index (rank) for each node let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes()); @@ -245,7 +280,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> { let time = compute_access_time(start_node, &immediate_dominators); - Dominators { start_node, post_order_rank, immediate_dominators, time } + Inner { post_order_rank, immediate_dominators, time } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -310,8 +345,7 @@ fn compress( /// Tracks the list of dominators for each node. #[derive(Clone, Debug)] -pub struct Dominators<N: Idx> { - start_node: N, +struct Inner<N: Idx> { post_order_rank: IndexVec<N, usize>, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator @@ -323,12 +357,24 @@ pub struct Dominators<N: Idx> { impl<Node: Idx> Dominators<Node> { /// Returns true if node is reachable from the start node. pub fn is_reachable(&self, node: Node) -> bool { - node == self.start_node || self.immediate_dominators[node].is_some() + match &self.kind { + Kind::Path => true, + Kind::General(g) => g.time[node].start != 0, + } } /// Returns the immediate dominator of node, if any. pub fn immediate_dominator(&self, node: Node) -> Option<Node> { - self.immediate_dominators[node] + match &self.kind { + Kind::Path => { + if 0 < node.index() { + Some(Node::new(node.index() - 1)) + } else { + None + } + } + Kind::General(g) => g.immediate_dominators[node], + } } /// Provides an iterator over each dominator up the CFG, for the given Node. @@ -343,7 +389,10 @@ impl<Node: Idx> Dominators<Node> { /// of two unrelated nodes will also be consistent, but otherwise the order has no /// meaning.) This method cannot be used to determine if either Node dominates the other. pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering { - self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs]) + match &self.kind { + Kind::Path => lhs.index().cmp(&rhs.index()), + Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]), + } } /// Returns true if `a` dominates `b`. @@ -352,10 +401,15 @@ impl<Node: Idx> Dominators<Node> { /// /// Panics if `b` is unreachable. pub fn dominates(&self, a: Node, b: Node) -> bool { - let a = self.time[a]; - let b = self.time[b]; - assert!(b.start != 0, "node {b:?} is not reachable"); - a.start <= b.start && b.finish <= a.finish + match &self.kind { + Kind::Path => a.index() <= b.index(), + Kind::General(g) => { + let a = g.time[a]; + let b = g.time[b]; + assert!(b.start != 0, "node {b:?} is not reachable"); + a.start <= b.start && b.finish <= a.finish + } + } } } diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index 5472bb8087e..39725ba4301 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -6,12 +6,11 @@ use super::super::tests::TestGraph; fn diamond() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); - let dominators = dominators(&graph); - let immediate_dominators = &dominators.immediate_dominators; - assert_eq!(immediate_dominators[0], None); - assert_eq!(immediate_dominators[1], Some(0)); - assert_eq!(immediate_dominators[2], Some(0)); - assert_eq!(immediate_dominators[3], Some(0)); + let d = dominators(&graph); + assert_eq!(d.immediate_dominator(0), None); + assert_eq!(d.immediate_dominator(1), Some(0)); + assert_eq!(d.immediate_dominator(2), Some(0)); + assert_eq!(d.immediate_dominator(3), Some(0)); } #[test] @@ -22,15 +21,14 @@ fn paper() { &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), (2, 1)], ); - let dominators = dominators(&graph); - let immediate_dominators = &dominators.immediate_dominators; - assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph - assert_eq!(immediate_dominators[1], Some(6)); - assert_eq!(immediate_dominators[2], Some(6)); - assert_eq!(immediate_dominators[3], Some(6)); - assert_eq!(immediate_dominators[4], Some(6)); - assert_eq!(immediate_dominators[5], Some(6)); - assert_eq!(immediate_dominators[6], None); + let d = dominators(&graph); + assert_eq!(d.immediate_dominator(0), None); // <-- note that 0 is not in graph + assert_eq!(d.immediate_dominator(1), Some(6)); + assert_eq!(d.immediate_dominator(2), Some(6)); + assert_eq!(d.immediate_dominator(3), Some(6)); + assert_eq!(d.immediate_dominator(4), Some(6)); + assert_eq!(d.immediate_dominator(5), Some(6)); + assert_eq!(d.immediate_dominator(6), None); } #[test] @@ -47,11 +45,11 @@ fn paper_slt() { #[test] fn immediate_dominator() { let graph = TestGraph::new(1, &[(1, 2), (2, 3)]); - let dominators = dominators(&graph); - assert_eq!(dominators.immediate_dominator(0), None); - assert_eq!(dominators.immediate_dominator(1), None); - assert_eq!(dominators.immediate_dominator(2), Some(1)); - assert_eq!(dominators.immediate_dominator(3), Some(2)); + let d = dominators(&graph); + assert_eq!(d.immediate_dominator(0), None); + assert_eq!(d.immediate_dominator(1), None); + assert_eq!(d.immediate_dominator(2), Some(1)); + assert_eq!(d.immediate_dominator(3), Some(2)); } #[test] @@ -75,8 +73,7 @@ fn transitive_dominator() { ], ); - let dom_tree = dominators(&graph); - let immediate_dominators = &dom_tree.immediate_dominators; - assert_eq!(immediate_dominators[2], Some(0)); - assert_eq!(immediate_dominators[3], Some(0)); // This used to return Some(1). + let d = dominators(&graph); + assert_eq!(d.immediate_dominator(2), Some(0)); + assert_eq!(d.immediate_dominator(3), Some(0)); // This used to return Some(1). } |
