Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preprocess and cache dominator tree #111673

Merged
merged 9 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge DominatorTree and Dominators.
  • Loading branch information
cjgillot committed May 17, 2023
commit fa8598cb5066b3463d53682170cc695af2c1b380
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if self.unwind_edge_count <= 1 {
return;
}
let dom_tree = self.body.basic_blocks.dominator_tree();
let dom_tree = self.body.basic_blocks.dominators();
let mut post_contract_node = FxHashMap::default();
// Reusing the allocation across invocations of the closure
let mut dom_path = vec![];
Expand Down
58 changes: 26 additions & 32 deletions compiler/rustc_data_structures/src/graph/dominators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ rustc_index::newtype_index! {
struct PreorderIndex {}
}

pub fn dominator_tree<G: ControlFlowGraph>(graph: G) -> DominatorTree<G::Node> {
pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
// compute the post order index (rank) for each node
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());

Expand Down Expand Up @@ -244,7 +244,10 @@ pub fn dominator_tree<G: ControlFlowGraph>(graph: G) -> DominatorTree<G::Node> {

let start_node = graph.start_node();
immediate_dominators[start_node] = None;
DominatorTree { start_node, post_order_rank, immediate_dominators }

let time = compute_access_time(start_node, &immediate_dominators);

Dominators { start_node, post_order_rank, immediate_dominators, time }
}

/// Evaluate the link-eval virtual forest, providing the currently minimum semi
Expand Down Expand Up @@ -309,16 +312,17 @@ fn compress(

/// Tracks the list of dominators for each node.
#[derive(Clone, Debug)]
pub struct DominatorTree<N: Idx> {
pub struct Dominators<N: Idx> {
start_node: N,
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
// of each dominator. (See the `impl Iterator for Iter` definition).
immediate_dominators: IndexVec<N, Option<N>>,
time: IndexVec<N, Time>,
}

impl<Node: Idx> DominatorTree<Node> {
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()
Expand All @@ -343,10 +347,22 @@ impl<Node: Idx> DominatorTree<Node> {
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
}

/// Returns true if `a` dominates `b`.
///
/// # Panics
///
/// 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
}
}

pub struct Iter<'dom, Node: Idx> {
dom_tree: &'dom DominatorTree<Node>,
dom_tree: &'dom Dominators<Node>,
node: Option<Node>,
}

Expand All @@ -363,11 +379,6 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
}
}

#[derive(Clone, Debug)]
pub struct Dominators<Node: Idx> {
time: IndexVec<Node, Time>,
}

/// Describes the number of vertices discovered at the time when processing of a particular vertex
/// started and when it finished. Both values are zero for unreachable vertices.
#[derive(Copy, Clone, Default, Debug)]
Expand All @@ -376,27 +387,10 @@ struct Time {
finish: u32,
}

impl<Node: Idx> Dominators<Node> {
pub fn dummy() -> Self {
Self { time: Default::default() }
}

/// Returns true if `a` dominates `b`.
///
/// # Panics
///
/// 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
}
}

pub fn dominators<N: Idx>(tree: &DominatorTree<N>) -> Dominators<N> {
let DominatorTree { start_node, ref immediate_dominators, post_order_rank: _ } = *tree;

fn compute_access_time<N: Idx>(
start_node: N,
immediate_dominators: &IndexSlice<N, Option<N>>,
) -> IndexVec<N, Time> {
// Transpose the dominator tree edges, so that child nodes of vertex v are stored in
// node[edges[v].start..edges[v].end].
let mut edges: IndexVec<N, std::ops::Range<u32>> =
Expand Down Expand Up @@ -446,5 +440,5 @@ pub fn dominators<N: Idx>(tree: &DominatorTree<N>) -> Dominators<N> {
}
}

Dominators { time }
time
}
8 changes: 4 additions & 4 deletions compiler/rustc_data_structures/src/graph/dominators/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::super::tests::TestGraph;
fn diamond() {
let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);

let tree = dominator_tree(&graph);
let tree = dominators(&graph);
let immediate_dominators = &tree.immediate_dominators;
assert_eq!(immediate_dominators[0], None);
assert_eq!(immediate_dominators[1], Some(0));
Expand All @@ -22,7 +22,7 @@ fn paper() {
&[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), (2, 1)],
);

