GVN: Do not unify dereferences if they are references

This commit is contained in:
dianqk 2026-01-26 20:49:16 +08:00
parent bc2bf6b544
commit 9c029d2102
No known key found for this signature in database
16 changed files with 443 additions and 118 deletions

View file

@ -799,6 +799,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
{
return Some((projection_ty, value));
}
// DO NOT reason the pointer value.
// We cannot unify two pointers that dereference same local, because they may
// have different lifetimes.
// ```
// let b: &T = *a;
// ... `a` is allowed to be modified. `c` and `b` have different borrowing lifetime.
// Unifying them will extend the lifetime of `b`.
// let c: &T = *a;
// ```
if projection_ty.ty.is_ref() {
return None;
}
// An immutable borrow `_x` always points to the same value for the
// lifetime of the borrow, so we can merge all instances of `*_x`.

View file

@ -0,0 +1,37 @@
- // MIR for `dereference_reborrow` before GVN
+ // MIR for `dereference_reborrow` after GVN
fn dereference_reborrow(_1: &mut u8) -> () {
debug mut_a => _1;
let mut _0: ();
let _2: &u8;
scope 1 {
debug a => _2;
let _3: u8;
scope 2 {
debug b => _3;
let _4: u8;
scope 3 {
debug c => _4;
}
}
}
bb0: {
StorageLive(_2);
_2 = &(*_1);
- StorageLive(_3);
+ nop;
_3 = copy (*_2);
StorageLive(_4);
- _4 = copy (*_2);
+ _4 = copy _3;
_0 = const ();
StorageDead(_4);
- StorageDead(_3);
+ nop;
StorageDead(_2);
return;
}
}

View file

@ -0,0 +1,37 @@
- // MIR for `dereference_reborrow` before GVN
+ // MIR for `dereference_reborrow` after GVN
fn dereference_reborrow(_1: &mut u8) -> () {
debug mut_a => _1;
let mut _0: ();
let _2: &u8;
scope 1 {
debug a => _2;
let _3: u8;
scope 2 {
debug b => _3;
let _4: u8;
scope 3 {
debug c => _4;
}
}
}
bb0: {
StorageLive(_2);
_2 = &(*_1);
- StorageLive(_3);
+ nop;
_3 = copy (*_2);
StorageLive(_4);
- _4 = copy (*_2);
+ _4 = copy _3;
_0 = const ();
StorageDead(_4);
- StorageDead(_3);
+ nop;
StorageDead(_2);
return;
}
}

View file

@ -0,0 +1,30 @@
- // MIR for `field_borrow` before GVN
+ // MIR for `field_borrow` after GVN
fn field_borrow(_1: &FieldBorrow<'_>) -> () {
debug a => _1;
let mut _0: ();
let _2: &u8;
scope 1 {
debug b => _2;
let _3: &u8;
scope 2 {
debug c => _3;
}
}
bb0: {
- StorageLive(_2);
+ nop;
_2 = copy ((*_1).0: &u8);
StorageLive(_3);
- _3 = copy ((*_1).0: &u8);
+ _3 = copy _2;
_0 = const ();
StorageDead(_3);
- StorageDead(_2);
+ nop;
return;
}
}

View file

@ -0,0 +1,30 @@
- // MIR for `field_borrow` before GVN
+ // MIR for `field_borrow` after GVN
fn field_borrow(_1: &FieldBorrow<'_>) -> () {
debug a => _1;
let mut _0: ();
let _2: &u8;
scope 1 {
debug b => _2;
let _3: &u8;
scope 2 {
debug c => _3;
}
}
bb0: {
- StorageLive(_2);
+ nop;
_2 = copy ((*_1).0: &u8);
StorageLive(_3);
- _3 = copy ((*_1).0: &u8);
+ _3 = copy _2;
_0 = const ();
StorageDead(_3);
- StorageDead(_2);
+ nop;
return;
}
}

View file

