Skip to content

Commit faaedfd

Browse files
committed
mir-opt: Eliminate dead ref statements
1 parent e14f065 commit faaedfd

File tree

47 files changed

+1319
-468
lines changed

Some content is hidden

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

47 files changed

+1319
-468
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
55
use std::borrow::Cow;
66
use std::fmt::{self, Debug, Formatter};
7-
use std::iter;
87
use std::ops::{Index, IndexMut};
8+
use std::{iter, mem};
99

1010
pub use basic_blocks::{BasicBlocks, SwitchTargetValue};
1111
use either::Either;
@@ -1341,6 +1341,10 @@ pub struct BasicBlockData<'tcx> {
13411341
/// List of statements in this block.
13421342
pub statements: Vec<Statement<'tcx>>,
13431343

1344+
/// All debuginfos happen before the statement.
1345+
/// Put debuginfos here when the last statement is eliminated.
1346+
pub after_last_stmt_debuginfos: Vec<StmtDebugInfo<'tcx>>,
1347+
13441348
/// Terminator for this block.
13451349
///
13461350
/// N.B., this should generally ONLY be `None` during construction.
@@ -1368,7 +1372,12 @@ impl<'tcx> BasicBlockData<'tcx> {
13681372
terminator: Option<Terminator<'tcx>>,
13691373
is_cleanup: bool,
13701374
) -> BasicBlockData<'tcx> {
1371-
BasicBlockData { statements, terminator, is_cleanup }
1375+
BasicBlockData {
1376+
statements,
1377+
after_last_stmt_debuginfos: Vec::new(),
1378+
terminator,
1379+
is_cleanup,
1380+
}
13721381
}
13731382

13741383
/// Accessor for terminator.
@@ -1403,6 +1412,23 @@ impl<'tcx> BasicBlockData<'tcx> {
14031412
self.terminator().successors()
14041413
}
14051414
}
1415+
1416+
pub fn retain_statements<F>(&mut self, mut f: F)
1417+
where
1418+
F: FnMut(&Statement<'tcx>) -> bool,
1419+
{
1420+
let mut debuginfos = Vec::new();
1421+
self.statements.retain_mut(|stmt| {
1422+
let retain = f(stmt);
1423+
if retain {
1424+
stmt.debuginfos.splice(0..0, mem::take(&mut debuginfos));
1425+
} else {
1426+
debuginfos.extend_from_slice(&stmt.debuginfos);
1427+
}
1428+
retain
1429+
});
1430+
self.after_last_stmt_debuginfos.extend_from_slice(&debuginfos);
1431+
}
14061432
}
14071433

