Auto merge of #132527 - DianQK:gvn-stmt-iter, r=oli-obk

gvn: Invalid dereferences for all non-local mutations

Fixes #132353.

This PR removes the computation value by traversing SSA locals through `for_each_assignment_mut`.

Because the `for_each_assignment_mut` traversal skips statements which have side effects, such as dereference assignments, the computation may be unsound. Instead of `for_each_assignment_mut`, we compute values by traversing in reverse postorder.

Because we compute and use the symbolic representation of values on the fly, I invalidate all old values when encountering a dereference assignment. The current approach does not prevent the optimization of a clone to a copy.

In the future, we may add an alias model, or dominance information for dereference assignments, or SSA form to help GVN.

r? cjgillot

cc `@jieyouxu` #132356
cc `@RalfJung` #133474
This commit is contained in:
bors 2025-04-03 19:17:33 +00:00
commit 00095b3da4
43 changed files with 567 additions and 574 deletions

View file

@ -8,8 +8,9 @@
bb0: {
StorageLive(_1);
_1 = const <bool as NeedsDrop>::NEEDS;
- _1 = const <bool as NeedsDrop>::NEEDS;
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
+ _1 = const false;
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
}

View file

@ -8,8 +8,9 @@
bb0: {
StorageLive(_1);
_1 = const <bool as NeedsDrop>::NEEDS;
- _1 = const <bool as NeedsDrop>::NEEDS;
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
+ _1 = const false;
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
}

View file

@ -14,19 +14,23 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
- StorageLive(_2);
- StorageLive(_3);
+ nop;
+ nop;
_3 = const {ALLOC0: &u8};
_2 = copy (*_3);
- _2 = copy (*_3);
+ _2 = const 2_u8;
StorageLive(_4);
StorageLive(_5);
_5 = const {ALLOC0: &u8};
- _4 = copy (*_5);
+ _4 = copy (*_3);
_1 = Add(move _2, move _4);
- _1 = Add(move _2, move _4);
+ _4 = const 2_u8;
+ _1 = const 4_u8;
StorageDead(_4);
StorageDead(_2);
- StorageDead(_2);
+ nop;
StorageDead(_5);
- StorageDead(_3);
+ nop;

View file

@ -6,7 +6,6 @@ static FOO: u8 = 2;
fn main() {
// CHECK-LABEL: fn main(
// CHECK: debug x => [[x:_.*]];
// Disabled due to <https://github.com/rust-lang/rust/issues/130853>
// COM: CHECK: [[x]] = const 4_u8;
// CHECK: [[x]] = const 4_u8;
let x = FOO + FOO;
}

View file

@ -16,7 +16,8 @@
StorageLive(_2);
_4 = const main::promoted[0];
_2 = &(*_4);
_1 = copy (*_2);
- _1 = copy (*_2);
+ _1 = const 4_i32;
StorageDead(_2);
_0 = const ();
StorageDead(_1);

View file

@ -16,7 +16,8 @@
StorageLive(_2);
_4 = const main::promoted[0];
_2 = &((*_4).1: i32);
_1 = copy (*_2);
- _1 = copy (*_2);
+ _1 = const 5_i32;
StorageDead(_2);
_0 = const ();
StorageDead(_1);

View file

@ -5,7 +5,6 @@
fn main() {
// CHECK-LABEL: fn main(
// CHECK: debug a => [[a:_.*]];
// Disabled due to <https://github.com/rust-lang/rust/issues/130853>
// COM: CHECK: [[a]] = const 5_i32;
// CHECK: [[a]] = const 5_i32;
let a = *(&(4, 5).1);
}

View file

@ -40,7 +40,7 @@
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
+ _1 = const 2_u32;
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);

View file

@ -40,7 +40,7 @@
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
+ _1 = const 2_u32;
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);

View file

@ -40,7 +40,7 @@
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
+ _1 = const 2_u32;
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);

View file

@ -40,7 +40,7 @@
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
+ _1 = const 2_u32;
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);

View file

@ -8,8 +8,7 @@ fn main() {
// CHECK-LABEL: fn main(
// CHECK: debug a => [[a:_.*]];
// CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast));
// Disabled due to <https://github.com/rust-lang/rust/issues/130853>
// COM: CHECK: assert(const true,
// COM: CHECK: [[a]] = const 2_u32;
// CHECK: assert(const true,
// CHECK: [[a]] = const 2_u32;
let a = (&[1u32, 2, 3] as &[u32])[1];
}

View file

