Skip to content

Commit 99f6bcf

Browse files
committed
Unify a source with all possible destinations.
1 parent 4e9dd1b commit 99f6bcf

8 files changed

+75
-93
lines changed

compiler/rustc_mir_transform/src/dest_prop.rs

Lines changed: 39 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -190,29 +190,51 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
190190
for (src, candidates) in candidates.c.into_iter() {
191191
trace!(?src, ?candidates);
192192

193-
let Some(src) = relevant.find(src) else { continue };
194-
let Some(src_live_ranges) = &live.row(src) else { continue };
195-
trace!(?src, ?src_live_ranges);
196-
197-
let dst = candidates.into_iter().find_map(|dst| {
198-
let dst = relevant.find(dst)?;
199-
let dst_live_ranges = &live.row(dst)?;
193+
for dst in candidates {
194+
// We call `relevant.find(src)` inside the loop, as a previous iteration may have
195+
// renamed `src` to one of the locals in `dst`.
196+
let Some(mut src) = relevant.find(src) else { continue };
197+
let Some(src_live_ranges) = live.row(src) else { continue };
198+
trace!(?src, ?src_live_ranges);
199+
200+
let Some(mut dst) = relevant.find(dst) else { continue };
201+
let Some(dst_live_ranges) = live.row(dst) else { continue };
200202
trace!(?dst, ?dst_live_ranges);
201203

202-
let disjoint = src_live_ranges.disjoint(dst_live_ranges);
203-
disjoint.then_some(dst)
204-
});
205-
let Some(dst) = dst else { continue };
204+
if src_live_ranges.disjoint(dst_live_ranges) {
205+
// We want to replace `src` by `dst`.
206+
let mut orig_src = relevant.original[src];
207+
let mut orig_dst = relevant.original[dst];
208+
209+
// The return place and function arguments are required and cannot be renamed.
210+
// This check cannot be made during candidate collection, as we may want to
211+
// unify the same non-required local with several required locals.
212+
match (is_local_required(orig_src, body), is_local_required(orig_dst, body)) {
213+
// Renaming `src` is ok.
214+
(false, _) => {}
215+
// Renaming `src` is wrong, but renaming `dst` is ok.
216+
(true, false) => {
217+
std::mem::swap(&mut src, &mut dst);
218+
std::mem::swap(&mut orig_src, &mut orig_dst);
219+
}
220+
// Neither local can be renamed, so skip this case.
221+
(true, true) => continue,
222+
}
206223

207-
merged_locals.insert(relevant.original[src]);
208-
merged_locals.insert(relevant.original[dst]);
224+
trace!(?src, ?dst, "merge");
225+
merged_locals.insert(orig_src);
226+
merged_locals.insert(orig_dst);
209227

210-
relevant.union(src, dst);
211-
live.union_rows(src, dst);
228+
// Replace `src` by `dst`.
229+
relevant.union(src, dst);
230+
live.union_rows(/* read */ src, /* write */ dst);
231+
}
232+
}
212233
}
213234
trace!(?merged_locals);
214235

215236
relevant.make_idempotent();
237+
trace!(?relevant.renames);
216238

217239
if merged_locals.is_empty() {
218240
return;
@@ -402,41 +424,6 @@ impl Candidates {
402424
}
403425
}
404426

405-
/// If the pair of places is being considered for merging, returns the candidate which would be
406-
/// merged in order to accomplish this.
407-
///
408-
/// The contract here is in one direction - there is a guarantee that merging the locals that are
409-
/// outputted by this function would result in an assignment between the inputs becoming a
410-
/// self-assignment. However, there is no guarantee that the returned pair is actually suitable for
411-
/// merging - candidate collection must still check this independently.
412-
///
413-
/// This output is unique for each unordered pair of input places.
414-
fn places_to_candidate_pair<'tcx>(
415-
a: Place<'tcx>,
416-
b: Place<'tcx>,
417-
body: &Body<'tcx>,
418-
) -> Option<(Local, Local)> {
419-
let (mut a, mut b) = if a.projection.len() == 0 && b.projection.len() == 0 {
420-
(a.local, b.local)
421-
} else {
422-
return None;
423-
};
424-
425-
// By sorting, we make sure we're input order independent
426-
if a > b {
427-
std::mem::swap(&mut a, &mut b);
428-
}
429-
430-
// We could now return `(a, b)`, but then we miss some candidates in the case where `a` can't be
431-
// used as a `src`.
432-
if is_local_required(a, body) {
433-
std::mem::swap(&mut a, &mut b);
434-
}
435-
// We could check `is_local_required` again here, but there's no need - after all, we make no
436-
// promise that the candidate pair is actually valid
437-
Some((a, b))
438-
}
439-
440427
struct FindAssignments<'a, 'tcx> {
441428
body: &'a Body<'tcx>,
442429
candidates: FxIndexMap<Local, Vec<Local>>,
@@ -449,11 +436,9 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
449436
lhs,
450437
Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
451438
)) = &statement.kind
439+
&& let Some(src) = lhs.as_local()
440+
&& let Some(dest) = rhs.as_local()
452441
{
453-
let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
454-
return;
455-
};
456-
457442
// As described at the top of the file, we do not go near things that have
458443
// their address taken.
459444
if self.borrowed.contains(src) || self.borrowed.contains(dest) {
@@ -470,11 +455,6 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
470455
return;
471456
}
472457

473-
// Also, we need to make sure that MIR actually allows the `src` to be removed
474-
if is_local_required(src, self.body) {
475-
return;
476-
}
477-
478458
// We may insert duplicates here, but that's fine
479459
self.candidates.entry(src).or_default().push(dest);
480460
}

tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-abort.diff

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,23 @@
88
let _5: ();
99
let mut _6: i32;
1010
scope 1 {
11-
- debug x => _1;
12-
+ debug x => _4;
11+
debug x => _1;
1312
let _2: i32;
1413
scope 2 {
1514
- debug y => _2;
16-
+ debug y => _4;
15+
+ debug y => _1;
1716
let _3: i32;
1817
scope 3 {
1918
- debug z => _3;
20-
+ debug z => _4;
19+
+ debug z => _1;
2120
}
2221
}
2322
}
2423

2524
bb0: {
2625
- StorageLive(_1);
27-
- _1 = val() -> [return: bb1, unwind unreachable];
2826
+ nop;
29-
+ _4 = val() -> [return: bb1, unwind unreachable];
27+
_1 = val() -> [return: bb1, unwind unreachable];
3028
}
3129

3230
bb1: {
@@ -47,14 +45,17 @@
4745
+ nop;
4846
+ nop;
4947
StorageLive(_5);
50-
StorageLive(_6);
48+
- StorageLive(_6);
5149
- _6 = copy _1;
52-
+ _6 = copy _4;
53-
_5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind unreachable];
50+
- _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind unreachable];
51+
+ nop;
52+
+ nop;
53+
+ _5 = std::mem::drop::<i32>(move _1) -> [return: bb2, unwind unreachable];
5454
}
5555

5656
bb2: {
57-
StorageDead(_6);
57+
- StorageDead(_6);
58+
+ nop;
5859
StorageDead(_5);
5960
_0 = const ();
6061
- StorageDead(_3);

tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,23 @@
88
let _5: ();
99
let mut _6: i32;
1010
scope 1 {
11-
- debug x => _1;
12-
+ debug x => _4;
11+
debug x => _1;
1312
let _2: i32;
1413
scope 2 {
1514
- debug y => _2;
16-
+ debug y => _4;
15+
+ debug y => _1;
1716
let _3: i32;
1817
scope 3 {
1918
- debug z => _3;
20-
+ debug z => _4;
19+
+ debug z => _1;
2120
}
2221
}
2322
}
2423

2524
bb0: {
2625
- StorageLive(_1);
27-
- _1 = val() -> [return: bb1, unwind continue];
2826
+ nop;
29-
+ _4 = val() -> [return: bb1, unwind continue];
27+
_1 = val() -> [return: bb1, unwind continue];
3028
}
3129

3230
bb1: {
@@ -47,14 +45,17 @@
4745
+ nop;
4846
+ nop;
4947
StorageLive(_5);
50-
StorageLive(_6);
48+
- StorageLive(_6);
5149
- _6 = copy _1;
52-
+ _6 = copy _4;
53-
_5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind continue];
50+
- _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind continue];
51+
+ nop;
52+
+ nop;
53+
+ _5 = std::mem::drop::<i32>(move _1) -> [return: bb2, unwind continue];
5454
}
5555

5656
bb2: {
57-
StorageDead(_6);
57+
- StorageDead(_6);
58+
+ nop;
5859
StorageDead(_5);
5960
_0 = const ();
6061
- StorageDead(_3);

tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-abort.mir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
77
let mut _3: usize;
88
let mut _4: usize;
99
scope 1 {
10-
debug b => _3;
10+
debug b => _2;
1111
}
1212

1313
bb0: {
1414
nop;
15-
_3 = copy _1;
15+
_2 = copy _1;
1616
_1 = const 5_usize;
1717
nop;
1818
nop;
19-
_1 = move _3;
19+
_1 = move _2;
2020
nop;
2121
nop;
2222
nop;

tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
77
let mut _3: usize;
88
let mut _4: usize;
99
scope 1 {
10-
debug b => _3;
10+
debug b => _2;
1111
}
1212

1313
bb0: {
1414
nop;
15-
_3 = copy _1;
15+
_2 = copy _1;
1616
_1 = const 5_usize;
1717
nop;
1818
nop;
19-
_1 = move _3;
19+
_1 = move _2;
2020
nop;
2121
nop;
2222
nop;

tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-abort.mir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
77
let mut _3: usize;
88
let mut _4: usize;
99
scope 1 {
10-
debug b => _3;
10+
debug b => _2;
1111
}
1212

1313
bb0: {
1414
nop;
15-
_3 = copy _1;
15+
_2 = copy _1;
1616
_1 = const 5_usize;
1717
nop;
1818
nop;
19-
_1 = move _3;
19+
_1 = move _2;
2020
nop;
2121
nop;
2222
nop;

tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ fn f(_1: usize) -> usize {
77
let mut _3: usize;
88
let mut _4: usize;
99
scope 1 {
10-
debug b => _3;
10+
debug b => _2;
1111
}
1212

1313
bb0: {
1414
nop;
15-
_3 = copy _1;
15+
_2 = copy _1;
1616
_1 = const 5_usize;
1717
nop;
1818
nop;
19-
_1 = move _3;
19+
_1 = move _2;
2020
nop;
2121
nop;
2222
nop;

tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 {
66
scope 1 (inlined <Enum1 as Clone>::clone) {
77
debug self => _1;
88
let mut _2: isize;
9-
let mut _3: &AllCopy;
10-
let mut _4: &NestCopy;
9+
let _3: &AllCopy;
10+
let _4: &NestCopy;
1111
scope 2 {
1212
debug __self_0 => _3;
1313
scope 6 (inlined <AllCopy as Clone>::clone) {

0 commit comments

Comments
 (0)