diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index f0fcb44603b15..5c090bf7cad08 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -189,6 +189,7 @@ declare_passes! { mod simplify_comparison_integral : SimplifyComparisonIntegral; mod single_use_consts : SingleUseConsts; mod sroa : ScalarReplacementOfAggregates; + mod strip_debuginfo : StripDebugInfo; mod unreachable_enum_branching : UnreachableEnumBranching; mod unreachable_prop : UnreachablePropagation; mod validate : Validator; @@ -699,6 +700,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &o1(simplify_branches::SimplifyConstCondition::Final), &o1(remove_noop_landing_pads::RemoveNoopLandingPads), &o1(simplify::SimplifyCfg::Final), + // After the last SimplifyCfg, because this wants one-block functions. + &strip_debuginfo::StripDebugInfo, ©_prop::CopyProp, &dead_store_elimination::DeadStoreElimination::Final, &nrvo::RenameReturnPlace, diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs new file mode 100644 index 0000000000000..438c75726bb90 --- /dev/null +++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs @@ -0,0 +1,34 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::MirStripDebugInfo; + +/// Conditionally remove some of the VarDebugInfo in MIR. +/// +/// In particular, stripping non-parameter debug info for tiny, primitive-like +/// methods in core saves work later, and nobody ever wanted to use it anyway. +pub(super) struct StripDebugInfo; + +impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.opts.unstable_opts.mir_strip_debuginfo != MirStripDebugInfo::None + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + match tcx.sess.opts.unstable_opts.mir_strip_debuginfo { + MirStripDebugInfo::None => return, + MirStripDebugInfo::AllLocals => {} + MirStripDebugInfo::LocalsInTinyFunctions + if let TerminatorKind::Return { .. } = + body.basic_blocks[START_BLOCK].terminator().kind => {} + MirStripDebugInfo::LocalsInTinyFunctions => return, + } + + body.var_debug_info.retain(|vdi| { + matches!( + vdi.value, + VarDebugInfoContents::Place(place) + if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE, + ) + }); + } +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index cb6d539cdf940..936c2ca87d69b 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -472,6 +472,13 @@ impl ToString for DebugInfoCompression { } } +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum MirStripDebugInfo { + None, + LocalsInTinyFunctions, + AllLocals, +} + /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform /// uses DWARF for debug-information. @@ -2900,10 +2907,10 @@ pub(crate) mod dep_tracking { BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, - LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - PatchableFunctionEntry, Polonius, RemapPathScopeComponents, ResolveDocLinks, - SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, - WasiExecModel, + LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel, OutFileName, + OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents, + ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, + SymbolManglingVersion, WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; @@ -2971,6 +2978,7 @@ pub(crate) mod dep_tracking { LtoCli, DebugInfo, DebugInfoCompression, + MirStripDebugInfo, CollapseMacroDebuginfo, UnstableFeatures, NativeLib, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b01d9e5e8e3ac..3873a203bd36c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -391,6 +391,8 @@ mod desc { pub(crate) const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub(crate) const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`"; pub(crate) const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`"; + pub(crate) const parse_mir_strip_debuginfo: &str = + "one of `none`, `locals-in-tiny-functions`, or `all-locals`"; pub(crate) const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`"; pub(crate) const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub(crate) const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); @@ -925,6 +927,16 @@ pub mod parse { true } + pub(crate) fn parse_mir_strip_debuginfo(slot: &mut MirStripDebugInfo, v: Option<&str>) -> bool { + match v { + Some("none") => *slot = MirStripDebugInfo::None, + Some("locals-in-tiny-functions") => *slot = MirStripDebugInfo::LocalsInTinyFunctions, + Some("all-locals") => *slot = MirStripDebugInfo::AllLocals, + _ => return false, + }; + true + } + pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { match v.and_then(LinkerFlavorCli::from_str) { Some(lf) => *slot = Some(lf), @@ -1893,6 +1905,8 @@ options! { #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] mir_opt_level: Option = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), + mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED], + "Whether to remove some of the MIR debug info from methods. Default: None"), move_size_limit: Option = (None, parse_opt_number, [TRACKED], "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 6e848628e5cfe..96d3162a8c57d 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1203,6 +1203,11 @@ impl Builder<'_> { // even if we're not going to output debuginfo for the crate we're currently building, // so that it'll be available when downstream consumers of std try to use it. rustflags.arg("-Zinline-mir-preserve-debug"); + + // FIXME: always pass this after the next `#[cfg(bootstrap)]` update. + if compiler.stage != 0 { + rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions"); + } } Cargo { diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index e62adfa0ba664..0b2229ba7d104 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -25,9 +25,10 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big { // CHECK-NOT: call void @llvm.memcpy // For a large type, we expect exactly three `memcpy`s -// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret([56 x i8]) +// CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}(ptr +// CHECK-SAME: sret([56 x i8]){{.+}}[[RESULT:%.+]], ptr{{.+}}%dest, ptr{{.+}}%src) // CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %result, ptr align 8 %dest, i{{.*}} 56, i1 false) +// CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 [[RESULT]], ptr align 8 %dest, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 8 %dest, ptr align 8 %src, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff index 94017f028cccf..56d4d50e967e2 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff @@ -16,7 +16,6 @@ + scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) { + debug pointer => _3; + scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) { -+ debug pointer => _3; + } + } + scope 5 (inlined g::{closure#0}) { diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff index 858f9ace9b40a..751916a00f14d 100644 --- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff @@ -16,7 +16,6 @@ + scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) { + debug pointer => _3; + scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) { -+ debug pointer => _3; + } + } + scope 5 (inlined g::{closure#0}) { diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 2efbb6d990427..3f0d60b46f48b 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -7,48 +7,36 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _9: *const u8; - let mut _10: usize; + let mut _7: *const u8; + let mut _8: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - let mut _8: *mut u8; + let mut _6: *mut u8; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - let mut _7: std::ptr::NonNull; + let mut _5: std::ptr::NonNull; scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { - debug self => _3; - let mut _4: std::ptr::NonNull; + let mut _2: std::ptr::NonNull; scope 7 (inlined Unique::::cast::) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; scope 8 (inlined NonNull::::cast::) { - debug self => _4; - let mut _5: *mut u8; - let mut _6: *const u8; + let mut _3: *mut u8; + let mut _4: *const u8; scope 9 (inlined NonNull::::as_ptr) { - debug self => _4; } } } scope 10 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _7; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; } } scope 11 (inlined NonNull::::as_ptr) { - debug self => _7; } } } } scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _9; - debug len => _10; - let _11: *const [u8]; + debug data => _7; + debug len => _8; + let _9: *const [u8]; scope 13 (inlined core::ub_checks::check_language_ub) { scope 14 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -58,11 +46,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 16 (inlined align_of::) { } scope 17 (inlined slice_from_raw_parts::) { - debug data => _9; - debug len => _10; + debug data => _7; + debug len => _8; scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _9; - debug metadata => _10; + debug data_pointer => _7; } } } @@ -70,37 +57,31 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } bb0: { - StorageLive(_8); - StorageLive(_9); + StorageLive(_6); + StorageLive(_7); + StorageLive(_5); StorageLive(_2); - _2 = &((*_1).0: alloc::raw_vec::RawVec); + _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); StorageLive(_3); - _3 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); - StorageLive(_7); StorageLive(_4); - _4 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - StorageLive(_5); - StorageLive(_6); - _5 = copy _4 as *mut u8 (Transmute); - _6 = copy _5 as *const u8 (PtrToPtr); - _7 = NonNull:: { pointer: move _6 }; - StorageDead(_6); - StorageDead(_5); + _3 = copy _2 as *mut u8 (Transmute); + _4 = copy _3 as *const u8 (PtrToPtr); + _5 = NonNull:: { pointer: move _4 }; StorageDead(_4); - _8 = copy _7 as *mut u8 (Transmute); - StorageDead(_7); StorageDead(_3); - _9 = copy _8 as *const u8 (PtrToPtr); StorageDead(_2); - StorageLive(_10); - _10 = copy ((*_1).1: usize); - StorageLive(_11); - _11 = *const [u8] from (copy _9, copy _10); - _0 = &(*_11); - StorageDead(_11); - StorageDead(_10); + _6 = copy _5 as *mut u8 (Transmute); + StorageDead(_5); + _7 = copy _6 as *const u8 (PtrToPtr); + StorageLive(_8); + _8 = copy ((*_1).1: usize); + StorageLive(_9); + _9 = *const [u8] from (copy _7, copy _8); + _0 = &(*_9); StorageDead(_9); StorageDead(_8); + StorageDead(_7); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 2efbb6d990427..3f0d60b46f48b 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -7,48 +7,36 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; scope 2 (inlined Vec::::as_slice) { debug self => _1; - let mut _9: *const u8; - let mut _10: usize; + let mut _7: *const u8; + let mut _8: usize; scope 3 (inlined Vec::::as_ptr) { debug self => _1; - let mut _2: &alloc::raw_vec::RawVec; - let mut _8: *mut u8; + let mut _6: *mut u8; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { - debug self => _2; - let mut _3: &alloc::raw_vec::RawVecInner; scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) { - debug self => _3; - let mut _7: std::ptr::NonNull; + let mut _5: std::ptr::NonNull; scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) { - debug self => _3; - let mut _4: std::ptr::NonNull; + let mut _2: std::ptr::NonNull; scope 7 (inlined Unique::::cast::) { - debug ((self: Unique).0: std::ptr::NonNull) => _4; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; scope 8 (inlined NonNull::::cast::) { - debug self => _4; - let mut _5: *mut u8; - let mut _6: *const u8; + let mut _3: *mut u8; + let mut _4: *const u8; scope 9 (inlined NonNull::::as_ptr) { - debug self => _4; } } } scope 10 (inlined Unique::::as_non_null_ptr) { - debug ((self: Unique).0: std::ptr::NonNull) => _7; - debug ((self: Unique).1: std::marker::PhantomData) => const PhantomData::; } } scope 11 (inlined NonNull::::as_ptr) { - debug self => _7; } } } } scope 12 (inlined std::slice::from_raw_parts::<'_, u8>) { - debug data => _9; - debug len => _10; - let _11: *const [u8]; + debug data => _7; + debug len => _8; + let _9: *const [u8]; scope 13 (inlined core::ub_checks::check_language_ub) { scope 14 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -58,11 +46,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 16 (inlined align_of::) { } scope 17 (inlined slice_from_raw_parts::) { - debug data => _9; - debug len => _10; + debug data => _7; + debug len => _8; scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _9; - debug metadata => _10; + debug data_pointer => _7; } } } @@ -70,37 +57,31 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } bb0: { - StorageLive(_8); - StorageLive(_9); + StorageLive(_6); + StorageLive(_7); + StorageLive(_5); StorageLive(_2); - _2 = &((*_1).0: alloc::raw_vec::RawVec); + _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); StorageLive(_3); - _3 = &(((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner); - StorageLive(_7); StorageLive(_4); - _4 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - StorageLive(_5); - StorageLive(_6); - _5 = copy _4 as *mut u8 (Transmute); - _6 = copy _5 as *const u8 (PtrToPtr); - _7 = NonNull:: { pointer: move _6 }; - StorageDead(_6); - StorageDead(_5); + _3 = copy _2 as *mut u8 (Transmute); + _4 = copy _3 as *const u8 (PtrToPtr); + _5 = NonNull:: { pointer: move _4 }; StorageDead(_4); - _8 = copy _7 as *mut u8 (Transmute); - StorageDead(_7); StorageDead(_3); - _9 = copy _8 as *const u8 (PtrToPtr); StorageDead(_2); - StorageLive(_10); - _10 = copy ((*_1).1: usize); - StorageLive(_11); - _11 = *const [u8] from (copy _9, copy _10); - _0 = &(*_11); - StorageDead(_11); - StorageDead(_10); + _6 = copy _5 as *mut u8 (Transmute); + StorageDead(_5); + _7 = copy _6 as *const u8 (PtrToPtr); + StorageLive(_8); + _8 = copy ((*_1).1: usize); + StorageLive(_9); + _9 = *const [u8] from (copy _7, copy _8); + _0 = &(*_9); StorageDead(_9); StorageDead(_8); + StorageDead(_7); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/strip_debuginfo.rs b/tests/mir-opt/strip_debuginfo.rs new file mode 100644 index 0000000000000..310609e1e9d5c --- /dev/null +++ b/tests/mir-opt/strip_debuginfo.rs @@ -0,0 +1,39 @@ +//@ revisions: NONE TINY ALL +//@[NONE] compile-flags: -Zmir_strip_debuginfo=none +//@[TINY] compile-flags: -Zmir_strip_debuginfo=locals-in-tiny-functions +//@[ALL] compile-flags: -Zmir_strip_debuginfo=all-locals + +// CHECK: fn tiny_function +fn tiny_function(end: u32) -> u32 { + // CHECK: debug end => _1; + // NONE: debug a => + // NONE: debug b => + // TINY-NOT: debug a => + // TINY-NOT: debug b => + // ALL-NOT: debug a => + // ALL-NOT: debug b => + let a = !end; + let b = a ^ 1; + b +} + +#[inline(never)] +fn opaque(_: u32) {} + +// CHECK: fn looping_function +fn looping_function(end: u32) { + // CHECK: debug end => _1; + // NONE: debug i => + // NONE: debug x => + // TINY: debug i => + // TINY: debug x => + // ALL-NOT: debug i => + // ALL-NOT: debug x => + let mut i = 0; + while i < end { + let x = i ^ 1; + opaque(x); + } +} + +fn main() {}