Skip to content

Commit 3ee4f4f

Browse files
committed
mir-opt: Eliminate dead ref statements
1 parent 7cd9505 commit 3ee4f4f

File tree

56 files changed

+1522
-488
lines changed

Some content is hidden

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

56 files changed

+1522
-488
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11461146
let opt_assignment_rhs_span =
11471147
self.find_assignments(local).first().map(|&location| {
11481148
if let Some(mir::Statement {
1149-
source_info: _,
11501149
kind:
11511150
mir::StatementKind::Assign(box (
11521151
_,

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 41 additions & 4 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;
@@ -1342,6 +1342,10 @@ pub struct BasicBlockData<'tcx> {
13421342
/// List of statements in this block.
13431343
pub statements: Vec<Statement<'tcx>>,
13441344

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

13751384
/// Accessor for terminator.
@@ -1404,6 +1413,34 @@ impl<'tcx> BasicBlockData<'tcx> {
14041413
self.terminator().successors()
14051414
}
14061415
}
1416+
1417+
pub fn retain_statements<F>(&mut self, mut f: F)
1418+
where
1419+
F: FnMut(&Statement<'tcx>) -> bool,
1420+
{
1421+
// Place debuginfos into the next retained statement,
1422+
// this `debuginfos` variable is used to cache debuginfos between two retained statements.
1423+
let mut debuginfos = Vec::new();
1424+
self.statements.retain_mut(|stmt| {
1425+
let retain = f(stmt);
1426+
if retain {
1427+
if !debuginfos.is_empty() {
1428+
if !stmt.debuginfos.is_empty() {
1429+
debuginfos.append(&mut stmt.debuginfos);
1430+
}
1431+
mem::swap(&mut debuginfos, &mut stmt.debuginfos);
1432+
}
1433+
} else {
1434+
if !stmt.debuginfos.is_empty() {
1435+
debuginfos.append(&mut stmt.debuginfos);
1436+
}
1437+
}
1438+
retain
1439+
});
1440+
if !debuginfos.is_empty() {
1441+
self.after_last_stmt_debuginfos.append(&mut debuginfos);
1442+
}
1443+
}
14071444
}
14081445

14091446
///////////////////////////////////////////////////////////////////////////
@@ -1708,10 +1745,10 @@ mod size_asserts {
17081745

17091746
use super::*;
17101747
// tidy-alphabetical-start
1711-
static_assert_size!(BasicBlockData<'_>, 128);
1748+
static_assert_size!(BasicBlockData<'_>, 152);
17121749
static_assert_size!(LocalDecl<'_>, 40);
17131750
static_assert_size!(SourceScopeData<'_>, 64);
1714-
static_assert_size!(Statement<'_>, 32);
1751+
static_assert_size!(Statement<'_>, 56);
17151752
static_assert_size!(Terminator<'_>, 96);
17161753
static_assert_size!(VarDebugInfo<'_>, 88);
17171754
// tidy-alphabetical-end

compiler/rustc_middle/src/mir/pretty.rs

Lines changed: 16 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 {
@@ -891,6 +897,16 @@ impl Debug for Statement<'_> {
891897
}
892898
}
893899

900+
impl Debug for StmtDebugInfo<'_> {
901+
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
902+
match self {
903+
StmtDebugInfo::AssignRef(local, place) => {
904+
write!(fmt, "{local:?} = &{place:?}")
905+
}
906+
}
907+
}
908+
}
909+
894910
impl Display for NonDivergingIntrinsic<'_> {
895911
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
896912
match self {

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,34 @@ use crate::ty::CoroutineArgsExt;
1515
pub struct Statement<'tcx> {
1616
pub source_info: SourceInfo,
1717
pub kind: StatementKind<'tcx>,
18+
/// Some debuginfos appearing before the primary statement.
19+
pub debuginfos: Vec<StmtDebugInfo<'tcx>>,
1820
}
1921

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

2744
pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self {
28-
Statement { source_info, kind }
45+
Statement { source_info, kind, debuginfos: Vec::new() }
2946
}
3047
}
3148

@@ -939,3 +956,8 @@ impl RawPtrKind {
939956
}
940957
}
941958
}
959+
960+
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
961+
pub enum StmtDebugInfo<'tcx> {
962+
AssignRef(Local, Place<'tcx>),
963+
}

compiler/rustc_middle/src/mir/visit.rs

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

98+
fn visit_statement_debuginfo(
99+
&mut self,
100+
stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
101+
location: Location
102+
) {
103+
self.super_statement_debuginfo(stmt_debuginfo, location);
104+
}
105+
98106
fn visit_statement(
99107
&mut self,
100108
statement: & $($mutability)? Statement<'tcx>,
@@ -301,6 +309,7 @@ macro_rules! make_mir_visitor {
301309
{
302310
let BasicBlockData {
303311
statements,
312+
after_last_stmt_debuginfos,
304313
terminator,
305314
is_cleanup: _
306315
} = data;
@@ -312,8 +321,11 @@ macro_rules! make_mir_visitor {
312321
index += 1;
313322
}
314323

324+
let location = Location { block, statement_index: index };
325+
for debuginfo in after_last_stmt_debuginfos as & $($mutability)? [_] {
326+
self.visit_statement_debuginfo(debuginfo, location);
327+
}
315328
if let Some(terminator) = terminator {
316-
let location = Location { block, statement_index: index };
317329
self.visit_terminator(terminator, location);
318330
}
319331
}
@@ -376,14 +388,38 @@ macro_rules! make_mir_visitor {
376388
}
377389
}
378390

391+
fn super_statement_debuginfo(
392+
&mut self,
393+
stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
394+
location: Location
395+
) {
396+
match stmt_debuginfo {
397+
StmtDebugInfo::AssignRef(local, place) => {
398+
self.visit_local(
399+
$(& $mutability)? *local,
400+
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
401+
location
402+
);
403+
self.visit_place(
404+
place,
405+
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
406+
location
407+
);
408+
},
409+
}
410+
}
411+
379412
fn super_statement(
380413
&mut self,
381414
statement: & $($mutability)? Statement<'tcx>,
382415
location: Location
383416
) {
384-
let Statement { source_info, kind } = statement;
417+
let Statement { source_info, kind, debuginfos } = statement;
385418

386419
self.visit_source_info(source_info);
420+
for debuginfo in debuginfos as & $($mutability)? [_] {
421+
self.visit_statement_debuginfo(debuginfo, location);
422+
}
387423
match kind {
388424
StatementKind::Assign(box (place, rvalue)) => {
389425
self.visit_assign(place, rvalue, location);

compiler/rustc_mir_dataflow/src/debuginfo.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ use rustc_middle::mir::*;
55
/// Return the set of locals that appear in debuginfo.
66
pub fn debuginfo_locals(body: &Body<'_>) -> DenseBitSet<Local> {
77
let mut visitor = DebuginfoLocals(DenseBitSet::new_empty(body.local_decls.len()));
8-
for debuginfo in body.var_debug_info.iter() {
9-
visitor.visit_var_debug_info(debuginfo);
10-
}
8+
visitor.visit_body(body);
119
visitor.0
1210
}
1311

1412
struct DebuginfoLocals(DenseBitSet<Local>);
1513

1614
impl Visitor<'_> for DebuginfoLocals {
17-
fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) {
18-
self.0.insert(local);
15+
fn visit_local(&mut self, local: Local, place_context: PlaceContext, _: Location) {
16+
if place_context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
17+
self.0.insert(local);
18+
}
1919
}
2020
}

compiler/rustc_mir_dataflow/src/impls/liveness.rs

Lines changed: 50 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,15 @@ 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+
// FIXME: We can eliminate the statement, but we'll need the statements it depends on
284+
// for debuginfos. We need a way to handle this.
285+
&& !self.debuginfo_locals.contains(destination.local)
286+
{
287+
// This store is dead
288+
return;
267289
}
268290
TransferFunction(state).visit_statement(statement, location);
269291
}

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(

0 commit comments

Comments
 (0)