Auto merge of #147099 - cjgillot:split-nop-landing, r=lcnr

Refactor remove_noop_landing_pads in two loops.

The point is to avoid clearing the CFG cache as often.

r? `@ghost` for perf
This commit is contained in:
bors 2025-10-07 03:31:27 +00:00
commit d773bd07d6

View file

@ -1,7 +1,7 @@
use rustc_index::bit_set::DenseBitSet;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use tracing::debug;
use tracing::{debug, instrument};
use crate::patch::MirPatch;
@ -15,6 +15,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
sess.panic_strategy().unwinds()
}
#[instrument(level = "debug", skip(self, _tcx, body))]
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
debug!(?def_id);
@ -25,7 +26,24 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
.iter_enumerated()
.any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume));
if !has_resume {
debug!("remove_noop_landing_pads: no resume block in MIR");
debug!("no resume block in MIR");
return;
}
let mut nop_landing_pads = DenseBitSet::new_empty(body.basic_blocks.len());
// This is a post-order traversal, so that if A post-dominates B
// then A will be visited before B.
for (bb, bbdata) in traversal::postorder(body) {
let is_nop_landing_pad = self.is_nop_landing_pad(bbdata, &nop_landing_pads);
debug!("is_nop_landing_pad({bb:?}) = {is_nop_landing_pad}");
if is_nop_landing_pad {
nop_landing_pads.insert(bb);
}
}
if nop_landing_pads.is_empty() {
debug!("no nop landing pads in MIR");
return;
}
@ -36,42 +54,27 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
patch.apply(body);
resume_block
};
debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
debug!(?resume_block);
let mut jumps_folded = 0;
let mut landing_pads_removed = 0;
let mut nop_landing_pads = DenseBitSet::new_empty(body.basic_blocks.len());
let basic_blocks = body.basic_blocks.as_mut();
for (bb, bbdata) in basic_blocks.iter_enumerated_mut() {
debug!("processing {:?}", bb);
// This is a post-order traversal, so that if A post-dominates B
// then A will be visited before B.
let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
for bb in postorder {
debug!(" processing {:?}", bb);
if let Some(unwind) = body[bb].terminator_mut().unwind_mut()
if let Some(unwind) = bbdata.terminator_mut().unwind_mut()
&& let UnwindAction::Cleanup(unwind_bb) = *unwind
&& nop_landing_pads.contains(unwind_bb)
{
debug!(" removing noop landing pad");
landing_pads_removed += 1;
*unwind = UnwindAction::Continue;
}
body[bb].terminator_mut().successors_mut(|target| {
bbdata.terminator_mut().successors_mut(|target| {
if *target != resume_block && nop_landing_pads.contains(*target) {
debug!(" folding noop jump to {:?} to resume block", target);
*target = resume_block;
jumps_folded += 1;
}
});
let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
if is_nop_landing_pad {
nop_landing_pads.insert(bb);
}
debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
}
debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
}
fn is_required(&self) -> bool {
@ -82,11 +85,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
impl RemoveNoopLandingPads {
fn is_nop_landing_pad(
&self,
bb: BasicBlock,
body: &Body<'_>,
bbdata: &BasicBlockData<'_>,
nop_landing_pads: &DenseBitSet<BasicBlock>,
) -> bool {
for stmt in &body[bb].statements {
for stmt in &bbdata.statements {
match &stmt.kind {
StatementKind::FakeRead(..)
| StatementKind::StorageLive(_)
@ -119,7 +121,7 @@ impl RemoveNoopLandingPads {
}
}
let terminator = body[bb].terminator();
let terminator = bbdata.terminator();
match terminator.kind {
TerminatorKind::Goto { .. }
| TerminatorKind::UnwindResume