@ -10,8 +10,9 @@
StorageLive(_1);
StorageLive(_2);
- _2 = ();
- _1 = Union32 { value: move _2 };
+ _2 = const ();
_1 = Union32 { value: move _2 };
+ _1 = Union32 { value: const () };
StorageDead(_2);
_0 = move _1 as u32 (Transmute);
StorageDead(_1);

View file

@ -10,8 +10,9 @@
StorageLive(_1);
StorageLive(_2);
- _2 = ();
- _1 = Union32 { value: move _2 };
+ _2 = const ();
_1 = Union32 { value: move _2 };
+ _1 = Union32 { value: const () };
StorageDead(_2);
_0 = move _1 as u32 (Transmute);
StorageDead(_1);

View file

@ -5,11 +5,10 @@
let mut _0: ();
let _1: main::Un;
let mut _2: u32;
let mut _3: u32;
scope 1 {
debug un => _1;
scope 3 (inlined std::mem::drop::<u32>) {
debug _x => _3;
debug _x => _2;
}
}
scope 2 (inlined val) {
@ -17,13 +16,10 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_1 = Un { us: const 1_u32 };
StorageLive(_2);
_2 = copy (_1.0: u32);
StorageDead(_2);
StorageLive(_3);
_3 = copy (_1.0: u32);
StorageDead(_3);
StorageDead(_1);
return;
}

View file

@ -5,11 +5,10 @@
let mut _0: ();
let _1: main::Un;
let mut _2: u32;
let mut _3: u32;
scope 1 {
debug un => _1;
scope 3 (inlined std::mem::drop::<u32>) {
debug _x => _3;
debug _x => _2;
}
}
scope 2 (inlined val) {
@ -17,13 +16,10 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
nop;
_1 = Un { us: const 1_u32 };
StorageLive(_2);
_2 = copy (_1.0: u32);
StorageDead(_2);
StorageLive(_3);
_3 = copy (_1.0: u32);
StorageDead(_3);
StorageDead(_1);
return;
}

View file