@ -0,0 +1,51 @@
- // MIR for `field_borrow_2` before GVN
+ // MIR for `field_borrow_2` after GVN
fn field_borrow_2(_1: &&FieldBorrow<'_>) -> () {
debug a => _1;
let mut _0: ();
let _2: &FieldBorrow<'_>;
scope 1 {
debug b => _2;
let _3: &u8;
scope 2 {
debug c => _3;
let _4: &FieldBorrow<'_>;
scope 3 {
debug d => _4;
let _5: &u8;
scope 4 {
debug e => _5;
let _6: &u8;
scope 5 {
debug f => _6;
}
}
}
}
}
bb0: {
StorageLive(_2);
_2 = copy (*_1);
StorageLive(_3);
_3 = copy ((*_2).0: &u8);
StorageLive(_4);
_4 = copy (*_1);
- StorageLive(_5);
+ nop;
_5 = copy ((*_4).0: &u8);
StorageLive(_6);
- _6 = copy ((*_4).0: &u8);
+ _6 = copy _5;
_0 = const ();
StorageDead(_6);
- StorageDead(_5);
+ nop;
StorageDead(_4);
StorageDead(_3);
StorageDead(_2);
return;
}
}

View file

@ -0,0 +1,51 @@
- // MIR for `field_borrow_2` before GVN
+ // MIR for `field_borrow_2` after GVN
fn field_borrow_2(_1: &&FieldBorrow<'_>) -> () {
debug a => _1;
let mut _0: ();
let _2: &FieldBorrow<'_>;
scope 1 {
debug b => _2;
let _3: &u8;
scope 2 {
debug c => _3;
let _4: &FieldBorrow<'_>;
scope 3 {
debug d => _4;
let _5: &u8;
scope 4 {
debug e => _5;
let _6: &u8;
scope 5 {
debug f => _6;
}
}
}
}
}
bb0: {
StorageLive(_2);
_2 = copy (*_1);
StorageLive(_3);
_3 = copy ((*_2).0: &u8);
StorageLive(_4);
_4 = copy (*_1);
- StorageLive(_5);
+ nop;
_5 = copy ((*_4).0: &u8);
StorageLive(_6);
- _6 = copy ((*_4).0: &u8);
+ _6 = copy _5;
_0 = const ();
StorageDead(_6);
- StorageDead(_5);
+ nop;
StorageDead(_4);
StorageDead(_3);
StorageDead(_2);
return;
}
}

View file

