Optimize dominators for small path graphs
Generalizes the small dominators approach from #107449.
This commit is contained in:
parent
ba694e301c
commit
0528d378b6
@ -26,7 +26,42 @@ rustc_index::newtype_index! {
|
|||||||
struct PreorderIndex {}
|
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
|
// compute the post order index (rank) for each node
|
||||||
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
|
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);
|
let time = compute_access_time(start_node, &immediate_dominators);
|
||||||
|
|
||||||
Dominators { post_order_rank, immediate_dominators, time }
|
Inner { post_order_rank, immediate_dominators, time }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
|
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
|
||||||
@ -310,7 +345,7 @@ fn compress(
|
|||||||
|
|
||||||
/// Tracks the list of dominators for each node.
|
/// Tracks the list of dominators for each node.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Dominators<N: Idx> {
|
struct Inner<N: Idx> {
|
||||||
post_order_rank: IndexVec<N, usize>,
|
post_order_rank: IndexVec<N, usize>,
|
||||||
// Even though we track only the immediate dominator of each node, it's
|
// 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
|
// possible to get its full list of dominators by looking up the dominator
|
||||||
@ -322,12 +357,24 @@ pub struct Dominators<N: Idx> {
|
|||||||
impl<Node: Idx> Dominators<Node> {
|
impl<Node: Idx> Dominators<Node> {
|
||||||
/// Returns true if node is reachable from the start node.
|
/// Returns true if node is reachable from the start node.
|
||||||
pub fn is_reachable(&self, node: Node) -> bool {
|
pub fn is_reachable(&self, node: Node) -> bool {
|
||||||
self.time[node].start != 0
|
match &self.kind {
|
||||||
|
Kind::Path => true,
|
||||||
|
Kind::General(g) => g.time[node].start != 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the immediate dominator of node, if any.
|
/// Returns the immediate dominator of node, if any.
|
||||||
pub fn immediate_dominator(&self, node: Node) -> Option<Node> {
|
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.
|
/// Provides an iterator over each dominator up the CFG, for the given Node.
|
||||||
@ -342,7 +389,10 @@ impl<Node: Idx> Dominators<Node> {
|
|||||||
/// of two unrelated nodes will also be consistent, but otherwise the order has no
|
/// 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.
|
/// 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 {
|
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`.
|
/// Returns true if `a` dominates `b`.
|
||||||
@ -351,11 +401,16 @@ impl<Node: Idx> Dominators<Node> {
|
|||||||
///
|
///
|
||||||
/// Panics if `b` is unreachable.
|
/// Panics if `b` is unreachable.
|
||||||
pub fn dominates(&self, a: Node, b: Node) -> bool {
|
pub fn dominates(&self, a: Node, b: Node) -> bool {
|
||||||
let a = self.time[a];
|
match &self.kind {
|
||||||
let b = self.time[b];
|
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");
|
assert!(b.start != 0, "node {b:?} is not reachable");
|
||||||
a.start <= b.start && b.finish <= a.finish
|
a.start <= b.start && b.finish <= a.finish
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Iter<'dom, Node: Idx> {
|
pub struct Iter<'dom, Node: Idx> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user