14081434
///////////////////////////////////////////////////////////////////////////
@@ -1707,7 +1733,7 @@ mod size_asserts {
17071733

17081734
use super::*;
17091735
// tidy-alphabetical-start
1710-
static_assert_size!(BasicBlockData<'_>, 128);
1736+
static_assert_size!(BasicBlockData<'_>, 152);
17111737
static_assert_size!(LocalDecl<'_>, 40);
17121738
static_assert_size!(SourceScopeData<'_>, 64);
17131739
static_assert_size!(Statement<'_>, 56);

compiler/rustc_middle/src/mir/pretty.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,9 @@ where
778778
let mut current_location = Location { block, statement_index: 0 };
779779
for statement in &data.statements {
780780
extra_data(PassWhere::BeforeLocation(current_location), w)?;
781+
for debuginfo in statement.debuginfos.iter() {
782+
writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?}")?;
783+
}
781784
let indented_body = format!("{INDENT}{INDENT}{statement:?};");
782785
if options.include_extra_comments {
783786
writeln!(
@@ -812,6 +815,9 @@ where
812815

813816
// Terminator at the bottom.
814817
extra_data(PassWhere::BeforeLocation(current_location), w)?;
818+
for debuginfo in data.after_last_stmt_debuginfos.iter() {
819+
writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?}")?;
820+
}
815821
if data.terminator.is_some() {
816822
let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
817823
if options.include_extra_comments {

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,33 @@ use crate::ty::CoroutineArgsExt;
1515
pub struct Statement<'tcx> {
1616
pub source_info: SourceInfo,
1717
pub kind: StatementKind<'tcx>,
18-
pub debug_info: Vec<StmtDebugInfo>,
18+
pub debuginfos: Vec<StmtDebugInfo<'tcx>>,
1919
}
2020

2121
impl<'tcx> Statement<'tcx> {
2222
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
2323
/// invalidating statement indices in `Location`s.
24-
pub fn make_nop(&mut self) {
25-
// TODO: convert the stmt to debuginfo.
26-
self.kind = StatementKind::Nop
24+
pub fn make_nop(&mut self, drop_debuginfo: bool) {
25+
if matches!(self.kind, StatementKind::Nop) {
26+
return;
27+
}
28+
let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop);
29+
if !drop_debuginfo {
30+
match replaced_stmt {
31+
StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place)))
32+
if let Some(local) = place.as_local() =>
33+
{
34+
self.debuginfos.push(StmtDebugInfo::AssignRef(local, ref_place));
35+
}
36+
_ => {
37+
bug!("debuginfo is not yet supported.")
38+
}
39+
}
40+
}
2741
}
2842

2943
pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self {
30-
Statement { source_info, kind, debug_info: Vec::new() }
44+
Statement { source_info, kind, debuginfos: Vec::new() }
3145
}
3246
}
3347

@@ -943,4 +957,6 @@ impl RawPtrKind {
943957
}
944958

945959
#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
946-
pub struct StmtDebugInfo {}
960+
pub enum StmtDebugInfo<'tcx> {
961+
AssignRef(Local, Place<'tcx>),
962+
}

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,22 @@ macro_rules! make_mir_visitor {
9595
self.super_source_scope_data(scope_data);
9696
}
9797

98+
fn visit_statement_debuginfos(
99+
&mut self,
100+
stmt_debuginfo: & $($mutability)? [StmtDebugInfo<'tcx>],
101+
location: Location
102+
) {
103+
self.super_statement_debuginfos(stmt_debuginfo, location);
104+
}
105+
106+
fn visit_statement_debuginfo(
107+
&mut self,
108+
stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
109+
location: Location
110+
) {
111+
self.super_statement_debuginfo(stmt_debuginfo, location);
112+
}
113+
98114
fn visit_statement(
99115
&mut self,
100116
statement: & $($mutability)? Statement<'tcx>,
@@ -301,6 +317,7 @@ macro_rules! make_mir_visitor {
301317
{
302318
let BasicBlockData {
303319
statements,
320+
after_last_stmt_debuginfos,
304321
terminator,
305322
is_cleanup: _
306323
} = data;
@@ -312,8 +329,9 @@ macro_rules! make_mir_visitor {
312329
index += 1;
313330
}
314331

332+
let location = Location { block, statement_index: index };
333+
self.visit_statement_debuginfos(after_last_stmt_debuginfos, location);
315334
if let Some(terminator) = terminator {
316-
let location = Location { block, statement_index: index };
317335
self.visit_terminator(terminator, location);
318336
}
319337
}
@@ -376,15 +394,46 @@ macro_rules! make_mir_visitor {
376394
}
377395
}
378396

397+
fn super_statement_debuginfos(
398+
&mut self,
399+
stmt_debuginfo: & $($mutability)? [StmtDebugInfo<'tcx>],
400+
location: Location
401+
) {
402+
for debuginfo in stmt_debuginfo {
403+
self.visit_statement_debuginfo(debuginfo, location);
404+
}
405+
}
406+
407+
fn super_statement_debuginfo(
408+
&mut self,
409+
stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
410+
location: Location
411+
) {
412+
match stmt_debuginfo {
413+
StmtDebugInfo::AssignRef(local, place) => {
414+
self.visit_local(
415+
$(& $mutability)? *local,
416+
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
417+
location
418+
);
419+
self.visit_place(
420+
place,
421+
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
422+
location
423+
);
424+
},
425+
}
426+
}
427+
379428
fn super_statement(
380429
&mut self,
381430
statement: & $($mutability)? Statement<'tcx>,
382431
location: Location
383432
) {
384-
// TODO: visit debuginfo
385-
let Statement { source_info, kind, .. } = statement;
433+
let Statement { source_info, kind, debuginfos } = statement;
386434

387435
self.visit_source_info(source_info);
436+
self.visit_statement_debuginfos(debuginfos, location);
388437
match kind {
389438
StatementKind::Assign(box (place, rvalue)) => {
390439
self.visit_assign(place, rvalue, location);

compiler/rustc_mir_dataflow/src/impls/liveness.rs

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,54 @@ impl DefUse {
205205
/// All of the caveats of `MaybeLiveLocals` apply.
206206
pub struct MaybeTransitiveLiveLocals<'a> {
207207
always_live: &'a DenseBitSet<Local>,
208+
debuginfo_locals: &'a DenseBitSet<Local>,
208209
}
209210

210211
impl<'a> MaybeTransitiveLiveLocals<'a> {
211212
/// The `always_alive` set is the set of locals to which all stores should unconditionally be
212213
/// considered live.
213214
///
214215
/// This should include at least all locals that are ever borrowed.
215-
pub fn new(always_live: &'a DenseBitSet<Local>) -> Self {
216-
MaybeTransitiveLiveLocals { always_live }
216+
pub fn new(
217+
always_live: &'a DenseBitSet<Local>,
218+
debuginfo_locals: &'a DenseBitSet<Local>,
219+
) -> Self {
220+
MaybeTransitiveLiveLocals { always_live, debuginfo_locals }
221+
}
222+
223+
pub fn can_be_removed_if_dead<'tcx>(
224+
stmt_kind: &StatementKind<'tcx>,
225+
always_live: &DenseBitSet<Local>,
226+
debuginfo_locals: &'a DenseBitSet<Local>,
227+
) -> Option<Place<'tcx>> {
228+
// Compute the place that we are storing to, if any
229+
let destination = match stmt_kind {
230+
StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove()
231+
&& (!debuginfo_locals.contains(place.local)
232+
|| (place.as_local().is_some() && matches!(rvalue, mir::Rvalue::Ref(..)))))
233+
.then_some(*place),
234+
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
235+
(!debuginfo_locals.contains(place.local)).then_some(**place)
236+
}
237+
StatementKind::FakeRead(_)
238+
| StatementKind::StorageLive(_)
239+
| StatementKind::StorageDead(_)
240+
| StatementKind::Retag(..)
241+
| StatementKind::AscribeUserType(..)
242+
| StatementKind::PlaceMention(..)
243+
| StatementKind::Coverage(..)
244+
| StatementKind::Intrinsic(..)
245+
| StatementKind::ConstEvalCounter
246+
| StatementKind::BackwardIncompatibleDropHint { .. }
247+
| StatementKind::Nop => None,
248+
};
249+
if let Some(destination) = destination
250+
&& !destination.is_indirect()
251+
&& !always_live.contains(destination.local)
252+
{
253+
return Some(destination);
254+
}
255+
None
217256
}
218257
}
219258

@@ -238,32 +277,12 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
238277
statement: &mir::Statement<'tcx>,
239278
location: Location,
240279
) {
241-
// Compute the place that we are storing to, if any
242-
let destination = match &statement.kind {
243-
StatementKind::Assign(assign) => assign.1.is_safe_to_remove().then_some(assign.0),
244-
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
245-
Some(**place)
246-
}
247-
StatementKind::FakeRead(_)
248-
| StatementKind::StorageLive(_)
249-
| StatementKind::StorageDead(_)
250-
| StatementKind::Retag(..)
251-
| StatementKind::AscribeUserType(..)
252-
| StatementKind::PlaceMention(..)
253-
| StatementKind::Coverage(..)
254-
| StatementKind::Intrinsic(..)
255-
| StatementKind::ConstEvalCounter
256-
| StatementKind::BackwardIncompatibleDropHint { .. }
257-
| StatementKind::Nop => None,
258-
};
259-
if let Some(destination) = destination {
260-
if !destination.is_indirect()
261-
&& !state.contains(destination.local)
262-
&& !self.always_live.contains(destination.local)
263-
{
264-
// This store is dead
265-
return;
266-
}
280+
if let Some(destination) =
281+
Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals)
282+
&& !state.contains(destination.local)
283+
{
284+
// This store is dead
285+
return;
267286
}
268287
TransferFunction(state).visit_statement(statement, location);
269288
}

compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
3636
CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
3737
)
3838
| StatementKind::FakeRead(..)
39-
| StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(),
39+
| StatementKind::BackwardIncompatibleDropHint { .. } => {
40+
statement.make_nop(true)
41+
}
4042
StatementKind::Assign(box (
4143
_,
4244
Rvalue::Cast(

compiler/rustc_mir_transform/src/copy_prop.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
138138
if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind
139139
&& self.storage_to_remove.contains(l)
140140
{
141-
stmt.make_nop();
141+
stmt.make_nop(true);
142142
return;
143143
}
144144

@@ -150,7 +150,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
150150
*rhs
151151
&& lhs == rhs
152152
{
153-
stmt.make_nop();
153+
stmt.make_nop(true);
154154
}
155155
}
156156
}

compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
412412
if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind
413413
&& self.remap.contains(l)
414414
{
415-
s.make_nop();
415+
s.make_nop(true);
416416
}
417417
}
418418

0 commit comments

Comments
 (0)