Skip to content

Commit 9c029d2

Browse files
committed
GVN: Do not unify dereferences if they are references
1 parent bc2bf6b commit 9c029d2

16 files changed

Lines changed: 442 additions & 117 deletions

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,18 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
799799
{
800800
return Some((projection_ty, value));
801801
}
802+
// DO NOT reason the pointer value.
803+
// We cannot unify two pointers that dereference same local, because they may
804+
// have different lifetimes.
805+
// ```
806+
// let b: &T = *a;
807+
// ... `a` is allowed to be modified. `c` and `b` have different borrowing lifetime.
808+
// Unifying them will extend the lifetime of `b`.
809+
// let c: &T = *a;
810+
// ```
811+
if projection_ty.ty.is_ref() {
812+
return None;
813+
}
802814

803815
// An immutable borrow `_x` always points to the same value for the
804816
// lifetime of the borrow, so we can merge all instances of `*_x`.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
- // MIR for `dereference_reborrow` before GVN
2+
+ // MIR for `dereference_reborrow` after GVN
3+
4+
fn dereference_reborrow(_1: &mut u8) -> () {
5+
debug mut_a => _1;
6+
let mut _0: ();
7+
let _2: &u8;
8+
scope 1 {
9+
debug a => _2;
10+
let _3: u8;
11+
scope 2 {
12+
debug b => _3;
13+
let _4: u8;
14+
scope 3 {
15+
debug c => _4;
16+
}
17+
}
18+
}
19+
20+
bb0: {
21+
StorageLive(_2);
22+
_2 = &(*_1);
23+
- StorageLive(_3);
24+
+ nop;
25+
_3 = copy (*_2);
26+
StorageLive(_4);
27+
- _4 = copy (*_2);
28+
+ _4 = copy _3;
29+
_0 = const ();
30+
StorageDead(_4);
31+
- StorageDead(_3);
32+
+ nop;
33+
StorageDead(_2);
34+
return;
35+
}
36+
}
37+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
- // MIR for `dereference_reborrow` before GVN
2+
+ // MIR for `dereference_reborrow` after GVN
3+
4+
fn dereference_reborrow(_1: &mut u8) -> () {
5+
debug mut_a => _1;
6+
let mut _0: ();
7+
let _2: &u8;
8+
scope 1 {
9+
debug a => _2;
10+
let _3: u8;
11+
scope 2 {
12+
debug b => _3;
13+
let _4: u8;
14+
scope 3 {
15+
debug c => _4;
16+
}
17+
}
18+
}
19+
20+
bb0: {
21+
StorageLive(_2);
22+
_2 = &(*_1);
23+
- StorageLive(_3);
24+
+ nop;
25+
_3 = copy (*_2);
26+
StorageLive(_4);
27+
- _4 = copy (*_2);
28+
+ _4 = copy _3;
29+
_0 = const ();
30+
StorageDead(_4);
31+
- StorageDead(_3);
32+
+ nop;
33+
StorageDead(_2);
34+
return;
35+
}
36+
}
37+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
- // MIR for `field_borrow` before GVN
2+
+ // MIR for `field_borrow` after GVN
3+
4+
fn field_borrow(_1: &FieldBorrow<'_>) -> () {
5+
debug a => _1;
6+
let mut _0: ();
7+
let _2: &u8;
8+
scope 1 {
9+
debug b => _2;
10+
let _3: &u8;
11+
scope 2 {
12+
debug c => _3;
13+
}
14+
}
15+
16+
bb0: {
17+
- StorageLive(_2);
18+
+ nop;
19+
_2 = copy ((*_1).0: &u8);
20+
StorageLive(_3);
21+
- _3 = copy ((*_1).0: &u8);
22+
+ _3 = copy _2;
23+
_0 = const ();
24+
StorageDead(_3);
25+
- StorageDead(_2);
26+
+ nop;
27+
return;
28+
}
29+
}
30+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
- // MIR for `field_borrow` before GVN
2+
+ // MIR for `field_borrow` after GVN
3+
4+
fn field_borrow(_1: &FieldBorrow<'_>) -> () {
5+
debug a => _1;
6+
let mut _0: ();
7+
let _2: &u8;
8+
scope 1 {
9+
debug b => _2;
10+
let _3: &u8;
11+
scope 2 {
12+
debug c => _3;
13+
}
14+
}
15+
16+
bb0: {
17+
- StorageLive(_2);
18+
+ nop;
19+
_2 = copy ((*_1).0: &u8);
20+
StorageLive(_3);
21+
- _3 = copy ((*_1).0: &u8);
22+
+ _3 = copy _2;
23+
_0 = const ();
24+
StorageDead(_3);
25+
- StorageDead(_2);
26+
+ nop;
27+
return;
28+
}
29+
}
30+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
- // MIR for `field_borrow_2` before GVN
2+
+ // MIR for `field_borrow_2` after GVN
3+
4+
fn field_borrow_2(_1: &&FieldBorrow<'_>) -> () {
5+
debug a => _1;
6+
let mut _0: ();
7+
let _2: &FieldBorrow<'_>;
8+
scope 1 {
9+
debug b => _2;
10+
let _3: &u8;
11+
scope 2 {
12+
debug c => _3;
13+
let _4: &FieldBorrow<'_>;
14+
scope 3 {
15+
debug d => _4;
16+
let _5: &u8;
17+
scope 4 {
18+
debug e => _5;
19+
let _6: &u8;
20+
scope 5 {
21+
debug f => _6;
22+
}
23+
}
24+
}
25+
}
26+
}
27+
28+
bb0: {
29+
StorageLive(_2);
30+
_2 = copy (*_1);
31+
StorageLive(_3);
32+
_3 = copy ((*_2).0: &u8);
33+
StorageLive(_4);
34+
_4 = copy (*_1);
35+
- StorageLive(_5);
36+
+ nop;
37+
_5 = copy ((*_4).0: &u8);
38+
StorageLive(_6);
39+
- _6 = copy ((*_4).0: &u8);
40+
+ _6 = copy _5;
41+
_0 = const ();
42+
StorageDead(_6);
43+
- StorageDead(_5);
44+
+ nop;
45+
StorageDead(_4);
46+
StorageDead(_3);
47+
StorageDead(_2);
48+
return;
49+
}
50+
}
51+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
- // MIR for `field_borrow_2` before GVN
2+
+ // MIR for `field_borrow_2` after GVN
3+
4+
fn field_borrow_2(_1: &&FieldBorrow<'_>) -> () {
5+
debug a => _1;
6+
let mut _0: ();
7+
let _2: &FieldBorrow<'_>;
8+
scope 1 {
9+
debug b => _2;
10+
let _3: &u8;
11+
scope 2 {
12+
debug c => _3;
13+
let _4: &FieldBorrow<'_>;
14+
scope 3 {
15+
debug d => _4;
16+
let _5: &u8;
17+
scope 4 {
18+
debug e => _5;
19+
let _6: &u8;
20+
scope 5 {
21+
debug f => _6;
22+
}
23+
}
24+
}
25+
}
26+
}
27+
28+
bb0: {
29+
StorageLive(_2);
30+
_2 = copy (*_1);
31+
StorageLive(_3);
32+
_3 = copy ((*_2).0: &u8);
33+
StorageLive(_4);
34+
_4 = copy (*_1);
35+
- StorageLive(_5);
36+
+ nop;
37+
_5 = copy ((*_4).0: &u8);
38+
StorageLive(_6);
39+
- _6 = copy ((*_4).0: &u8);
40+
+ _6 = copy _5;
41+
_0 = const ();
42+
StorageDead(_6);
43+
- StorageDead(_5);
44+
+ nop;
45+
StorageDead(_4);
46+
StorageDead(_3);
47+
StorageDead(_2);
48+
return;
49+
}
50+
}
51+

