Skip to content

Commit 85b2f70

Browse files
committed
mir-opt: Eliminate trivial unnecessary storage annotations
1 parent cc93132 commit 85b2f70

File tree

50 files changed

+179
-556
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+179
-556
lines changed

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,10 @@ impl<'tcx> Statement<'tcx> {
3030
}
3131
let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop);
3232
if !drop_debuginfo {
33-
match replaced_stmt {
34-
StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place)))
35-
if let Some(local) = place.as_local() =>
36-
{
37-
self.debuginfos.push(StmtDebugInfo::AssignRef(local, ref_place));
38-
}
39-
_ => {
40-
bug!("debuginfo is not yet supported.")
41-
}
42-
}
33+
let Some(debuginfo) = replaced_stmt.as_debuginfo() else {
34+
bug!("debuginfo is not yet supported.")
35+
};
36+
self.debuginfos.push(debuginfo);
4337
}
4438
}
4539

compiler/rustc_mir_dataflow/src/impls/liveness.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,10 @@ impl<'a> MaybeTransitiveLiveLocals<'a> {
233233
// Compute the place that we are storing to, if any
234234
let destination = match stmt_kind {
235235
StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove()
236+
// FIXME: We are not sure how we should represent this debugging information for some statements,
237+
// keep it for now.
236238
&& (!debuginfo_locals.contains(place.local)
237-
|| (place.as_local().is_some() && matches!(rvalue, mir::Rvalue::Ref(..)))))
239+
|| (place.as_local().is_some() && stmt_kind.as_debuginfo().is_some())))
238240
.then_some(*place),
239241
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
240242
(!debuginfo_locals.contains(place.local)).then_some(**place)

compiler/rustc_mir_transform/src/dead_store_elimination.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ use rustc_mir_dataflow::impls::{
2222
LivenessTransferFunction, MaybeTransitiveLiveLocals, borrowed_locals,
2323
};
2424

25+
use crate::simplify::UsedInStmtLocals;
2526
use crate::util::is_within_packed;
2627

2728
/// Performs the optimization on the body
2829
///
2930
/// The `borrowed` set must be a `DenseBitSet` of all the locals that are ever borrowed in this
3031
/// body. It can be generated via the [`borrowed_locals`] function.
31-
fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
32+
/// Returns true if any instruction is eliminated.
33+
fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
3234
let borrowed_locals = borrowed_locals(body);
3335

3436
// If the user requests complete debuginfo, mark the locals that appear in it as live, so
@@ -97,8 +99,9 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
9799
}
98100

99101
if patch.is_empty() && call_operands_to_move.is_empty() {
100-
return;
102+
return false;
101103
}
104+
let eliminated = !patch.is_empty();
102105

103106
let bbs = body.basic_blocks.as_mut_preserves_cfg();
104107
for (Location { block, statement_index }, drop_debuginfo) in patch {
@@ -112,6 +115,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
112115
let Operand::Copy(place) = *arg else { bug!() };
113116
*arg = Operand::Move(place);
114117
}
118+
119+
eliminated
115120
}
116121

117122
pub(super) enum DeadStoreElimination {
@@ -132,7 +137,12 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
132137
}
133138

134139
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
135-
eliminate(tcx, body);
140+
if eliminate(tcx, body) {
141+
UsedInStmtLocals::new(body).remove_unused_storage_annotations(body);
142+
for data in body.basic_blocks.as_mut_preserves_cfg() {
143+
data.strip_nops();
144+
}
145+
}
136146
}
137147

138148
fn is_required(&self) -> bool {

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tracing::{debug, instrument, trace, trace_span};
2121

2222
use crate::cost_checker::{CostChecker, is_call_like};
2323
use crate::deref_separator::deref_finder;
24-
use crate::simplify::simplify_cfg;
24+
use crate::simplify::{UsedInStmtLocals, simplify_cfg};
2525
use crate::validate::validate_types;
2626
use crate::{check_inline, util};
2727

@@ -935,7 +935,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
935935
in_cleanup_block: false,
936936
return_block,
937937
tcx,
938-
always_live_locals: DenseBitSet::new_filled(callee_body.local_decls.len()),
938+
always_live_locals: UsedInStmtLocals::new(&callee_body).locals,
939939
};
940940

941941
// Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
@@ -995,6 +995,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
995995
// people working on rust can build with or without debuginfo while
996996
// still getting consistent results from the mir-opt tests.
997997
caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
998+
} else {
999+
for bb in callee_body.basic_blocks_mut() {
1000+
bb.drop_debuginfo();
1001+
}
9981002
}
9991003
caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut());
10001004