@ -18,7 +18,8 @@
}
bb2: {
_0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind unreachable];
- _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind unreachable];
+ _0 = opaque::<T>(copy _1) -> [return: bb3, unwind unreachable];
}
bb3: {

View file

@ -18,7 +18,8 @@
}
bb2: {
_0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind continue];
- _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind continue];
+ _0 = opaque::<T>(copy _1) -> [return: bb3, unwind continue];
}
bb3: {

View file

@ -8,10 +8,10 @@
let mut _3: fn(u8) -> u8;
let _5: ();
let mut _6: fn(u8) -> u8;
let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
let _10: ();
let mut _11: fn();
let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
let _14: ();
let mut _15: fn();
scope 1 {
@ -19,7 +19,7 @@
let _4: fn(u8) -> u8;
scope 2 {
debug g => _4;
let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
scope 3 {
debug closure => _7;
let _8: fn();
@ -62,16 +62,16 @@
StorageDead(_6);
StorageDead(_5);
- StorageLive(_7);
- _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
- _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
- StorageLive(_8);
+ nop;
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ nop;
StorageLive(_9);
- _9 = copy _7;
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_9);
StorageLive(_10);
StorageLive(_11);
@ -88,8 +88,8 @@
StorageLive(_13);
- _13 = copy _7;
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);

View file

@ -8,10 +8,10 @@
let mut _3: fn(u8) -> u8;
let _5: ();
let mut _6: fn(u8) -> u8;
let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
let _10: ();
let mut _11: fn();
let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
let _14: ();
let mut _15: fn();
scope 1 {
@ -19,7 +19,7 @@
let _4: fn(u8) -> u8;
scope 2 {
debug g => _4;
let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
scope 3 {
debug closure => _7;
let _8: fn();
@ -62,16 +62,16 @@
StorageDead(_6);
StorageDead(_5);
- StorageLive(_7);
- _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
- _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
- StorageLive(_8);
+ nop;
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ nop;
StorageLive(_9);
- _9 = copy _7;
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_9);
StorageLive(_10);
StorageLive(_11);
@ -88,8 +88,8 @@
StorageLive(_13);
- _13 = copy _7;
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);

View file

@ -100,17 +100,18 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
opaque((x * y) - y);
// We cannot substitute through an immutable reference.
// (Disabled due to <https://github.com/rust-lang/rust/issues/130853>)
// CHECK: [[ref:_.*]] = &_3;
// CHECK: [[deref:_.*]] = copy (*[[ref]]);
// COM: CHECK: [[addref:_.*]] = Add(copy [[deref]], copy _1);
// COM: CHECK: opaque::<u64>(copy [[addref]])
// COM: CHECK: opaque::<u64>(copy [[addref]])
// CHECK: [[addref:_.*]] = Add(move [[deref]], copy _1);
// CHECK: opaque::<u64>(move [[addref]])
// CHECK: [[deref2:_.*]] = copy (*[[ref]]);
// CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1);
// CHECK: opaque::<u64>(move [[addref2]])
let a = &z;
opaque(*a + x);
opaque(*a + x);
// And certainly not through a mutable reference or a pointer.
// But not through a mutable reference or a pointer.
// CHECK: [[mut:_.*]] = &mut _3;
// CHECK: [[addmut:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addmut]])
@ -142,9 +143,11 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
// Important: `e` is not `a`!
// CHECK: [[ref2:_.*]] = &_3;
// CHECK: [[deref2:_.*]] = copy (*[[ref2]]);
// COM: CHECK: [[addref2:_.*]] = Add(copy [[deref2]], copy _1);
// COM: CHECK: opaque::<u64>(copy [[addref2]])
// COM: CHECK: opaque::<u64>(copy [[addref2]])
// CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1);
// CHECK: opaque::<u64>(move [[addref2]])
// CHECK: [[deref3:_.*]] = copy (*[[ref2]]);
// CHECK: [[addref3:_.*]] = Add(move [[deref3]], copy _1);
// CHECK: opaque::<u64>(move [[addref3]])
let e = &z;
opaque(*e + x);
opaque(*e + x);
@ -499,8 +502,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
// Do not reuse dereferences of `&Freeze`.
// CHECK: [[ref:_.*]] = &(*_1);
// CHECK: [[st7:_.*]] = copy (*[[ref]]);
// COM: CHECK: opaque::<u32>(copy [[st7]])
// COM: CHECK: opaque::<u32>(copy [[st7]])
// CHECK: opaque::<u32>(move [[st7]])
// CHECK: [[st8:_.*]] = copy (*[[ref]]);
// CHECK: opaque::<u32>(move [[st8]])
let z = &*t;
opaque(*z);
opaque(*z);
@ -519,8 +523,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
// `*s` is not Copy, but `(*s).0` is, but we still cannot reuse.
// CHECK: [[st10:_.*]] = copy ((*_3).0: u32);
// COM: CHECK: opaque::<u32>(copy [[st10]])
// COM: CHECK: opaque::<u32>(copy [[st10]])
// CHECK: opaque::<u32>(move [[st10]])
// CHECK: [[st11:_.*]] = copy ((*_3).0: u32);
// CHECK: opaque::<u32>(move [[st11]])
opaque(s.0);
opaque(s.0);
}
@ -737,7 +742,7 @@ fn borrowed<T: Copy + Freeze>(x: T) {
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
// CHECK: bb2: {
// COM: CHECK-NEXT: _0 = opaque::<T>(copy _1)
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
mir! {
{
let a = x;

View file

@ -111,8 +111,9 @@
StorageLive(_7);
StorageLive(_8);
- StorageLive(_9);
- StorageLive(_10);
+ nop;
+ nop;
StorageLive(_10);
StorageLive(_11);
_11 = &(*_1);
_10 = core::str::<impl str>::as_ptr(move _11) -> [return: bb3, unwind unreachable];
@ -122,8 +123,9 @@
StorageDead(_11);
_9 = &_10;
- StorageLive(_12);
- StorageLive(_13);
+ nop;
+ nop;
StorageLive(_13);
StorageLive(_14);
- _14 = &(*_4);
+ _14 = &(*_1);
@ -148,11 +150,12 @@
StorageLive(_17);
StorageLive(_18);
- _18 = copy (*_15);
+ _18 = copy (*_9);
+ _18 = copy _10;
StorageLive(_19);
- _19 = copy (*_16);
+ _19 = copy (*_12);
_17 = Eq(move _18, move _19);
- _17 = Eq(move _18, move _19);
+ _19 = copy _13;
+ _17 = Eq(copy _10, copy _13);
switchInt(move _17) -> [0: bb6, otherwise: bb5];
}
@ -163,8 +166,10 @@
StorageDead(_17);
StorageDead(_16);
StorageDead(_15);
StorageDead(_13);
StorageDead(_10);
- StorageDead(_13);
- StorageDead(_10);
+ nop;
+ nop;
StorageDead(_8);
StorageDead(_7);
- StorageLive(_29);
@ -213,8 +218,9 @@
StorageLive(_33);
StorageLive(_34);
- StorageLive(_35);
- StorageLive(_36);
+ nop;
+ nop;
StorageLive(_36);
StorageLive(_37);
_37 = &(*_1);
_36 = core::str::<impl str>::as_ptr(move _37) -> [return: bb8, unwind unreachable];
@ -224,8 +230,9 @@
StorageDead(_37);
_35 = &_36;
- StorageLive(_38);
- StorageLive(_39);
+ nop;
+ nop;
StorageLive(_39);
StorageLive(_40);
_40 = &(*_29);
_39 = core::slice::<impl [u8]>::as_ptr(move _40) -> [return: bb9, unwind unreachable];
@ -249,11 +256,12 @@
StorageLive(_43);
StorageLive(_44);
- _44 = copy (*_41);
+ _44 = copy (*_35);
+ _44 = copy _36;
StorageLive(_45);
- _45 = copy (*_42);
+ _45 = copy (*_38);
_43 = Eq(move _44, move _45);
- _43 = Eq(move _44, move _45);
+ _45 = copy _39;
+ _43 = Eq(copy _36, copy _39);
switchInt(move _43) -> [0: bb11, otherwise: bb10];
}
@ -264,8 +272,10 @@
StorageDead(_43);
StorageDead(_42);
StorageDead(_41);
StorageDead(_39);
StorageDead(_36);
- StorageDead(_39);
- StorageDead(_36);
+ nop;
+ nop;
StorageDead(_34);
StorageDead(_33);
_0 = const ();

View file

@ -111,8 +111,9 @@
StorageLive(_7);
StorageLive(_8);
- StorageLive(_9);
- StorageLive(_10);
+ nop;
+ nop;
StorageLive(_10);
StorageLive(_11);
_11 = &(*_1);
_10 = core::str::<impl str>::as_ptr(move _11) -> [return: bb3, unwind continue];
@ -122,8 +123,9 @@
StorageDead(_11);
_9 = &_10;
- StorageLive(_12);
- StorageLive(_13);
+ nop;
+ nop;
StorageLive(_13);
StorageLive(_14);
- _14 = &(*_4);
+ _14 = &(*_1);
@ -148,11 +150,12 @@
StorageLive(_17);
StorageLive(_18);
- _18 = copy (*_15);
+ _18 = copy (*_9);
+ _18 = copy _10;
StorageLive(_19);
- _19 = copy (*_16);
+ _19 = copy (*_12);
_17 = Eq(move _18, move _19);
- _17 = Eq(move _18, move _19);
+ _19 = copy _13;
+ _17 = Eq(copy _10, copy _13);
switchInt(move _17) -> [0: bb6, otherwise: bb5];
}
@ -163,8 +166,10 @@
StorageDead(_17);
StorageDead(_16);
StorageDead(_15);
StorageDead(_13);
StorageDead(_10);
- StorageDead(_13);
- StorageDead(_10);
+ nop;
+ nop;
StorageDead(_8);
StorageDead(_7);
- StorageLive(_29);
@ -213,8 +218,9 @@
StorageLive(_33);
StorageLive(_34);
- StorageLive(_35);
- StorageLive(_36);
+ nop;
+ nop;
StorageLive(_36);
StorageLive(_37);
_37 = &(*_1);
_36 = core::str::<impl str>::as_ptr(move _37) -> [return: bb8, unwind continue];
@ -224,8 +230,9 @@
StorageDead(_37);
_35 = &_36;
- StorageLive(_38);
- StorageLive(_39);
+ nop;
+ nop;
StorageLive(_39);
StorageLive(_40);
_40 = &(*_29);
_39 = core::slice::<impl [u8]>::as_ptr(move _40) -> [return: bb9, unwind continue];
@ -249,11 +256,12 @@
StorageLive(_43);
StorageLive(_44);
- _44 = copy (*_41);
+ _44 = copy (*_35);
+ _44 = copy _36;
StorageLive(_45);
- _45 = copy (*_42);
+ _45 = copy (*_38);
_43 = Eq(move _44, move _45);
- _43 = Eq(move _44, move _45);
+ _45 = copy _39;
+ _43 = Eq(copy _36, copy _39);
switchInt(move _43) -> [0: bb11, otherwise: bb10];
}
@ -264,8 +272,10 @@
StorageDead(_43);
StorageDead(_42);
StorageDead(_41);
StorageDead(_39);
StorageDead(_36);
- StorageDead(_39);
- StorageDead(_36);
+ nop;
+ nop;
StorageDead(_34);
StorageDead(_33);
_0 = const ();

View file

@ -1,5 +1,3 @@
//@ compile-flags: -Zunsound-mir-opts
// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
//@ test-mir-pass: GVN
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-before-inline

View file

@ -1,7 +1,7 @@
- // MIR for `<impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone` before GVN
+ // MIR for `<impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone` after GVN
- // MIR for `<impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone` before GVN
+ // MIR for `<impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone` after GVN
fn <impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone(_1: &AllCopy) -> AllCopy {
fn <impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone(_1: &AllCopy) -> AllCopy {
debug self => _1;
let mut _0: AllCopy;
let mut _2: i32;

View file

@ -1,5 +1,3 @@
//@ compile-flags: -Zunsound-mir-opts
// FIXME: see <https://github.com/rust-lang/rust/issues/132353.
//@ test-mir-pass: GVN
//@ compile-flags: -Cpanic=abort

View file

@ -17,15 +17,16 @@
StorageLive(_3);
_5 = const f::promoted[0];
_3 = &(*_5);
_2 = copy ((*_3).1: E);
- StorageLive(_1);
+ nop;
_1 = copy ((_2 as A).1: u32);
- _2 = copy ((*_3).1: E);
+ _2 = const Scalar(0x00000000): E;
StorageLive(_1);
- _1 = copy ((_2 as A).1: u32);
+ _1 = const 0_u32;
StorageDead(_3);
StorageDead(_2);
_0 = copy _1;
- StorageDead(_1);
+ nop;
- _0 = copy _1;
+ _0 = const 0_u32;
StorageDead(_1);
return;
}
}

View file

@ -17,15 +17,16 @@
StorageLive(_3);
_5 = const f::promoted[0];
_3 = &(*_5);
_2 = copy ((*_3).1: E);
- StorageLive(_1);
+ nop;
_1 = copy ((_2 as A).1: u32);
- _2 = copy ((*_3).1: E);
+ _2 = const Scalar(0x00000000): E;
StorageLive(_1);
- _1 = copy ((_2 as A).1: u32);
+ _1 = const 0_u32;
StorageDead(_3);
StorageDead(_2);
_0 = copy _1;
- StorageDead(_1);
+ nop;
- _0 = copy _1;
+ _0 = const 0_u32;
StorageDead(_1);
return;
}
}

