Skip to content

Commit b6f5a49

Browse files
authored
Rollup merge of rust-lang#143208 - Mark-Simulacrum:skip-noop-cleanup, r=oli-obk
Apply RemoveNoopLandingPads post-monomorphization On cargo this cuts ~5% of the LLVM IR lines we generate (measured with -Cno-prepopulate-passes).
2 parents 5764724 + ec26dde commit b6f5a49

File tree

8 files changed

+180
-77
lines changed

8 files changed

+180
-77
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,7 @@ dependencies = [
35843584
"rustc_macros",
35853585
"rustc_metadata",
35863586
"rustc_middle",
3587+
"rustc_mir_transform",
35873588
"rustc_query_system",
35883589
"rustc_serialize",
35893590
"rustc_session",

compiler/rustc_codegen_ssa/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ rustc_index = { path = "../rustc_index" }
3030
rustc_macros = { path = "../rustc_macros" }
3131
rustc_metadata = { path = "../rustc_metadata" }
3232
rustc_middle = { path = "../rustc_middle" }
33+
rustc_mir_transform = { path = "../rustc_mir_transform" }
3334
rustc_query_system = { path = "../rustc_query_system" }
3435
rustc_serialize = { path = "../rustc_serialize" }
3536
rustc_session = { path = "../rustc_session" }

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,14 @@ impl CleanupKind {
278278
/// MSVC requires unwinding code to be split to a tree of *funclets*, where each funclet can only
279279
/// branch to itself or to its parent. Luckily, the code we generates matches this pattern.
280280
/// Recover that structure in an analyze pass.
281-
pub(crate) fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKind> {
281+
pub(crate) fn cleanup_kinds(
282+
mir: &mir::Body<'_>,
283+
nop_landing_pads: &DenseBitSet<mir::BasicBlock>,
284+
) -> IndexVec<mir::BasicBlock, CleanupKind> {
282285
fn discover_masters<'tcx>(
283286
result: &mut IndexSlice<mir::BasicBlock, CleanupKind>,
284287
mir: &mir::Body<'tcx>,
288+
nop_landing_pads: &DenseBitSet<mir::BasicBlock>,
285289
) {
286290
for (bb, data) in mir.basic_blocks.iter_enumerated() {
287291
match data.terminator().kind {
@@ -300,7 +304,9 @@ pub(crate) fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, Cl
300304
| TerminatorKind::InlineAsm { unwind, .. }
301305
| TerminatorKind::Assert { unwind, .. }
302306
| TerminatorKind::Drop { unwind, .. } => {
303-
if let mir::UnwindAction::Cleanup(unwind) = unwind {
307+
if let mir::UnwindAction::Cleanup(unwind) = unwind
308+
&& !nop_landing_pads.contains(unwind)
309+
{
304310
debug!(
305311
"cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
306312
bb, data, unwind
@@ -381,7 +387,7 @@ pub(crate) fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, Cl
381387

382388
let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, &mir.basic_blocks);
383389

384-
discover_masters(&mut result, mir);
390+
discover_masters(&mut result, mir, &nop_landing_pads);
385391
propagate(&mut result, mir);
386392
debug!("cleanup_kinds: result={:?}", result);
387393
result

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
200200
}
201201

202202
let unwind_block = match unwind {
203-
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
203+
mir::UnwindAction::Cleanup(cleanup) => {
204+
if !fx.nop_landing_pads.contains(cleanup) {
205+
Some(self.llbb_with_cleanup(fx, cleanup))
206+
} else {
207+
None
208+
}
209+
}
204210
mir::UnwindAction::Continue => None,
205211
mir::UnwindAction::Unreachable => None,
206212
mir::UnwindAction::Terminate(reason) => {
@@ -286,7 +292,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
286292
mergeable_succ: bool,
287293
) -> MergingSucc {
288294
let unwind_target = match unwind {
289-
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
295+
mir::UnwindAction::Cleanup(cleanup) => {
296+
if !fx.nop_landing_pads.contains(cleanup) {
297+
Some(self.llbb_with_cleanup(fx, cleanup))
298+
} else {
299+
None
300+
}
301+
}
290302
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)),
291303
mir::UnwindAction::Continue => None,
292304
mir::UnwindAction::Unreachable => None,

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
9797
/// A cold block is a block that is unlikely to be executed at runtime.
9898
cold_blocks: IndexVec<mir::BasicBlock, bool>,
9999

100+
nop_landing_pads: DenseBitSet<mir::BasicBlock>,
101+
100102
/// The location where each MIR arg/var/tmp/ret is stored. This is
101103
/// usually an `PlaceRef` representing an alloca, but not always:
102104
/// sometimes we can skip the alloca and just store the value
@@ -181,8 +183,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
181183

182184
let mut mir = tcx.instance_mir(instance.def);
183185

184-
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
185-
debug!("fn_abi: {:?}", fn_abi);
186+
let nop_landing_pads = rustc_mir_transform::remove_noop_landing_pads::find_noop_landing_pads(
187+
mir,
188+
Some(rustc_mir_transform::remove_noop_landing_pads::ExtraInfo {
189+
tcx,
190+
instance,
191+
typing_env: cx.typing_env(),
192+
}),
193+
);
186194

187195
if tcx.features().ergonomic_clones() {
188196
let monomorphized_mir = instance.instantiate_mir_and_normalize_erasing_regions(
@@ -193,19 +201,23 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
193201
mir = tcx.arena.alloc(optimize_use_clone::<Bx>(cx, monomorphized_mir));
194202
}
195203

204+
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
205+
debug!("fn_abi: {:?}", fn_abi);
206+
196207
let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, &mir);
197208

198209
let start_llbb = Bx::append_block(cx, llfn, "start");
199210
let mut start_bx = Bx::build(cx, start_llbb);
200211

201-
if mir.basic_blocks.iter().any(|bb| {
202-
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
212+
if mir::traversal::mono_reachable(&mir, tcx, instance).any(|(bb, block)| {
213+
(block.is_cleanup && !nop_landing_pads.contains(bb))
214+
|| matches!(block.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
203215
}) {
204216
start_bx.set_personality_fn(cx.eh_personality());
205217
}
206218

207-
let cleanup_kinds =
208-
base::wants_new_eh_instructions(tcx.sess).then(|| analyze::cleanup_kinds(&mir));
219+
let cleanup_kinds = base::wants_new_eh_instructions(tcx.sess)
220+
.then(|| analyze::cleanup_kinds(&mir, &nop_landing_pads));
209221

210222
let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> =
211223
mir.basic_blocks
@@ -233,6 +245,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
233245
debug_context,
234246
per_local_var_debug_info: None,
235247
caller_location: None,
248+
nop_landing_pads,
236249
};
237250

238251
// It may seem like we should iterate over `required_consts` to ensure they all successfully
@@ -244,7 +257,36 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
244257
fx.compute_per_local_var_debug_info(&mut start_bx).unzip();
245258
fx.per_local_var_debug_info = per_local_var_debug_info;
246259

247-
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, tcx, instance);
260+
let mut traversal_order = traversal::mono_reachable_reverse_postorder(mir, tcx, instance);
261+
262+
// Filter out blocks that won't be codegen'd because of nop_landing_pads optimization.
263+
// FIXME: We might want to integrate the nop_landing_pads analysis into mono reachability.
264+
{
265+
let mut reachable = DenseBitSet::new_empty(mir.basic_blocks.len());
266+
let mut to_visit = vec![mir::START_BLOCK];
267+
while let Some(next) = to_visit.pop() {
268+
if !reachable.insert(next) {
269+
continue;
270+
}
271+
272+
let block = &mir.basic_blocks[next];
273+
if let Some(mir::UnwindAction::Cleanup(target)) = block.terminator().unwind()
274+
&& fx.nop_landing_pads.contains(*target)
275+
{
276+
// This edge will not be followed when we actually codegen, so skip generating it here.
277+
//
278+
// It's guaranteed that the cleanup block (`target`) occurs only in
279+
// UnwindAction::Cleanup(...) -- i.e., we can't incorrectly filter too much here --
280+
// because cleanup transitions must happen via UnwindAction::Cleanup.
281+
to_visit.extend(block.terminator().successors().filter(|s| s != target));
282+
} else {
283+
to_visit.extend(block.terminator().successors());
284+
}
285+
}
286+
287+
traversal_order.retain(|bb| reachable.contains(*bb));
288+
}
289+
248290
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order);
249291

250292
// Allocate variable and temp allocas

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ declare_passes! {
159159
mod prettify : ReorderBasicBlocks, ReorderLocals;
160160
mod promote_consts : PromoteTemps;
161161
mod ref_prop : ReferencePropagation;
162-
mod remove_noop_landing_pads : RemoveNoopLandingPads;
162+
pub mod remove_noop_landing_pads : RemoveNoopLandingPads;
163163
mod remove_place_mention : RemovePlaceMention;
164164
mod remove_storage_markers : RemoveStorageMarkers;
165165
mod remove_uninit_drops : RemoveUninitDrops;

0 commit comments

Comments
 (0)