Skip to content

Commit 853ac8f

Browse files
committed
Check dominance for the full edge.
1 parent 6fe5e1f commit 853ac8f

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

compiler/rustc_mir_transform/src/ssa.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,16 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> {
246246
Some(LocationExtended::Assign(loc))
247247
}
248248
PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {
249-
let target = self.body.basic_blocks[loc.block].terminator().successors().next();
250-
target.map(|target| LocationExtended::Terminator(loc.block, target))
249+
// The assignment happens on the `loc -> target` edge. We need to ensure that
250+
// this *edge* dominates all uses of the local. This is true if
251+
// `loc` dominates `target` *and* `target` dominates all uses.
252+
if let Some(target) = self.body.basic_blocks[loc.block].terminator().successors().next()
253+
&& self.dominators.dominates(loc, Location { block: target, statement_index: 0 })
254+
{
255+
Some(LocationExtended::Terminator(loc.block, target))
256+
} else {
257+
None
258+
}
251259
}
252260
_ => None,
253261
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `multiple_edges` before CopyProp
2+
+ // MIR for `multiple_edges` after CopyProp
3+
4+
fn multiple_edges(_1: bool) -> u8 {
5+
let mut _0: u8;
6+
let mut _2: u8;
7+
8+
bb0: {
9+
switchInt(_1) -> [1: bb1, otherwise: bb2];
10+
}
11+
12+
bb1: {
13+
_2 = dummy(const 13_u8) -> [return: bb2, unwind continue];
14+
}
15+
16+
bb2: {
17+
_0 = _2;
18+
return;
19+
}
20+
}
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
- // MIR for `nrvo` before CopyProp
2+
+ // MIR for `nrvo` after CopyProp
3+
4+
fn nrvo() -> u8 {
5+
let mut _0: u8;
6+
let _1: u8;
7+
scope 1 {
8+
- debug y => _1;
9+
+ debug y => _0;
10+
}
11+
12+
bb0: {
13+
- StorageLive(_1);
14+
- _1 = dummy(const 5_u8) -> [return: bb1, unwind continue];
15+
+ _0 = dummy(const 5_u8) -> [return: bb1, unwind continue];
16+
}
17+
18+
bb1: {
19+
- _0 = _1;
20+
- StorageDead(_1);
21+
return;
22+
}
23+
}
24+

tests/mir-opt/copy-prop/calls.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Check that CopyProp does propagate return values of call terminators.
2+
// unit-test: CopyProp
3+
// needs-unwind
4+
5+
#![feature(custom_mir, core_intrinsics)]
6+
use std::intrinsics::mir::*;
7+
8+
#[inline(never)]
9+
fn dummy(x: u8) -> u8 {
10+
x
11+
}
12+
13+
// EMIT_MIR calls.nrvo.CopyProp.diff
14+
fn nrvo() -> u8 {
15+
let y = dummy(5); // this should get NRVO
16+
y
17+
}
18+
19+
// EMIT_MIR calls.multiple_edges.CopyProp.diff
20+
#[custom_mir(dialect = "runtime", phase = "initial")]
21+
fn multiple_edges(t: bool) -> u8 {
22+
mir! {
23+
let x: u8;
24+
{
25+
match t { true => bbt, _ => ret }
26+
}
27+
bbt = {
28+
Call(x = dummy(13), ret)
29+
}
30+
ret = {
31+
// `x` is not assigned on the `bb0 -> ret` edge,
32+
// so should not be marked as SSA for merging with `_0`.
33+
RET = x;
34+
Return()
35+
}
36+
}
37+
}
38+
39+
fn main() {
40+
// Make sure the function actually gets instantiated.
41+
nrvo();
42+
multiple_edges(false);
43+
}

0 commit comments

Comments
 (0)