Improve efficiency of has_back_edge(...)
This commit is contained in:
parent
7618163a1c
commit
1bbd655888
@ -304,13 +304,18 @@ fn compress(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tracks the list of dominators for each node.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Dominators<N: Idx> {
|
pub struct Dominators<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
|
||||||
|
// 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>>,
|
immediate_dominators: IndexVec<N, Option<N>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Node: Idx> Dominators<Node> {
|
impl<Node: Idx> Dominators<Node> {
|
||||||
|
/// Whether the given Node has an immediate dominator.
|
||||||
pub fn is_reachable(&self, node: Node) -> bool {
|
pub fn is_reachable(&self, node: Node) -> bool {
|
||||||
self.immediate_dominators[node].is_some()
|
self.immediate_dominators[node].is_some()
|
||||||
}
|
}
|
||||||
@ -320,6 +325,8 @@ impl<Node: Idx> Dominators<Node> {
|
|||||||
self.immediate_dominators[node].unwrap()
|
self.immediate_dominators[node].unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides an iterator over each dominator up the CFG, for the given Node.
|
||||||
|
/// See the `impl Iterator for Iter` definition to understand how this works.
|
||||||
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
|
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
|
||||||
assert!(self.is_reachable(node), "node {node:?} is not reachable");
|
assert!(self.is_reachable(node), "node {node:?} is not reachable");
|
||||||
Iter { dominators: self, node: Some(node) }
|
Iter { dominators: self, node: Some(node) }
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
|
//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
|
||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
|
|
||||||
|
use rustc_data_structures::graph::dominators::Dominators;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
BasicBlock, BasicBlockData, BasicBlocks, Body, Statement, StatementKind, TerminatorKind,
|
BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
|
||||||
@ -12,13 +13,14 @@ pub struct CtfeLimit;
|
|||||||
impl<'tcx> MirPass<'tcx> for CtfeLimit {
|
impl<'tcx> MirPass<'tcx> for CtfeLimit {
|
||||||
#[instrument(skip(self, _tcx, body))]
|
#[instrument(skip(self, _tcx, body))]
|
||||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
|
let doms = body.basic_blocks.dominators();
|
||||||
let indices: Vec<BasicBlock> = body
|
let indices: Vec<BasicBlock> = body
|
||||||
.basic_blocks
|
.basic_blocks
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.filter_map(|(node, node_data)| {
|
.filter_map(|(node, node_data)| {
|
||||||
if matches!(node_data.terminator().kind, TerminatorKind::Call { .. })
|
if matches!(node_data.terminator().kind, TerminatorKind::Call { .. })
|
||||||
// Back edges in a CFG indicate loops
|
// Back edges in a CFG indicate loops
|
||||||
|| has_back_edge(&body.basic_blocks, node, &node_data)
|
|| has_back_edge(&doms, node, &node_data)
|
||||||
{
|
{
|
||||||
Some(node)
|
Some(node)
|
||||||
} else {
|
} else {
|
||||||
@ -37,17 +39,16 @@ impl<'tcx> MirPass<'tcx> for CtfeLimit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_back_edge(
|
fn has_back_edge(
|
||||||
basic_blocks: &BasicBlocks<'_>,
|
doms: &Dominators<BasicBlock>,
|
||||||
node: BasicBlock,
|
node: BasicBlock,
|
||||||
node_data: &BasicBlockData<'_>,
|
node_data: &BasicBlockData<'_>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let doms = basic_blocks.dominators();
|
if !doms.is_reachable(node) {
|
||||||
basic_blocks.indices().any(|potential_dom| {
|
return false;
|
||||||
doms.is_reachable(potential_dom)
|
}
|
||||||
&& doms.is_reachable(node)
|
// Check if any of the dominators of the node are also the node's successor.
|
||||||
&& doms.is_dominated_by(node, potential_dom)
|
doms.dominators(node)
|
||||||
&& node_data.terminator().successors().into_iter().any(|succ| succ == potential_dom)
|
.any(|dom| node_data.terminator().successors().into_iter().any(|succ| succ == dom))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
|
fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user