Skip to content

Commit bb36e3c

Browse files
simonvandelerikdesjardins
authored andcommitted
Move ZST check inside UsedLocals
1 parent 4e901be commit bb36e3c

File tree

2 files changed

+54
-50
lines changed

2 files changed

+54
-50
lines changed

compiler/rustc_mir/src/transform/simplify.rs

+53-50
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ use crate::transform::MirPass;
3131
use rustc_index::vec::{Idx, IndexVec};
3232
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
3333
use rustc_middle::mir::*;
34+
use rustc_middle::ty::ParamEnv;
3435
use rustc_middle::ty::TyCtxt;
3536
use smallvec::SmallVec;
36-
use std::borrow::Cow;
37-
use std::convert::TryInto;
37+
use std::{borrow::Cow, convert::TryInto};
3838

3939
pub struct SimplifyCfg {
4040
label: String,
@@ -326,17 +326,18 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
326326

327327
pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
328328
// First, we're going to get a count of *actual* uses for every `Local`.
329-
let mut used_locals = UsedLocals::new(body);
329+
let mut used_locals = UsedLocals::new(body, tcx);
330330

331331
// Next, we're going to remove any `Local` with zero actual uses. When we remove those
332332
// `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
333333
// count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
334334
// `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
335335
// fixedpoint where there are no more unused locals.
336-
remove_unused_definitions(&mut used_locals, body, tcx);
336+
remove_unused_definitions(&mut used_locals, body);
337337

338338
// Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
339-
let map = make_local_map(&mut body.local_decls, &used_locals);
339+
let arg_count = body.arg_count.try_into().unwrap();
340+
let map = make_local_map(&mut body.local_decls, &used_locals, arg_count);
340341

341342
// Only bother running the `LocalUpdater` if we actually found locals to remove.
342343
if map.iter().any(Option::is_none) {
@@ -349,54 +350,61 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
349350
}
350351

351352
/// Construct the mapping while swapping out unused stuff out from the `vec`.
352-
fn make_local_map<V>(
353+
fn make_local_map<'tcx, V>(
353354
local_decls: &mut IndexVec<Local, V>,
354-
used_locals: &UsedLocals,
355+
used_locals: &UsedLocals<'tcx>,
356+
arg_count: u32,
355357
) -> IndexVec<Local, Option<Local>> {
356-
let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*local_decls);
358+
let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, local_decls);
357359
let mut used = Local::new(0);
358360

359361
for alive_index in local_decls.indices() {
360-
// `is_used` treats the `RETURN_PLACE` and arguments as used.
361-
if !used_locals.is_used(alive_index) {
362-
continue;
363-
}
364-
365-
map[alive_index] = Some(used);
366-
if alive_index != used {
367-
local_decls.swap(alive_index, used);
362+
// When creating the local map treat the `RETURN_PLACE` and arguments as used.
363+
if alive_index.as_u32() <= arg_count || used_locals.is_used(alive_index) {
364+
map[alive_index] = Some(used);
365+
if alive_index != used {
366+
local_decls.swap(alive_index, used);
367+
}
368+
used.increment_by(1);
368369
}
369-
used.increment_by(1);
370370
}
371371
local_decls.truncate(used.index());
372372
map
373373
}
374374

375375
/// Keeps track of used & unused locals.
376-
struct UsedLocals {
376+
struct UsedLocals<'tcx> {
377377
increment: bool,
378-
arg_count: u32,
379378
use_count: IndexVec<Local, u32>,
379+
is_static: bool,
380+
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
381+
param_env: ParamEnv<'tcx>,
382+
tcx: TyCtxt<'tcx>,
380383
}
381384

382-
impl UsedLocals {
385+
impl UsedLocals<'tcx> {
383386
/// Determines which locals are used & unused in the given body.
384-
fn new(body: &Body<'_>) -> Self {
387+
fn new(body: &Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
388+
let def_id = body.source.def_id();
389+
let is_static = tcx.is_static(def_id);
390+
let param_env = tcx.param_env(def_id);
391+
let local_decls = body.local_decls.clone();
385392
let mut this = Self {
386393
increment: true,
387-
arg_count: body.arg_count.try_into().unwrap(),
388394
use_count: IndexVec::from_elem(0, &body.local_decls),
395+
is_static,
396+
local_decls,
397+
param_env,
398+
tcx,
389399
};
390400
this.visit_body(body);
391401
this
392402
}
393403

394404
/// Checks if local is used.
395-
///
396-
/// Return place and arguments are always considered used.
397405
fn is_used(&self, local: Local) -> bool {
398406
trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]);
399-
local.as_u32() <= self.arg_count || self.use_count[local] != 0
407+
self.use_count[local] != 0
400408
}
401409