View file

@ -1,5 +1,3 @@
//@ compile-flags: -Zunsound-mir-opts
// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
//@ compile-flags: -Cdebuginfo=full
// Check if we have transformed the nested clone to the copy in the complete pipeline.

View file

@ -1,4 +1,3 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/130853>
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
fn src(x: &&u8) -> bool {

View file

@ -3,13 +3,9 @@
fn <impl at $DIR/no_inlined_clone.rs:9:10: 9:15>::clone(_1: &Foo) -> Foo {
debug self => _1;
let mut _0: Foo;
let mut _2: i32;
bb0: {
StorageLive(_2);
_2 = copy ((*_1).0: i32);
_0 = Foo { a: move _2 };
StorageDead(_2);
_0 = copy (*_1);
return;
}
}

View file

@ -4,70 +4,65 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
let mut _0: bool;
let mut _3: &(usize, usize, usize, usize);
let _4: &usize;
let mut _5: &(usize, usize, usize, usize);
let _5: &usize;
let _6: &usize;
let mut _7: &(usize, usize, usize, usize);
let _8: &usize;
let mut _9: &(usize, usize, usize, usize);
let _10: &usize;
let mut _11: &&usize;
let _12: &usize;
let mut _13: &&usize;
let mut _16: bool;
let mut _17: &&usize;
let _18: &usize;
let mut _19: &&usize;
let mut _22: bool;
let mut _23: &&usize;
let _24: &usize;
let mut _25: &&usize;
let mut _28: bool;
let mut _29: &&usize;
let _30: &usize;
let mut _31: &&usize;
let _7: &usize;
let mut _8: &&usize;
let _9: &usize;
let mut _10: &&usize;
let mut _13: bool;
let mut _14: &&usize;
let _15: &usize;
let mut _16: &&usize;
let mut _19: bool;
let mut _20: &&usize;
let _21: &usize;
let mut _22: &&usize;
let mut _23: bool;
let mut _24: &&usize;
let _25: &usize;
let mut _26: &&usize;
scope 1 {
debug a => _4;
debug b => _6;
debug c => _8;
debug d => _10;
debug b => _5;
debug c => _6;
debug d => _7;
scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _11;
debug other => _13;
debug self => _8;
debug other => _10;
scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _4;
debug other => _8;
let mut _14: usize;
let mut _15: usize;
debug other => _6;
let mut _11: usize;
let mut _12: usize;
}
}
scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _17;
debug other => _19;
debug self => _14;
debug other => _16;
scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _10;
debug other => _6;
let mut _20: usize;
let mut _21: usize;
debug self => _7;
debug other => _5;
let mut _17: usize;
let mut _18: usize;
}
}
scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _23;
debug other => _25;
debug self => _20;
debug other => _22;
scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _8;
debug self => _6;
debug other => _4;
let mut _26: usize;
let mut _27: usize;
}
}
scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _29;
debug other => _31;
debug self => _24;
debug other => _26;
scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _6;
debug other => _10;
let mut _32: usize;
let mut _33: usize;
debug self => _5;
debug other => _7;
let mut _27: usize;
let mut _28: usize;
}
}
}
@ -75,129 +70,116 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
bb0: {
_3 = copy (*_2);
_4 = &((*_3).0: usize);
_5 = copy (*_2);
_6 = &((*_5).1: usize);
_7 = copy (*_2);
_8 = &((*_7).2: usize);
_9 = copy (*_2);
_10 = &((*_9).3: usize);
StorageLive(_16);
StorageLive(_11);
_11 = &_4;
_5 = &((*_3).1: usize);
_6 = &((*_3).2: usize);
_7 = &((*_3).3: usize);
StorageLive(_13);
StorageLive(_12);
_12 = copy _8;
_13 = &_12;
StorageLive(_14);
_14 = copy ((*_3).0: usize);
StorageLive(_15);
_15 = copy ((*_7).2: usize);
_16 = Le(move _14, move _15);
StorageDead(_15);
StorageDead(_14);
switchInt(move _16) -> [0: bb1, otherwise: bb2];
StorageLive(_8);
_8 = &_4;
StorageLive(_10);
StorageLive(_9);
_9 = copy _6;
_10 = &_9;
_11 = copy ((*_3).0: usize);
_12 = copy ((*_3).2: usize);
_13 = Le(copy _11, copy _12);
switchInt(move _13) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageDead(_12);
StorageDead(_13);
StorageDead(_11);
StorageDead(_9);
StorageDead(_10);
StorageDead(_8);
goto -> bb4;
}
bb2: {
StorageDead(_12);
StorageDead(_13);
StorageDead(_11);
StorageLive(_22);
StorageLive(_17);
_17 = &_10;
StorageDead(_9);
StorageDead(_10);
StorageDead(_8);
StorageLive(_19);
StorageLive(_14);
_14 = &_7;
StorageLive(_16);
StorageLive(_15);
_15 = copy _5;
_16 = &_15;
StorageLive(_17);
_17 = copy ((*_3).3: usize);
StorageLive(_18);
_18 = copy _6;
_19 = &_18;
StorageLive(_20);
_20 = copy ((*_9).3: usize);
StorageLive(_21);
_21 = copy ((*_5).1: usize);
_22 = Le(move _20, move _21);
StorageDead(_21);
StorageDead(_20);
switchInt(move _22) -> [0: bb3, otherwise: bb8];
_18 = copy ((*_3).1: usize);
_19 = Le(move _17, move _18);
StorageDead(_18);
StorageDead(_17);
switchInt(move _19) -> [0: bb3, otherwise: bb8];
}
bb3: {
StorageDead(_18);
StorageDead(_19);
StorageDead(_17);
StorageDead(_15);
StorageDead(_16);
StorageDead(_14);
goto -> bb4;
}
bb4: {
StorageLive(_28);
StorageLive(_23);
_23 = &_8;
StorageLive(_25);
StorageLive(_24);
_24 = copy _4;
_25 = &_24;
StorageLive(_26);
_26 = copy ((*_7).2: usize);
StorageLive(_27);
_27 = copy ((*_3).0: usize);
_28 = Le(move _26, move _27);
StorageDead(_27);
StorageDead(_26);
switchInt(move _28) -> [0: bb5, otherwise: bb6];
StorageLive(_20);
_20 = &_6;
StorageLive(_22);
StorageLive(_21);
_21 = copy _4;
_22 = &_21;
_23 = Le(copy _12, copy _11);
switchInt(move _23) -> [0: bb5, otherwise: bb6];
}
bb5: {
StorageDead(_24);
StorageDead(_25);
StorageDead(_23);
StorageDead(_21);
StorageDead(_22);
StorageDead(_20);
_0 = const false;
goto -> bb7;
}
bb6: {
StorageDead(_24);
StorageDead(_21);
StorageDead(_22);
StorageDead(_20);
StorageLive(_24);
_24 = &_5;
StorageLive(_26);
StorageLive(_25);
_25 = copy _7;
_26 = &_25;
StorageLive(_27);
_27 = copy ((*_3).1: usize);
StorageLive(_28);
_28 = copy ((*_3).3: usize);
_0 = Le(move _27, move _28);
StorageDead(_28);
StorageDead(_27);
StorageDead(_25);
StorageDead(_23);
StorageLive(_29);
_29 = &_6;
StorageLive(_31);
StorageLive(_30);
_30 = copy _10;
_31 = &_30;
StorageLive(_32);
_32 = copy ((*_5).1: usize);
StorageLive(_33);
_33 = copy ((*_9).3: usize);
_0 = Le(move _32, move _33);
StorageDead(_33);
StorageDead(_32);
StorageDead(_30);
StorageDead(_31);
StorageDead(_29);
StorageDead(_26);
StorageDead(_24);
goto -> bb7;
}
bb7: {
StorageDead(_28);
StorageDead(_23);
goto -> bb9;
}
bb8: {
StorageDead(_18);
StorageDead(_19);
StorageDead(_17);
StorageDead(_15);
StorageDead(_16);
StorageDead(_14);
_0 = const true;
goto -> bb9;
}
bb9: {
StorageDead(_22);
StorageDead(_16);
StorageDead(_19);
StorageDead(_13);
return;
}
}