compiler/rustc_mir_transform/src/simplify.rs

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@
3535
//! pre-"runtime" MIR!
3636
3737
use itertools::Itertools as _;
38+
use rustc_index::bit_set::DenseBitSet;
3839
use rustc_index::{Idx, IndexSlice, IndexVec};
39-
use rustc_middle::mir::visit::{
40-
MutVisitor, MutatingUseContext, NonUseContext, PlaceContext, Visitor,
41-
};
40+
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
4241
use rustc_middle::mir::*;
4342
use rustc_middle::ty::TyCtxt;
43+
use rustc_mir_dataflow::debuginfo::debuginfo_locals;
4444
use rustc_span::DUMMY_SP;
4545
use smallvec::SmallVec;
4646
use tracing::{debug, trace};
@@ -329,7 +329,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
329329

330330
fn strip_nops(&mut self) {
331331
for blk in self.basic_blocks.iter_mut() {
332-
blk.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop))
332+
blk.strip_nops();
333333
}
334334
}
335335
}
@@ -502,28 +502,39 @@ fn make_local_map<V>(
502502
/// Keeps track of used & unused locals.
503503
struct UsedLocals {
504504
increment: bool,
505-
arg_count: u32,
506505
use_count: IndexVec<Local, u32>,
506+
always_used: DenseBitSet<Local>,
507507
}
508508

509509
impl UsedLocals {
510510
/// Determines which locals are used & unused in the given body.
511511
fn new(body: &Body<'_>) -> Self {
512+
let mut always_used = debuginfo_locals(body);
513+
always_used.insert(RETURN_PLACE);
514+
for arg in body.args_iter() {
515+
always_used.insert(arg);
516+
}
512517
let mut this = Self {
513518
increment: true,
514-
arg_count: body.arg_count.try_into().unwrap(),
515519
use_count: IndexVec::from_elem(0, &body.local_decls),
520+
always_used,
516521
};
517522
this.visit_body(body);
518523
this
519524
}
520525

521526
/// Checks if local is used.
522527
///
523-
/// Return place and arguments are always considered used.
528+
/// Return place, arguments, var debuginfo are always considered used.
524529
fn is_used(&self, local: Local) -> bool {
525-
trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]);
526-
local.as_u32() <= self.arg_count || self.use_count[local] != 0
530+
trace!(
531+
"is_used({:?}): use_count: {:?}, always_used: {}",
532+
local,
533+
self.use_count[local],
534+
self.always_used.contains(local)
535+
);
536+
// To keep things simple, we don't handle debugging information here, these are in DSE.
537+
self.always_used.contains(local) || self.use_count[local] != 0
527538
}
528539

529540
/// Updates the use counts to reflect the removal of given statement.
@@ -568,17 +579,9 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
568579
StatementKind::ConstEvalCounter
569580
| StatementKind::Nop
570581
| StatementKind::StorageLive(..)
571-
| StatementKind::StorageDead(..) => {
572-
for debuginfo in statement.debuginfos.iter() {
573-
self.visit_statement_debuginfo(debuginfo, location);
574-
}
575-
}
576-
582+
| StatementKind::StorageDead(..) => {}
577583
StatementKind::Assign(box (ref place, ref rvalue)) => {
578584
if rvalue.is_safe_to_remove() {
579-
for debuginfo in statement.debuginfos.iter() {
580-
self.visit_statement_debuginfo(debuginfo, location);
581-
}
582585
self.visit_lhs(place, location);
583586
self.visit_rvalue(rvalue, location);
584587
} else {
@@ -589,18 +592,18 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
589592
StatementKind::SetDiscriminant { ref place, variant_index: _ }
590593
| StatementKind::Deinit(ref place)
591594
| StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => {
592-
for debuginfo in statement.debuginfos.iter() {
593-
self.visit_statement_debuginfo(debuginfo, location);
594-
}
595595
self.visit_lhs(place, location);
596596
}
597597
}
598598
}
599599

600600
fn visit_local(&mut self, local: Local, ctx: PlaceContext, _location: Location) {
601+
if matches!(ctx, PlaceContext::NonUse(_)) {
602+
return;
603+
}
601604
if self.increment {
602605
self.use_count[local] += 1;
603-
} else if ctx != PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
606+
} else {
604607
assert_ne!(self.use_count[local], 0);
605608
self.use_count[local] -= 1;
606609
}
@@ -620,28 +623,26 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod
620623

