diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 3f3870cc7bad2..9496ebbdf06c9 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -20,10 +20,12 @@ use rustc_mir_dataflow::Analysis; /// Performs the optimization on the body /// -/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It +/// The `always_live` set must be a `BitSet` of all the locals that are considered always alive and +/// never eliminated. This should be, at least, the set of locals which are ever borrowed in this +/// body. It may include other locals as well if necessary. The minimum set of always alive locals /// can be generated via the [`borrowed_locals`] function. -pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet) { - let mut live = MaybeTransitiveLiveLocals::new(borrowed) +pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, always_live: &BitSet) { + let mut live = MaybeTransitiveLiveLocals::new(always_live) .into_engine(tcx, body) .iterate_to_fixpoint() .into_results_cursor(body); @@ -41,7 +43,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS StatementKind::Assign(box (place, _)) | StatementKind::SetDiscriminant { place: box place, .. } | StatementKind::Deinit(box place) => { - if !place.is_indirect() && !borrowed.contains(place.local) { + if !place.is_indirect() && !always_live.contains(place.local) { live.seek_before_primary_effect(loc); if !live.get().contains(place.local) { patch.push(loc); @@ -80,7 +82,21 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let borrowed = borrowed_locals(body); - eliminate(tcx, body, &borrowed); + let mut always_live = borrowed_locals(body); + + // Include any locals which are used by debuginfo unless we're at a high enough MIR opt + // level that degrading debuginfo is acceptable. + if tcx.sess.mir_opt_level() < 3 { + for x in &body.var_debug_info { + match x.value { + VarDebugInfoContents::Place(p) => { + always_live.insert(p.local); + } + VarDebugInfoContents::Const(..) => {} + } + } + } + + eliminate(tcx, body, &always_live); } } diff --git a/src/test/codegen/debuginfo-constant-locals.rs b/src/test/codegen/debuginfo-constant-locals.rs new file mode 100644 index 0000000000000..95a1b8c9d214e --- /dev/null +++ b/src/test/codegen/debuginfo-constant-locals.rs @@ -0,0 +1,28 @@ +// compile-flags: -g -O + +// Check that simple constant values are preserved in debuginfo across both MIR opts and LLVM opts + +#![crate_type = "lib"] + +#[no_mangle] +pub fn check_it() { + let a = 1; + let b = 42; + + foo(a + b); +} + +#[inline(never)] +fn foo(x: i32) { + std::process::exit(x); +} + +// CHECK-LABEL: @check_it +// CHECK: call void @llvm.dbg.value(metadata i32 1, metadata ![[a_metadata:[0-9]+]], metadata !DIExpression()) +// CHECK: call void @llvm.dbg.value(metadata i32 42, metadata ![[b_metadata:[0-9]+]], metadata !DIExpression()) + +// CHECK: ![[a_metadata]] = !DILocalVariable(name: "a" +// CHECK-SAME: line: 9 + +// CHECK: ![[b_metadata]] = !DILocalVariable(name: "b" +// CHECK-SAME: line: 10 diff --git a/src/test/mir-opt/dead-store-elimination/constant_local_debuginfo.main.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/constant_local_debuginfo.main.DeadStoreElimination.diff index d550775f2bf9a..9e2b6c5e30064 100644 --- a/src/test/mir-opt/dead-store-elimination/constant_local_debuginfo.main.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/constant_local_debuginfo.main.DeadStoreElimination.diff @@ -18,11 +18,9 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/constant-local-debuginfo.rs:+1:9: +1:10 -- _1 = const 1_i32; // scope 0 at $DIR/constant-local-debuginfo.rs:+1:13: +1:14 -+ nop; // scope 0 at $DIR/constant-local-debuginfo.rs:+1:13: +1:14 + _1 = const 1_i32; // scope 0 at $DIR/constant-local-debuginfo.rs:+1:13: +1:14 StorageLive(_2); // scope 1 at $DIR/constant-local-debuginfo.rs:+2:9: +2:10 -- _2 = const 4_i32; // scope 1 at $DIR/constant-local-debuginfo.rs:+2:13: +2:14 -+ nop; // scope 1 at $DIR/constant-local-debuginfo.rs:+2:13: +2:14 + _2 = const 4_i32; // scope 1 at $DIR/constant-local-debuginfo.rs:+2:13: +2:14 StorageLive(_3); // scope 2 at $DIR/constant-local-debuginfo.rs:+4:5: +4:15 StorageLive(_4); // scope 2 at $DIR/constant-local-debuginfo.rs:+4:9: +4:14 StorageLive(_5); // scope 2 at $DIR/constant-local-debuginfo.rs:+4:9: +4:10 diff --git a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff index 58dd788b6afca..8d7049af45ca4 100644 --- a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff @@ -37,25 +37,18 @@ bb3: { StorageLive(_6); // scope 0 at $DIR/cycle.rs:+4:13: +4:17 -- _6 = _3; // scope 0 at $DIR/cycle.rs:+4:20: +4:21 -+ nop; // scope 0 at $DIR/cycle.rs:+4:20: +4:21 + _6 = _3; // scope 0 at $DIR/cycle.rs:+4:20: +4:21 StorageLive(_7); // scope 1 at $DIR/cycle.rs:+5:13: +5:14 -- _7 = _2; // scope 1 at $DIR/cycle.rs:+5:13: +5:14 -- _3 = move _7; // scope 1 at $DIR/cycle.rs:+5:9: +5:14 -+ nop; // scope 1 at $DIR/cycle.rs:+5:13: +5:14 -+ nop; // scope 1 at $DIR/cycle.rs:+5:9: +5:14 + _7 = _2; // scope 1 at $DIR/cycle.rs:+5:13: +5:14 + _3 = move _7; // scope 1 at $DIR/cycle.rs:+5:9: +5:14 StorageDead(_7); // scope 1 at $DIR/cycle.rs:+5:13: +5:14 StorageLive(_8); // scope 1 at $DIR/cycle.rs:+6:13: +6:14 -- _8 = _1; // scope 1 at $DIR/cycle.rs:+6:13: +6:14 -- _2 = move _8; // scope 1 at $DIR/cycle.rs:+6:9: +6:14 -+ nop; // scope 1 at $DIR/cycle.rs:+6:13: +6:14 -+ nop; // scope 1 at $DIR/cycle.rs:+6:9: +6:14 + _8 = _1; // scope 1 at $DIR/cycle.rs:+6:13: +6:14 + _2 = move _8; // scope 1 at $DIR/cycle.rs:+6:9: +6:14 StorageDead(_8); // scope 1 at $DIR/cycle.rs:+6:13: +6:14 StorageLive(_9); // scope 1 at $DIR/cycle.rs:+7:13: +7:17 -- _9 = _6; // scope 1 at $DIR/cycle.rs:+7:13: +7:17 -- _1 = move _9; // scope 1 at $DIR/cycle.rs:+7:9: +7:17 -+ nop; // scope 1 at $DIR/cycle.rs:+7:13: +7:17 -+ nop; // scope 1 at $DIR/cycle.rs:+7:9: +7:17 + _9 = _6; // scope 1 at $DIR/cycle.rs:+7:13: +7:17 + _1 = move _9; // scope 1 at $DIR/cycle.rs:+7:9: +7:17 StorageDead(_9); // scope 1 at $DIR/cycle.rs:+7:16: +7:17 - _4 = const (); // scope 0 at $DIR/cycle.rs:+3:18: +8:6 + nop; // scope 0 at $DIR/cycle.rs:+3:18: +8:6