@ -1100,6 +1100,53 @@ fn dereference_indexing(array: [u8; 2], index: usize) {
opaque(*a);
}
// EMIT_MIR gvn.dereference_reborrow.GVN.diff
fn dereference_reborrow(mut_a: &mut u8) {
// CHECK-LABEL: fn dereference_reborrow(
// CHECK: debug a => [[a:_.*]];
// CHECK: debug b => [[b:_.*]];
// CHECK: debug c => [[c:_.*]];
// CHECK: [[a]] = &(*_1);
// CHECK: [[b]] = copy (*[[a]]);
// CHECK: [[c]] = copy [[b]];
let a = &*mut_a;
let b = *a;
let c = *a;
}
struct FieldBorrow<'a>(&'a u8);
// EMIT_MIR gvn.field_borrow.GVN.diff
fn field_borrow(a: &FieldBorrow<'_>) {
// CHECK-LABEL: fn field_borrow(
// CHECK: debug b => [[b:_.*]];
// CHECK: debug c => [[c:_.*]];
// CHECK: [[b]] = copy ((*_1).0: &u8);
// CHECK: [[c]] = copy [[b]];
let b = a.0;
let c = a.0;
}
// EMIT_MIR gvn.field_borrow_2.GVN.diff
fn field_borrow_2(a: &&FieldBorrow<'_>) {
// CHECK-LABEL: fn field_borrow_2(
// CHECK: debug b => [[b:_.*]];
// CHECK: debug c => [[c:_.*]];
// CHECK: debug d => [[d:_.*]];
// CHECK: debug e => [[e:_.*]];
// CHECK: debug f => [[f:_.*]];
// CHECK: [[b]] = copy (*_1);
// CHECK: [[c]] = copy ((*[[b]]).0: &u8);
// CHECK: [[d]] = copy (*_1);
// CHECK: [[e]] = copy ((*[[d]]).0: &u8);
// CHECK: [[f]] = copy [[e]];
let b = *a;
let c = b.0;
let d = *a;
let e = d.0;
let f = d.0;
}
// CHECK-LABEL: fn main(
fn main() {
subexpression_elimination(2, 4, 5);
@ -1129,6 +1176,9 @@ fn main() {
meta_of_ref_to_slice(&42);
slice_from_raw_parts_as_ptr(&123, 456);
dereference_indexing([129, 14], 5);
dereference_reborrow(&mut 5);
field_borrow(&FieldBorrow(&0));
field_borrow(&&FieldBorrow(&0));
}
#[inline(never)]

View file

@ -29,17 +29,13 @@
_8 = copy (*_1);
_2 = copy ((*_8).0: i32);
- StorageLive(_3);
- _9 = copy (*_1);
- _3 = copy ((*_9).1: u64);
+ nop;
_9 = copy (*_1);
_3 = copy ((*_9).1: u64);
- StorageLive(_4);
- _10 = copy (*_1);
- _4 = copy ((*_10).2: [i8; 3]);
+ nop;
+ _9 = copy _8;
+ _3 = copy ((*_8).1: u64);
+ nop;
+ _10 = copy _8;
+ _4 = copy ((*_8).2: [i8; 3]);
_10 = copy (*_1);
_4 = copy ((*_10).2: [i8; 3]);
StorageLive(_5);
_5 = copy _2;
StorageLive(_6);

View file

@ -2,6 +2,17 @@
fn src(x: &&u8) -> bool {
// CHECK-LABEL: fn src(
// CHECK: debug y => [[Y:_.*]];
// CHECK: bb0:
// CHECK: [[BORROW_u8:_.*]] = copy (*_1);
// CHECK: [[Y]] = copy (*[[BORROW_u8]]);
// CHECK: bb1:
// BORROW_u8 outside its lifetime in bb1.
// CHECK-NOT: copy (*[[BORROW_u8]]);
// CHECK: copy (*_1);
// CHECK-NOT: _0 = const true;
// CHECK: _0 = Eq({{.*}}, {{.*}});
// CHECK-NOT: _0 = const true;
let y = **x;
unsafe { unknown() };
**x == y

View file

@ -24,14 +24,12 @@
bb1: {
StorageLive(_4);
- _7 = copy (*_1);
- _4 = copy (*_7);
+ _7 = copy _6;
+ _4 = copy _2;
_7 = copy (*_1);
_4 = copy (*_7);
StorageLive(_5);
_5 = copy _2;
- _0 = Eq(move _4, move _5);
+ _0 = const true;
+ _0 = Eq(move _4, copy _2);
StorageDead(_5);
StorageDead(_4);
- StorageDead(_2);

View file

@ -24,14 +24,12 @@
bb1: {
StorageLive(_4);
- _7 = copy (*_1);
- _4 = copy (*_7);
+ _7 = copy _6;
+ _4 = copy _2;
_7 = copy (*_1);
_4 = copy (*_7);
StorageLive(_5);
_5 = copy _2;
- _0 = Eq(move _4, move _5);
+ _0 = const true;
+ _0 = Eq(move _4, copy _2);
StorageDead(_5);
StorageDead(_4);
- StorageDead(_2);

View file

@ -6,6 +6,8 @@ fn src(_1: &&u8) -> bool {
let mut _2: &u8;
let _3: u8;
let _4: ();
let mut _5: &u8;
let mut _6: u8;
scope 1 {
debug y => _3;
}
@ -17,7 +19,11 @@ fn src(_1: &&u8) -> bool {
}
bb1: {
_0 = const true;
StorageLive(_6);
_5 = copy (*_1);
_6 = copy (*_5);
_0 = Eq(move _6, copy _3);
StorageDead(_6);
return;
}
}

View file

@ -6,6 +6,8 @@ fn src(_1: &&u8) -> bool {
let mut _2: &u8;
let _3: u8;
let _4: ();
let mut _5: &u8;
let mut _6: u8;
scope 1 {
debug y => _3;
}
@ -17,7 +19,11 @@ fn src(_1: &&u8) -> bool {
}
bb1: {
_0 = const true;
StorageLive(_6);
_5 = copy (*_1);
_6 = copy (*_5);
_0 = Eq(move _6, copy _3);
StorageDead(_6);
return;
}
}

View file

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

View file

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