621624
for data in body.basic_blocks.as_mut_preserves_cfg() {
622625
// Remove unnecessary StorageLive and StorageDead annotations.
623-
data.retain_statements(|statement| {
624-
let keep = match &statement.kind {
626+
for statement in data.statements.iter_mut() {
627+
let keep_statement = match &statement.kind {
625628
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
626629
used_locals.is_used(*local)
627630
}
628-
StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
629-
630-
StatementKind::SetDiscriminant { place, .. }
631-
| StatementKind::BackwardIncompatibleDropHint { place, reason: _ }
632-
| StatementKind::Deinit(place) => used_locals.is_used(place.local),
633-
StatementKind::Nop => false,
634-
_ => true,
631+
StatementKind::Assign(box (place, _))
632+
| StatementKind::SetDiscriminant { box place, .. }
633+
| StatementKind::BackwardIncompatibleDropHint { box place, .. }
634+
| StatementKind::Deinit(box place) => used_locals.is_used(place.local),
635+
_ => continue,
635636
};
636-
637-
if !keep {
638-
trace!("removing statement {:?}", statement);
639-
modified = true;
640-
used_locals.statement_removed(statement);
637+
if keep_statement {
638+
continue;
641639
}
642-
643-
keep
644-
});
640+
trace!("removing statement {:?}", statement);
641+
modified = true;
642+
used_locals.statement_removed(statement);
643+
statement.make_nop(true);
644+
}
645+
data.strip_nops();
645646
}
646647
}
647648
}
@@ -660,3 +661,42 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
660661
*l = self.map[*l].unwrap();
661662
}
662663
}
664+
665+
pub(crate) struct UsedInStmtLocals {
666+
pub(crate) locals: DenseBitSet<Local>,
667+
}
668+
669+
impl UsedInStmtLocals {
670+
pub(crate) fn new(body: &Body<'_>) -> Self {
671+
let mut this = Self { locals: DenseBitSet::new_empty(body.local_decls.len()) };
672+
this.visit_body(body);
673+
this
674+
}
675+
676+
pub(crate) fn remove_unused_storage_annotations<'tcx>(&self, body: &mut Body<'tcx>) {
677+
for data in body.basic_blocks.as_mut_preserves_cfg() {
678+
// Remove unnecessary StorageLive and StorageDead annotations.
679+
for statement in data.statements.iter_mut() {
680+
let keep_statement = match &statement.kind {
681+
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
682+
self.locals.contains(*local)
683+
}
684+
_ => continue,
685+
};
686+
if keep_statement {
687+
continue;
688+
}
689+
statement.make_nop(true);
690+
}
691+
}
692+
}
693+
}
694+
695+
impl<'tcx> Visitor<'tcx> for UsedInStmtLocals {
696+
fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
697+
if matches!(context, PlaceContext::NonUse(_)) {
698+
return;
699+
}
700+
self.locals.insert(local);
701+
}
702+
}

tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@
1919
- _3 = copy _2;
2020
- _2 = copy _1;
2121
- _1 = copy _5;
22-
+ nop;
23-
+ nop;
24-
+ nop;
25-
+ nop;
2622
_4 = cond() -> [return: bb1, unwind continue];
2723
}
2824

tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
StorageLive(_2);
1616
- _2 = &((*_1).2: i32);
1717
+ // DBG: _2 = &((*_1).2: i32);
18-
+ nop;
1918
StorageLive(_3);
2019
StorageLive(_4);
2120
_4 = &((*_1).0: i32);

tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212
}
1313

1414
bb0: {
15-
StorageLive(_2);
15+
- StorageLive(_2);
1616
_3 = deref_copy (_1.1: &Foo);
1717
- _2 = &((*_3).2: i32);
1818
+ // DBG: _2 = &((*_3).2: i32);
19-
+ nop;
2019
_4 = deref_copy (_1.1: &Foo);
2120
_0 = copy ((*_4).0: i32);
22-
StorageDead(_2);
21+
- StorageDead(_2);
2322
return;
2423
}
2524
}

tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@
1414
-
1515
- bb1: {
1616
- // DBG: _3 = &((*_1).0: i32);
17-
- nop;
1817
- goto -> bb2;
1918
- }
2019
-
2120
- bb2: {
2221
// DBG: _4 = &((*_1).1: i64);
23-
- nop;
2422
_0 = copy ((*_1).2: i32);
2523
return;
2624
}

tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,13 @@
1717
- bb1: {
1818
(*_2) = const true;
1919
// DBG: _3 = &((*_1).0: i32);
20-
- nop;
2120
- goto -> bb2;
2221
- }
2322
-
2423
- bb2: {
2524
// DBG: _4 = &((*_1).1: i64);
26-
- nop;
2725
_0 = copy ((*_1).2: i32);
2826
// DBG: _5 = &((*_1).2: i32);
29-
- nop;
3027
return;
3128
}
3229
}

0 commit comments

Comments
 (0)