Skip to content

Commit d89c048

Browse files
committed
switch to using MaybeUninitializedPlaces
1 parent 8a5d883 commit d89c048

File tree

2 files changed

+59
-17
lines changed

2 files changed

+59
-17
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,8 +1189,8 @@ impl<'tcx> LocalDecl<'tcx> {
11891189

11901190
/// Returns `true` if this is a DerefTemp
11911191
pub fn is_deref_temp(&self) -> bool {
1192-
match self.local_info() {
1193-
LocalInfo::DerefTemp => true,
1192+
match self.local_info.as_ref() {
1193+
ClearCrossCrate::Set(box LocalInfo::DerefTemp) => true,
11941194
_ => false,
11951195
}
11961196
}

compiler/rustc_mir_transform/src/copy_prop.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use std::borrow::Cow;
2-
31
use rustc_index::IndexSlice;
42
use rustc_index::bit_set::DenseBitSet;
53
use rustc_middle::mir::visit::*;
64
use rustc_middle::mir::*;
75
use rustc_middle::ty::TyCtxt;
8-
use rustc_mir_dataflow::impls::{MaybeStorageDead, always_storage_live_locals};
6+
use rustc_mir_dataflow::impls::MaybeUninitializedPlaces;
7+
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData};
98
use rustc_mir_dataflow::{Analysis, ResultsCursor};
109
use tracing::{debug, instrument};
1110

@@ -51,15 +50,20 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
5150
let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h);
5251

5352
let storage_to_remove = if any_replacement {
54-
let always_live_locals = &always_storage_live_locals(body);
53+
// The replacer will remove tautological moves from the head to the local,
54+
// so we remove them before running `MaybeUninitializedPlaces`.
55+
TautologicalMoveAssignmentRemover { tcx, copy_classes: ssa.copy_classes() }
56+
.visit_body_preserves_cfg(body);
57+
58+
let move_data = MoveData::gather_moves(body, tcx, |_| true);
5559

56-
let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals))
57-
.iterate_to_fixpoint(tcx, body, None)
60+
let maybe_uninit = MaybeUninitializedPlaces::new(tcx, body, &move_data)
61+
.iterate_to_fixpoint(tcx, body, Some("mir_opt::copy_prop"))
5862
.into_results_cursor(body);
5963

6064
let mut storage_checker = StorageChecker {
6165
copy_classes: ssa.copy_classes(),
62-
maybe_storage_dead,
66+
maybe_uninit,
6367
head_storage_to_check,
6468
storage_to_remove: DenseBitSet::new_empty(fully_moved.domain_size()),
6569
};
@@ -126,6 +130,33 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> DenseBitSet<Local> {
126130
fully_moved
127131
}
128132

133+
// The replacer will remove tautological moves from the head to the local, so we want the `MaybeUninitializedPlaces`
134+
struct TautologicalMoveAssignmentRemover<'a, 'tcx> {
135+
tcx: TyCtxt<'tcx>,
136+
copy_classes: &'a IndexSlice<Local, Local>,
137+
}
138+
139+
impl<'tcx> MutVisitor<'tcx> for TautologicalMoveAssignmentRemover<'_, 'tcx> {
140+
fn tcx(&self) -> TyCtxt<'tcx> {
141+
self.tcx
142+
}
143+
144+
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
145+
// Similar to `Replacer::visit_statement`, but only handle moves.
146+
if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind
147+
&& let Rvalue::Use(Operand::Move(rhs)) = *rhs
148+
{
149+
let new_lhs_local = self.copy_classes[lhs.local];
150+
let new_rhs_local = self.copy_classes[rhs.local];
151+
152+
if new_lhs_local == new_rhs_local && lhs.projection == rhs.projection {
153+
debug!(?loc, ?lhs, ?rhs, "removing a to-be-tautological assignment");
154+
stmt.make_nop();
155+
}
156+
}
157+
}
158+
}
159+
129160
/// Utility to help performing substitution of `*pattern` by `target`.
130161
struct Replacer<'a, 'tcx> {
131162
tcx: TyCtxt<'tcx>,
@@ -206,30 +237,41 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
206237
struct StorageChecker<'a, 'tcx> {
207238
storage_to_remove: DenseBitSet<Local>,
208239
head_storage_to_check: DenseBitSet<Local>,
209-
maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>,
240+
maybe_uninit: ResultsCursor<'a, 'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
210241
copy_classes: &'a IndexSlice<Local, Local>,
211242
}
212243

213244
impl<'a, 'tcx> Visitor<'tcx> for StorageChecker<'a, 'tcx> {
214-
fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
245+
fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
215246
if !context.is_use() {
216247
return;
217248
}
218249

219250
let head = self.copy_classes[local];
220-
if self.head_storage_to_check.contains(head) {
221-
self.maybe_storage_dead.seek_after_primary_effect(location);
222251

223-
if self.maybe_storage_dead.get().contains(head) {
252+
if local == head {
253+
// Every original use of the head is known to be initialized, so we don't need to check it.
254+
return;
255+
}
256+
257+
// The head must be initialized at the location of the local, otherwise we must remove it's storage statements.
258+
if self.head_storage_to_check.contains(head)
259+
&& let Some(move_idx) =
260+
self.maybe_uninit.analysis().move_data().rev_lookup.find_local(head)
261+
{
262+
self.maybe_uninit.seek_after_primary_effect(loc);
263+
264+
if self.maybe_uninit.get().contains(move_idx) {
224265
debug!(
225-
?location,
266+
?loc,
226267
?local,
227268
?head,
228-
"found use of local with head at a location in which head is maybe dead, marking head for storage removal"
269+
?move_idx,
270+
"found use of local with head at a location in which it is maybe uninit, marking head for storage statement removal"
229271
);
230272
self.storage_to_remove.insert(head);
231273

232-
// Once we found a use of the head that is maybe dead, we do not need to check it again.
274+
// Once we found a use of the head that is maybe uninit, we do not need to check it again.
233275
self.head_storage_to_check.remove(head);
234276
}
235277
}

0 commit comments

Comments
 (0)