Skip to content

Commit d0d4e02

Browse files
committed
Iteratively replace pointers.
1 parent b64e911 commit d0d4e02

File tree

3 files changed

+60
-33
lines changed

3 files changed

+60
-33
lines changed

compiler/rustc_mir_transform/src/ref_prop.rs

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
8585
let ssa = SsaLocals::new(body);
8686

8787
let mut replacer = compute_replacement(tcx, body, &ssa);
88-
debug!(?replacer.targets, ?replacer.allowed_replacements, ?replacer.storage_to_remove);
88+
debug!(?replacer.targets);
89+
debug!(?replacer.allowed_replacements);
90+
debug!(?replacer.storage_to_remove);
8991

9092
replacer.visit_body_preserves_cfg(body);
9193

@@ -190,8 +192,11 @@ fn compute_replacement<'tcx>(
190192
continue;
191193
}
192194

195+
// Whether the current local is subject to the uniqueness rule.
196+
let needs_unique = ty.is_mutable_ptr();
197+
193198
// If this a mutable reference that we cannot fully replace, mark it as unknown.
194-
if ty.is_mutable_ptr() && !fully_replacable_locals.contains(local) {
199+
if needs_unique && !fully_replacable_locals.contains(local) {
195200
debug!("not fully replaceable");
196201
continue;
197202
}
@@ -217,18 +222,18 @@ fn compute_replacement<'tcx>(
217222
let mut place = *place;
218223
// Try to see through `place` in order to collapse reborrow chains.
219224
if place.projection.first() == Some(&PlaceElem::Deref)
220-
&& let Value::Pointer(target, refmut) = targets[place.local]
225+
&& let Value::Pointer(target, needs_unique) = targets[place.local]
221226
// Only see through immutable reference and pointers, as we do not know yet if
222227
// mutable references are fully replaced.
223-
&& !refmut
228+
&& !needs_unique
224229
// Only collapse chain if the pointee is definitely live.
225230
&& can_perform_opt(target, location)
226231
{
227232
place = target.project_deeper(&place.projection[1..], tcx);
228233
}
229234
assert_ne!(place.local, local);
230235
if is_constant_place(place) {
231-
targets[local] = Value::Pointer(place, ty.is_mutable_ptr());
236+
targets[local] = Value::Pointer(place, needs_unique);
232237
}
233238
}
234239
// We do not know what to do, so keep as not-a-pointer.
@@ -276,16 +281,35 @@ fn compute_replacement<'tcx>(
276281
return;
277282
}
278283

279-
if let Value::Pointer(target, refmut) = self.targets[place.local]
280-
&& place.projection.first() == Some(&PlaceElem::Deref)
281-
{
282-
let perform_opt = (self.can_perform_opt)(target, loc);
283-
if perform_opt {
284-
self.allowed_replacements.insert((target.local, loc));
285-
} else if refmut {
286-
// This mutable reference is not fully replacable, so drop it.
287-
self.targets[place.local] = Value::Unknown;
284+
if place.projection.first() != Some(&PlaceElem::Deref) {
285+
// This is not a dereference, nothing to do.
286+
return;
287+
}
288+
289+
let mut place = place.as_ref();
290+
loop {
291+
if let Value::Pointer(target, needs_unique) = self.targets[place.local] {
292+
let perform_opt = (self.can_perform_opt)(target, loc);
293+
debug!(?place, ?target, ?needs_unique, ?perform_opt);
294+
295+
// This a reborrow chain, recursively allow the replacement.
296+
//
297+
// This also allows to detect cases where `target.local` is not replacable,
298+
// and mark it as such.
299+
if let &[PlaceElem::Deref] = &target.projection[..] {
300+
assert!(perform_opt);
301+
self.allowed_replacements.insert((target.local, loc));
302+
place.local = target.local;
303+
continue;
304+
} else if perform_opt {
305+
self.allowed_replacements.insert((target.local, loc));
306+
} else if needs_unique {
307+
// This mutable reference is not fully replacable, so drop it.
308+
self.targets[place.local] = Value::Unknown;
309+
}
288310
}
311+
312+
break;
289313
}
290314
}
291315
}
@@ -326,18 +350,23 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
326350
}
327351

