Skip to content

Commit e0423d5

Browse files
Remove no-op cleanups as post-mono MIR opt
On cargo this cuts ~5% of the LLVM IR lines we generate (measured with -Cno-prepopulate-passes).
1 parent d41e12f commit e0423d5

File tree

2 files changed

+124
-9
lines changed

2 files changed

+124
-9
lines changed

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,24 +176,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
176176

177177
let mut mir = tcx.instance_mir(instance.def);
178178

179-
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
180-
debug!("fn_abi: {:?}", fn_abi);
181-
182-
if tcx.features().ergonomic_clones() {
183-
let monomorphized_mir = instance.instantiate_mir_and_normalize_erasing_regions(
179+
mir = {
180+
let mut mir = instance.instantiate_mir_and_normalize_erasing_regions(
184181
tcx,
185182
ty::TypingEnv::fully_monomorphized(),
186183
ty::EarlyBinder::bind(mir.clone()),
187184
);
188-
mir = tcx.arena.alloc(optimize_use_clone::<Bx>(cx, monomorphized_mir));
189-
}
185+
186+
if tcx.features().ergonomic_clones() {
187+
mir = optimize_use_clone::<Bx>(cx, mir);
188+
}
189+
mir = optimize_noop_cleanup::<Bx>(cx, mir, instance);
190+
tcx.arena.alloc(mir)
191+
};
192+
193+
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
194+
debug!("fn_abi: {:?}", fn_abi);
190195

191196
let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, &mir);
192197

193198
let start_llbb = Bx::append_block(cx, llfn, "start");
194199
let mut start_bx = Bx::build(cx, start_llbb);
195200

196-
if mir.basic_blocks.iter().any(|bb| {
201+
if mir::traversal::mono_reachable(&mir, tcx, instance).any(|(_, bb)| {
197202
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
198203
}) {
199204
start_bx.set_personality_fn(cx.eh_personality());
@@ -371,6 +376,116 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
371376
mir
372377
}
373378

379+
// FIXME: Move this function to mir::transform when post-mono MIR passes land.
380+
//
381+
/// Detect cases where monomorphized MIR has a cleanup block (or series of blocks) that never does
382+
/// anything, just resumes unwinding.
383+
///
384+
/// This usually results from pre-mono MIR having a no-op drop(...) for a specific type.
385+
fn optimize_noop_cleanup<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
386+
cx: &'a Bx::CodegenCx,
387+
mut mir: Body<'tcx>,
388+
instance: Instance<'tcx>,
389+
) -> Body<'tcx> {
390+
let tcx = cx.tcx();
391+
392+
let mut any_action = DenseBitSet::new_empty(mir.basic_blocks.len());
393+
for (bb, block) in mir.basic_blocks.iter_enumerated() {
394+
if !block.is_cleanup {
395+
// We don't care about non-cleanup blocks.
396+
any_action.insert(bb);
397+
continue;
398+
}
399+
400+
let mut has_actions = false;
401+
for stmt in &block.statements {
402+
match stmt.kind {
403+
mir::StatementKind::SetDiscriminant { .. }
404+
| mir::StatementKind::Deinit(..)
405+
| mir::StatementKind::StorageLive(..)
406+
| mir::StatementKind::StorageDead(..)
407+
| mir::StatementKind::Retag(..)
408+
| mir::StatementKind::Coverage(..)
409+
| mir::StatementKind::Intrinsic(..)
410+
| mir::StatementKind::Assign(..) => {
411+
has_actions = true;
412+
break;
413+
}
414+
mir::StatementKind::FakeRead(..)
415+
| mir::StatementKind::PlaceMention(..)
416+
| mir::StatementKind::AscribeUserType(..)
417+
| mir::StatementKind::ConstEvalCounter
418+
| mir::StatementKind::Nop
419+
| mir::StatementKind::BackwardIncompatibleDropHint { .. } => {}
420+
}
421+
}
422+
match block.terminator().kind {
423+
mir::TerminatorKind::Goto { .. }
424+
| mir::TerminatorKind::SwitchInt { .. }
425+
| mir::TerminatorKind::UnwindResume
426+
| mir::TerminatorKind::Unreachable => {}
427+
428+
mir::TerminatorKind::Call { .. }
429+
| mir::TerminatorKind::Assert { .. }
430+
| mir::TerminatorKind::Yield { .. }
431+
| mir::TerminatorKind::InlineAsm { .. }
432+
| mir::TerminatorKind::CoroutineDrop
433+
| mir::TerminatorKind::TailCall { .. }
434+
| mir::TerminatorKind::UnwindTerminate(..)
435+
| mir::TerminatorKind::Return => has_actions = true,
436+
437+
mir::TerminatorKind::Drop { place, .. } => {
438+
let ty = place.ty(&mir, tcx).ty;
439+
debug!("monomorphize: instance={:?}", instance);
440+
let ty = instance.instantiate_mir_and_normalize_erasing_regions(
441+
tcx,
442+
cx.typing_env(),
443+
ty::EarlyBinder::bind(ty),
444+
);
445+
let drop_fn = Instance::resolve_drop_in_place(tcx, ty);
446+
if let ty::InstanceKind::DropGlue(_, None) = drop_fn.def {
447+
// no need to drop anything
448+
} else {
449+
has_actions = true;
450+
}
451+
}
452+
453+
mir::TerminatorKind::FalseEdge { .. } | mir::TerminatorKind::FalseUnwind { .. } => {
454+
bug!("not present in optimized mir")
455+
}
456+
}
457+
458+
if has_actions {
459+
any_action.insert(bb);
460+
}
461+
}
462+
463+
let mut to_replace = vec![];
464+
for (bb, block) in mir.basic_blocks.iter_enumerated() {
465+
if let Some(mir::UnwindAction::Cleanup(target)) = block.terminator().unwind() {
466+
let mut stack = vec![*target];
467+
let mut found_action = false;
468+
while let Some(next) = stack.pop() {
469+
if any_action.contains(next) {
470+
found_action = true;
471+
break;
472+
}
473+
stack.extend(mir.basic_blocks[next].terminator().successors());
474+
}
475+
if !found_action {
476+
to_replace.push(bb);
477+
}
478+
}
479+
}
480+
481+
for bb in to_replace {
482+
*mir.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap() =
483+
mir::UnwindAction::Continue;
484+
}
485+
486+
mir
487+
}
488+
374489
/// Produces, for each argument, a `Value` pointing at the
375490
/// argument's value. As arguments are places, these are always
376491
/// indirect.

tests/codegen/mem-replace-big-type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big {
2525
// CHECK-NOT: call void @llvm.memcpy
2626

2727
// For a large type, we expect exactly three `memcpy`s
28-
// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}(ptr
28+
// CHECK-LABEL: define void @{{.+}}mem{{.+}}replace{{.+}}(ptr
2929
// CHECK-SAME: sret([56 x i8]){{.+}}[[RESULT:%.+]], ptr{{.+}}%dest, ptr{{.+}}%src)
3030
// CHECK-NOT: call void @llvm.memcpy
3131
// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 [[RESULT]], ptr align 8 %dest, i{{.*}} 56, i1 false)

0 commit comments

Comments
 (0)