tests/mir-opt/gvn.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,53 @@ fn dereference_indexing(array: [u8; 2], index: usize) {
11001100
opaque(*a);
11011101
}
11021102

1103+
// EMIT_MIR gvn.dereference_reborrow.GVN.diff
1104+
fn dereference_reborrow(mut_a: &mut u8) {
1105+
// CHECK-LABEL: fn dereference_reborrow(
1106+
// CHECK: debug a => [[a:_.*]];
1107+
// CHECK: debug b => [[b:_.*]];
1108+
// CHECK: debug c => [[c:_.*]];
1109+
// CHECK: [[a]] = &(*_1);
1110+
// CHECK: [[b]] = copy (*[[a]]);
1111+
// CHECK: [[c]] = copy [[b]];
1112+
let a = &*mut_a;
1113+
let b = *a;
1114+
let c = *a;
1115+
}
1116+
1117+
struct FieldBorrow<'a>(&'a u8);
1118+
1119+
// EMIT_MIR gvn.field_borrow.GVN.diff
1120+
fn field_borrow(a: &FieldBorrow<'_>) {
1121+
// CHECK-LABEL: fn field_borrow(
1122+
// CHECK: debug b => [[b:_.*]];
1123+
// CHECK: debug c => [[c:_.*]];
1124+
// CHECK: [[b]] = copy ((*_1).0: &u8);
1125+
// CHECK: [[c]] = copy [[b]];
1126+
let b = a.0;
1127+
let c = a.0;
1128+
}
1129+
1130+
// EMIT_MIR gvn.field_borrow_2.GVN.diff
1131+
fn field_borrow_2(a: &&FieldBorrow<'_>) {
1132+
// CHECK-LABEL: fn field_borrow_2(
1133+
// CHECK: debug b => [[b:_.*]];
1134+
// CHECK: debug c => [[c:_.*]];
1135+
// CHECK: debug d => [[d:_.*]];
1136+
// CHECK: debug e => [[e:_.*]];
1137+
// CHECK: debug f => [[f:_.*]];
1138+
// CHECK: [[b]] = copy (*_1);
1139+
// CHECK: [[c]] = copy ((*[[b]]).0: &u8);
1140+
// CHECK: [[d]] = copy (*_1);
1141+
// CHECK: [[e]] = copy ((*[[d]]).0: &u8);
1142+
// CHECK: [[f]] = copy [[e]];
1143+
let b = *a;
1144+
let c = b.0;
1145+
let d = *a;
1146+
let e = d.0;
1147+
let f = d.0;
1148+
}
1149+
11031150
// CHECK-LABEL: fn main(
11041151
fn main() {
11051152
subexpression_elimination(2, 4, 5);
@@ -1129,6 +1176,9 @@ fn main() {
11291176
meta_of_ref_to_slice(&42);
11301177
slice_from_raw_parts_as_ptr(&123, 456);
11311178
dereference_indexing([129, 14], 5);
1179+
dereference_reborrow(&mut 5);
1180+
field_borrow(&FieldBorrow(&0));
1181+
field_borrow(&&FieldBorrow(&0));
11321182
}
11331183

11341184
#[inline(never)]

tests/mir-opt/gvn_copy_aggregate.all_copy_2.GVN.diff

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,13 @@
2929
_8 = copy (*_1);
3030
_2 = copy ((*_8).0: i32);
3131
- StorageLive(_3);
32-
- _9 = copy (*_1);
33-
- _3 = copy ((*_9).1: u64);
34-
- StorageLive(_4);
35-
- _10 = copy (*_1);
36-
- _4 = copy ((*_10).2: [i8; 3]);
3732
+ nop;
38-
+ _9 = copy _8;
39-
+ _3 = copy ((*_8).1: u64);
33+
_9 = copy (*_1);
34+
_3 = copy ((*_9).1: u64);
35+
- StorageLive(_4);
4036
+ nop;
41-
+ _10 = copy _8;
42-
+ _4 = copy ((*_8).2: [i8; 3]);
37+
_10 = copy (*_1);
38+
_4 = copy ((*_10).2: [i8; 3]);
4339
StorageLive(_5);
4440
_5 = copy _2;
4541
StorageLive(_6);

tests/mir-opt/pre-codegen/deref_nested_borrows.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
fn src(x: &&u8) -> bool {
44
// CHECK-LABEL: fn src(
5+
// CHECK: debug y => [[Y:_.*]];
6+
// CHECK: bb0:
7+
// CHECK: [[BORROW_u8:_.*]] = copy (*_1);
8+
// CHECK: [[Y]] = copy (*[[BORROW_u8]]);
9+
// CHECK: bb1:
10+
// BORROW_u8 outside its lifetime in bb1.
11+
// CHECK-NOT: copy (*[[BORROW_u8]]);
12+
// CHECK: copy (*_1);
13+
// CHECK-NOT: _0 = const true;
14+
// CHECK: _0 = Eq({{.*}}, {{.*}});
15+
// CHECK-NOT: _0 = const true;
516
let y = **x;
617
unsafe { unknown() };
718
**x == y

0 commit comments

Comments
 (0)