View file

@ -4,46 +4,40 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
let mut _0: bool;
let mut _3: &(usize, usize, usize, usize);
let _4: usize;
let mut _5: &(usize, usize, usize, usize);
let _5: usize;
let _6: usize;
let mut _7: &(usize, usize, usize, usize);
let _8: usize;
let mut _9: &(usize, usize, usize, usize);
let _10: usize;
let mut _11: bool;
let mut _12: bool;
let mut _13: bool;
let _7: usize;
let mut _8: bool;
let mut _9: bool;
let mut _10: bool;
scope 1 {
debug a => _4;
debug b => _6;
debug c => _8;
debug d => _10;
debug b => _5;
debug c => _6;
debug d => _7;
}
bb0: {
_3 = copy (*_2);
_4 = copy ((*_3).0: usize);
_5 = copy (*_2);
_6 = copy ((*_5).1: usize);
_7 = copy (*_2);
_8 = copy ((*_7).2: usize);
_9 = copy (*_2);
_10 = copy ((*_9).3: usize);
StorageLive(_11);
_11 = Le(copy _4, copy _8);
switchInt(move _11) -> [0: bb2, otherwise: bb1];
_5 = copy ((*_3).1: usize);
_6 = copy ((*_3).2: usize);
_7 = copy ((*_3).3: usize);
StorageLive(_8);
_8 = Le(copy _4, copy _6);
switchInt(move _8) -> [0: bb2, otherwise: bb1];
}
bb1: {
StorageLive(_12);
_12 = Le(copy _10, copy _6);
switchInt(move _12) -> [0: bb2, otherwise: bb6];
StorageLive(_9);
_9 = Le(copy _7, copy _5);
switchInt(move _9) -> [0: bb2, otherwise: bb6];
}
bb2: {
StorageLive(_13);
_13 = Le(copy _8, copy _4);
switchInt(move _13) -> [0: bb3, otherwise: bb4];
StorageLive(_10);
_10 = Le(copy _6, copy _4);
switchInt(move _10) -> [0: bb3, otherwise: bb4];
}
bb3: {
@ -52,12 +46,12 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
}
bb4: {
_0 = Le(copy _6, copy _10);
_0 = Le(copy _5, copy _7);
goto -> bb5;
}
bb5: {
StorageDead(_13);
StorageDead(_10);
goto -> bb7;
}
@ -67,8 +61,8 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
}
bb7: {
StorageDead(_12);
StorageDead(_11);
StorageDead(_9);
StorageDead(_8);
return;
}
}