328352
fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
329-
if let Value::Pointer(target, _) = self.targets[place.local]
330-
&& place.projection.first() == Some(&PlaceElem::Deref)
331-
{
332-
let perform_opt = matches!(ctxt, PlaceContext::NonUse(_))
333-
|| self.allowed_replacements.contains(&(target.local, loc));
334-
335-
if perform_opt {
336-
*place = target.project_deeper(&place.projection[1..], self.tcx);
337-
self.any_replacement = true;
353+
if place.projection.first() != Some(&PlaceElem::Deref) {
354+
return;
355+
}
356+
357+
loop {
358+
if let Value::Pointer(target, _) = self.targets[place.local] {
359+
let perform_opt = matches!(ctxt, PlaceContext::NonUse(_))
360+
|| self.allowed_replacements.contains(&(target.local, loc));
361+
362+
if perform_opt {
363+
*place = target.project_deeper(&place.projection[1..], self.tcx);
364+
self.any_replacement = true;
365+
continue;
366+
}
338367
}
339-
} else {
340-
self.super_place(place, ctxt, loc);
368+
369+
break;
341370
}
342371
}
343372

tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@
4141
- StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
4242
- _5 = &mut (*_2); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
4343
- _4 = &raw mut (*_5); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
44-
+ _5 = &mut _1; // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
45-
+ _4 = &raw mut (*_2); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
44+
+ _4 = &raw mut _1; // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26
4645
_3 = _4; // scope 2 at $DIR/reference_prop.rs:+3:16: +3:36
4746
- StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+3:36: +3:37
4847
StorageDead(_4); // scope 2 at $DIR/reference_prop.rs:+3:36: +3:37
@@ -55,8 +54,8 @@
5554
- (*_3) = const 4_i32; // scope 6 at $DIR/reference_prop.rs:+7:14: +7:23
5655
- _8 = const (); // scope 6 at $DIR/reference_prop.rs:+7:5: +7:26
5756
- StorageDead(_8); // scope 5 at $DIR/reference_prop.rs:+7:25: +7:26
58-
+ _7 = (*_2); // scope 4 at $DIR/reference_prop.rs:+6:13: +6:18
59-
+ (*_5) = const 4_i32; // scope 6 at $DIR/reference_prop.rs:+7:14: +7:23
57+
+ _7 = _1; // scope 4 at $DIR/reference_prop.rs:+6:13: +6:18
58+
+ _1 = const 4_i32; // scope 6 at $DIR/reference_prop.rs:+7:14: +7:23
6059
StorageLive(_9); // scope 5 at $DIR/reference_prop.rs:+8:6: +8:7
6160
_9 = _7; // scope 5 at $DIR/reference_prop.rs:+8:6: +8:7
6261
StorageLive(_10); // scope 5 at $DIR/reference_prop.rs:+8:9: +8:10

tests/mir-opt/reference_prop.read_through_raw.ReferencePropagation.diff

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@
99
let mut _5: *mut usize; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
1010

1111
bb0: {
12-
_2 = &mut (*_1); // scope 0 at $DIR/reference_prop.rs:+10:13: +10:25
12+
- _2 = &mut (*_1); // scope 0 at $DIR/reference_prop.rs:+10:13: +10:25
1313
- _3 = &mut (*_2); // scope 0 at $DIR/reference_prop.rs:+11:13: +11:26
1414
- _4 = &raw mut (*_2); // scope 0 at $DIR/reference_prop.rs:+12:13: +12:30
1515
- _5 = &raw mut (*_3); // scope 0 at $DIR/reference_prop.rs:+13:13: +13:30
1616
- _0 = (*_4); // scope 0 at $DIR/reference_prop.rs:+15:13: +15:22
1717
- _0 = (*_5); // scope 0 at $DIR/reference_prop.rs:+16:13: +16:22
18-
+ _3 = &mut (*_1); // scope 0 at $DIR/reference_prop.rs:+11:13: +11:26
19-
+ _0 = (*_2); // scope 0 at $DIR/reference_prop.rs:+15:13: +15:22
20-
+ _0 = (*_3); // scope 0 at $DIR/reference_prop.rs:+16:13: +16:22
18+
+ _0 = (*_1); // scope 0 at $DIR/reference_prop.rs:+15:13: +15:22
19+
+ _0 = (*_1); // scope 0 at $DIR/reference_prop.rs:+16:13: +16:22
2120
return; // scope 0 at $DIR/reference_prop.rs:+17:13: +17:21
2221
}
2322
}

0 commit comments

Comments
 (0)