let dom_tree = dominator_tree(&graph);
let dom_tree = dominators(&graph);
let immediate_dominators = &dom_tree.immediate_dominators;
assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph
assert_eq!(immediate_dominators[1], Some(6));
Expand All @@ -41,13 +41,13 @@ fn paper_slt() {
&[(1, 2), (1, 3), (2, 3), (2, 7), (3, 4), (3, 6), (4, 5), (5, 4), (6, 7), (7, 8), (8, 5)],
);

dominator_tree(&graph);
dominators(&graph);
}

#[test]
fn immediate_dominator() {
let graph = TestGraph::new(1, &[(1, 2), (2, 3)]);
let tree = dominator_tree(&graph);
let tree = dominators(&graph);
assert_eq!(tree.immediate_dominator(0), None);
assert_eq!(tree.immediate_dominator(1), None);
assert_eq!(tree.immediate_dominator(2), Some(1));
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_middle/src/mir/basic_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::mir::{BasicBlock, BasicBlockData, Successors, Terminator, TerminatorK

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph;
use rustc_data_structures::graph::dominators::{dominator_tree, DominatorTree};
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::OnceCell;
Expand All @@ -28,7 +27,6 @@ struct Cache {
switch_sources: OnceCell<SwitchSources>,
is_cyclic: OnceCell<bool>,
postorder: OnceCell<Vec<BasicBlock>>,
dominator_tree: OnceCell<DominatorTree<BasicBlock>>,
dominators: OnceCell<Dominators<BasicBlock>>,
}

Expand All @@ -44,12 +42,8 @@ impl<'tcx> BasicBlocks<'tcx> {
*self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self))
}

pub fn dominator_tree(&self) -> &DominatorTree<BasicBlock> {
self.cache.dominator_tree.get_or_init(|| dominator_tree(&self))
}

pub fn dominators(&self) -> &Dominators<BasicBlock> {
self.cache.dominators.get_or_init(|| dominators(self.dominator_tree()))
self.cache.dominators.get_or_init(|| dominators(self))
}

/// Returns predecessors for each basic block.
Expand Down
19 changes: 5 additions & 14 deletions compiler/rustc_mir_transform/src/coverage/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::Error;

use itertools::Itertools;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::dominators::{self, DominatorTree, Dominators};
use rustc_data_structures::graph::dominators::{self, Dominators};
use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
use rustc_index::bit_set::BitSet;
use rustc_index::{IndexSlice, IndexVec};
Expand All @@ -25,7 +25,6 @@ pub(super) struct CoverageGraph {
bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
pub successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
pub predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
dominator_tree: Option<DominatorTree<BasicCoverageBlock>>,
dominators: Option<Dominators<BasicCoverageBlock>>,
}

Expand Down Expand Up @@ -68,17 +67,9 @@ impl CoverageGraph {
}
}

let mut basic_coverage_blocks = Self {
bcbs,
bb_to_bcb,
successors,
predecessors,
dominator_tree: None,
dominators: None,
};
let dominator_tree = dominators::dominator_tree(&basic_coverage_blocks);
let dominators = dominators::dominators(&dominator_tree);
basic_coverage_blocks.dominator_tree = Some(dominator_tree);
let mut basic_coverage_blocks =
Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None };
let dominators = dominators::dominators(&basic_coverage_blocks);
basic_coverage_blocks.dominators = Some(dominators);
basic_coverage_blocks
}
Expand Down Expand Up @@ -227,7 +218,7 @@ impl CoverageGraph {
a: BasicCoverageBlock,
b: BasicCoverageBlock,
) -> Option<Ordering> {
self.dominator_tree.as_ref().unwrap().rank_partial_cmp(a, b)
self.dominators.as_ref().unwrap().rank_partial_cmp(a, b)
}
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_transform/src/ctfe_limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
use crate::MirPass;

use rustc_data_structures::graph::dominators::DominatorTree;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::{
BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
};
Expand All @@ -13,7 +13,7 @@ pub struct CtfeLimit;
impl<'tcx> MirPass<'tcx> for CtfeLimit {
#[instrument(skip(self, _tcx, body))]
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let doms = body.basic_blocks.dominator_tree();
let doms = body.basic_blocks.dominators();
let indices: Vec<BasicBlock> = body
.basic_blocks
.iter_enumerated()
Expand All @@ -39,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for CtfeLimit {
}

fn has_back_edge(
doms: &DominatorTree<BasicBlock>,
doms: &Dominators<BasicBlock>,
node: BasicBlock,
node_data: &BasicBlockData<'_>,
) -> bool {
Expand Down