View file

@ -19,14 +19,14 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
}
bb1: {
_3 = move ((_1 as Ok).0: T);
_0 = Result::<T, E>::Ok(copy _3);
_3 = copy ((_1 as Ok).0: T);
_0 = copy _1;
goto -> bb3;
}
bb2: {
_4 = move ((_1 as Err).0: E);
_0 = Result::<T, E>::Err(copy _4);
_4 = copy ((_1 as Err).0: E);
_0 = copy _1;
goto -> bb3;
}

View file

@ -6,62 +6,52 @@
let mut _0: std::option::Option<i32>;
let mut _2: &std::option::Option<i32>;
let mut _3: &std::option::Option<i32>;
let _4: &&mut std::option::Option<i32>;
let mut _5: isize;
let mut _7: !;
let mut _8: std::option::Option<i32>;
let mut _9: i32;
let mut _10: !;
let mut _11: &mut std::option::Option<i32>;
let mut _4: isize;
let mut _6: !;
let mut _7: std::option::Option<i32>;
let mut _8: i32;
let mut _9: !;
scope 1 {
debug col => _6;
let _6: i32;
debug col => _5;
let _5: i32;
}
bb0: {
- StorageLive(_2);
+ nop;
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
_4 = &_1;
- _11 = deref_copy (*_4);
- _3 = &(*_11);
+ _11 = copy _1;
+ _3 = &(*_1);
_2 = get(move _3) -> [return: bb1, unwind unreachable];
_3 = &(*_1);
_2 = get::<Option<i32>>(move _3) -> [return: bb1, unwind unreachable];
}
bb1: {
StorageDead(_3);
_5 = discriminant((*_2));
switchInt(move _5) -> [1: bb2, otherwise: bb3];
_4 = discriminant((*_2));
switchInt(move _4) -> [1: bb2, otherwise: bb3];
}
bb2: {
- StorageLive(_6);
- StorageLive(_5);
+ nop;
_6 = copy (((*_2) as Some).0: i32);
StorageLive(_8);
- _8 = Option::<i32>::None;
- (*_1) = move _8;
+ _8 = const Option::<i32>::None;
_5 = copy (((*_2) as Some).0: i32);
StorageLive(_7);
- _7 = Option::<i32>::None;
- (*_1) = move _7;
+ _7 = const Option::<i32>::None;
+ (*_1) = const Option::<i32>::None;
StorageDead(_7);
StorageLive(_8);
_8 = copy _5;
- _0 = Option::<i32>::Some(move _8);
+ _0 = Option::<i32>::Some(copy _5);
StorageDead(_8);
StorageLive(_9);
_9 = copy _6;
- _0 = Option::<i32>::Some(move _9);
+ _0 = copy (*_2);
StorageDead(_9);
- StorageDead(_6);
+ nop;
StorageDead(_4);
- StorageDead(_2);
- StorageDead(_5);
+ nop;
StorageDead(_2);
return;
}
bb3: {
StorageLive(_10);
StorageLive(_9);
unreachable;
}
+ }

