Skip to content

Commit 1bbd655

Browse files
committed
Improve efficiency of has_back_edge(...)
1 parent 7618163 commit 1bbd655

File tree

2 files changed

+18
-10
lines changed

2 files changed

+18
-10
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,18 @@ fn compress(
304304
}
305305
}
306306

307+
/// Tracks the list of dominators for each node.
307308
#[derive(Clone, Debug)]
308309
pub struct Dominators<N: Idx> {
309310
post_order_rank: IndexVec<N, usize>,
311+
// Even though we track only the immediate dominator of each node, it's
312+
// possible to get its full list of dominators by looking up the dominator
313+
// of each dominator. (See the `impl Iterator for Iter` definition).
310314
immediate_dominators: IndexVec<N, Option<N>>,
311315
}
312316

313317
impl<Node: Idx> Dominators<Node> {
318+
/// Whether the given Node has an immediate dominator.
314319
pub fn is_reachable(&self, node: Node) -> bool {
315320
self.immediate_dominators[node].is_some()
316321
}
@@ -320,6 +325,8 @@ impl<Node: Idx> Dominators<Node> {
320325
self.immediate_dominators[node].unwrap()
321326
}
322327

328+
/// Provides an iterator over each dominator up the CFG, for the given Node.
329+
/// See the `impl Iterator for Iter` definition to understand how this works.
323330
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
324331
assert!(self.is_reachable(node), "node {node:?} is not reachable");
325332
Iter { dominators: self, node: Some(node) }

compiler/rustc_mir_transform/src/ctfe_limit.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
//! (thus indicating there is a loop in the CFG), or whose terminator is a function call.
33
use crate::MirPass;
44

5+
use rustc_data_structures::graph::dominators::Dominators;
56
use rustc_middle::mir::{
6-
BasicBlock, BasicBlockData, BasicBlocks, Body, Statement, StatementKind, TerminatorKind,
7+
BasicBlock, BasicBlockData, Body, Statement, StatementKind, TerminatorKind,
78
};
89
use rustc_middle::ty::TyCtxt;
910

@@ -12,13 +13,14 @@ pub struct CtfeLimit;
1213
impl<'tcx> MirPass<'tcx> for CtfeLimit {
1314
#[instrument(skip(self, _tcx, body))]
1415
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
16+
let doms = body.basic_blocks.dominators();
1517
let indices: Vec<BasicBlock> = body
1618
.basic_blocks
1719
.iter_enumerated()
1820
.filter_map(|(node, node_data)| {
1921
if matches!(node_data.terminator().kind, TerminatorKind::Call { .. })
2022
// Back edges in a CFG indicate loops
21-
|| has_back_edge(&body.basic_blocks, node, &node_data)
23+
|| has_back_edge(&doms, node, &node_data)
2224
{
2325
Some(node)
2426
} else {
@@ -37,17 +39,16 @@ impl<'tcx> MirPass<'tcx> for CtfeLimit {
3739
}
3840

3941
fn has_back_edge(
40-
basic_blocks: &BasicBlocks<'_>,
42+
doms: &Dominators<BasicBlock>,
4143
node: BasicBlock,
4244
node_data: &BasicBlockData<'_>,
4345
) -> bool {
44-
let doms = basic_blocks.dominators();
45-
basic_blocks.indices().any(|potential_dom| {
46-
doms.is_reachable(potential_dom)
47-
&& doms.is_reachable(node)
48-
&& doms.is_dominated_by(node, potential_dom)
49-
&& node_data.terminator().successors().into_iter().any(|succ| succ == potential_dom)
50-
})
46+
if !doms.is_reachable(node) {
47+
return false;
48+
}
49+
// Check if any of the dominators of the node are also the node's successor.
50+
doms.dominators(node)
51+
.any(|dom| node_data.terminator().successors().into_iter().any(|succ| succ == dom))
5152
}
5253

5354
fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {

0 commit comments

Comments
 (0)