402410
/// Updates the use counts to reflect the removal of given statement.
@@ -424,7 +432,7 @@ impl UsedLocals {
424432
}
425433
}
426434

427-
impl Visitor<'_> for UsedLocals {
435+
impl Visitor<'tcx> for UsedLocals<'tcx> {
428436
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
429437
match statement.kind {
430438
StatementKind::LlvmInlineAsm(..)
@@ -451,7 +459,23 @@ impl Visitor<'_> for UsedLocals {
451459
}
452460
}
453461

454-
fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) {
462+
fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _location: Location) {
463+
debug!("local: {:?} is_static: {:?}, ctx: {:?}", local, self.is_static, ctx);
464+
// Do not count a local as used in `_local = <rhs>` if RHS is a ZST.
465+
let store = matches!(ctx, PlaceContext::MutatingUse(MutatingUseContext::Store));
466+
// Do not count _0 as a used in `return;` if it is a ZST.
467+
let return_place = *local == RETURN_PLACE
468+
&& matches!(ctx, PlaceContext::NonMutatingUse(visit::NonMutatingUseContext::Move));
469+
if !self.is_static && (store || return_place) {
470+
let ty = self.local_decls[*local].ty;
471+
let param_env_and = self.param_env.and(ty);
472+
if let Ok(layout) = self.tcx.layout_of(param_env_and) {
473+
debug!("layout.is_zst: {:?}", layout.is_zst());
474+
if layout.is_zst() {
475+
return;
476+
}
477+
}
478+
}
455479
if self.increment {
456480
self.use_count[*local] += 1;
457481
} else {
@@ -463,21 +487,14 @@ impl Visitor<'_> for UsedLocals {
463487

464488
/// Removes unused definitions. Updates the used locals to reflect the changes made.
465489
fn remove_unused_definitions<'a, 'tcx>(
466-
used_locals: &'a mut UsedLocals,
490+
used_locals: &'a mut UsedLocals<'tcx>,
467491
body: &mut Body<'tcx>,
468-
tcx: TyCtxt<'tcx>,
469492
) {
470493
// The use counts are updated as we remove the statements. A local might become unused
471494
// during the retain operation, leading to a temporary inconsistency (storage statements or
472495
// definitions referencing the local might remain). For correctness it is crucial that this
473496
// computation reaches a fixed point.
474497

475-
let def_id = body.source.def_id();
476-
let is_static = tcx.is_static(def_id);
477-
let param_env = tcx.param_env(def_id);
478-
479-
let local_decls = body.local_decls.clone();
480-
481498
let mut modified = true;
482499
while modified {
483500
modified = false;
@@ -489,21 +506,7 @@ fn remove_unused_definitions<'a, 'tcx>(
489506
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
490507
used_locals.is_used(*local)
491508
}
492-
StatementKind::Assign(box (place, _)) => {
493-
let used = used_locals.is_used(place.local);
494-
let mut is_zst = false;
495-
496-
// ZST locals can be removed
497-
if used && !is_static {
498-
let ty = local_decls[place.local].ty;
499-
let param_env_and = param_env.and(ty);
500-
if let Ok(layout) = tcx.layout_of(param_env_and) {
501-
is_zst = layout.is_zst();
502-
}
503-
}
504-
505-
used && !is_zst
506-
}
509+
StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
507510

508511
StatementKind::SetDiscriminant { ref place, .. } => {
509512
used_locals.is_used(place.local)

src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fn main() -> () {
2828
StorageLive(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
2929
_5 = move (_3.0: ()); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
3030
StorageLive(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
31+
_6 = const (); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
3132
StorageDead(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
3233
StorageDead(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
3334
StorageDead(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:9: 6:10

0 commit comments

Comments
 (0)