View file

@ -7,16 +7,23 @@
//! This test demonstrates the behavior, and should be adjusted or removed when fixing and relanding
//! the mir-opt.
#![crate_type = "lib"]
// skip-filecheck
//@ compile-flags: -O -Zunsound-mir-opts
//@ test-mir-pass: GVN
#![allow(internal_features)]
#![feature(rustc_attrs, core_intrinsics)]
#![feature(core_intrinsics, custom_mir, rustc_attrs)]
use std::intrinsics::mir::*;
// EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff
#[no_mangle]
fn foo(v: &mut Option<i32>) -> Option<i32> {
if let &Some(col) = get(&v) {
// CHECK-LABEL: fn foo(
// CHECK-SAME: [[v:_.*]]: &mut Option<i32>
// CHECK: [[v_alias_1:_.*]] = &(*_1)
// CHECK-NEXT: [[v_alias_2:_.*]] = get::<Option<i32>>(move [[v_alias_1]])
// CHECK: (*[[v]]) = const Option::<i32>::None;
// CHECK-NOT: _0 = copy (*[[v_alias_2]])
// CHECK: _0 = Option::<i32>::Some
// CHECK-NOT: _0 = copy (*[[v_alias_2]])
if let &Some(col) = get(v) {
*v = None;
return Some(col);
} else {
@ -24,9 +31,31 @@ fn foo(v: &mut Option<i32>) -> Option<i32> {
}
}
#[no_mangle]
pub enum Value {
V0(i32),
V1(i32),
}
// EMIT_MIR simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
#[custom_mir(dialect = "runtime", phase = "initial")]
fn set_discriminant(v: &mut Value) -> Value {
// CHECK-LABEL: fn set_discriminant(
mir! {
let v_: &Value;
{
Call(v_ = get(v), ReturnTo(ret), UnwindUnreachable())
}
ret = {
let col: i32 = Field(Variant(*v_, 0), 0);
SetDiscriminant(*v, 1);
RET = Value::V0(col);
Return()
}
}
}
#[inline(never)]
#[rustc_nounwind]
fn get(v: &Option<i32>) -> &Option<i32> {
fn get<T>(v: &T) -> &T {
v
}

View file

@ -0,0 +1,20 @@
- // MIR for `set_discriminant` before GVN
+ // MIR for `set_discriminant` after GVN
fn set_discriminant(_1: &mut Value) -> Value {
let mut _0: Value;
let mut _2: &Value;
let mut _3: i32;
bb0: {
_2 = get::<Value>(copy _1) -> [return: bb1, unwind unreachable];
}
bb1: {
_3 = copy (((*_2) as variant#0).0: i32);
discriminant((*_1)) = 1;
_0 = Value::V0(copy _3);
return;
}
}