Skip to content

Commit 109edab

Browse files
committed
Allow GVN to produce places and not just locals.
1 parent f174fd7 commit 109edab

17 files changed

+203
-58
lines changed

Diff for: compiler/rustc_mir_transform/src/gvn.rs

+39-27
Original file line numberDiff line numberDiff line change
@@ -980,27 +980,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
980980
}
981981
}
982982

983-
let tcx = self.tcx;
984-
let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new();
985-
loop {
986-
if let Some(local) = self.try_as_local(copy_from_local_value, location) {
987-
projection.reverse();
988-
let place = Place { local, projection: tcx.mk_place_elems(projection.as_slice()) };
989-
if rvalue.ty(self.local_decls, tcx) == place.ty(self.local_decls, tcx).ty {
990-
self.reused_locals.insert(local);
991-
*rvalue = Rvalue::Use(Operand::Copy(place));
992-
return Some(copy_from_value);
993-
}
994-
return None;
995-
} else if let Value::Projection(pointer, proj) = *self.get(copy_from_local_value)
996-
&& let Some(proj) = self.try_as_place_elem(proj, location)
997-
{
998-
projection.push(proj);
999-
copy_from_local_value = pointer;
1000-
} else {
1001-
return None;
983+
if let Some(place) = self.try_as_place(copy_from_local_value, location) {
984+
if rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty {
985+
self.reused_locals.insert(place.local);
986+
*rvalue = Rvalue::Use(Operand::Copy(place));
987+
return Some(copy_from_local_value);
1002988
}
1003989
}
990+
991+
None
1004992
}
1005993

1006994
fn simplify_aggregate(
@@ -1672,14 +1660,14 @@ fn op_to_prop_const<'tcx>(
16721660
}
16731661

16741662
impl<'tcx> VnState<'_, 'tcx> {
1675-
/// If either [`Self::try_as_constant`] as [`Self::try_as_local`] succeeds,
1663+
/// If either [`Self::try_as_constant`] as [`Self::try_as_place`] succeeds,
16761664
/// returns that result as an [`Operand`].
16771665
fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option<Operand<'tcx>> {
16781666
if let Some(const_) = self.try_as_constant(index) {
16791667
Some(Operand::Constant(Box::new(const_)))
1680-
} else if let Some(local) = self.try_as_local(index, location) {
1681-
self.reused_locals.insert(local);
1682-
Some(Operand::Copy(local.into()))
1668+
} else if let Some(place) = self.try_as_place(index, location) {
1669+
self.reused_locals.insert(place.local);
1670+
Some(Operand::Copy(place))
16831671
} else {
16841672
None
16851673
}
@@ -1712,6 +1700,29 @@ impl<'tcx> VnState<'_, 'tcx> {
17121700
Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_ })
17131701
}
17141702

1703+
/// Construct a place which holds the same value as `index` and for which all locals strictly
1704+
/// dominate `loc`. If you used this place, add its base local to `reused_locals` to remove
1705+
/// storage statements.
1706+
#[instrument(level = "trace", skip(self), ret)]
1707+
fn try_as_place(&mut self, mut index: VnIndex, loc: Location) -> Option<Place<'tcx>> {
1708+
let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new();
1709+
loop {
1710+
if let Some(local) = self.try_as_local(index, loc) {
1711+
projection.reverse();
1712+
let place =
1713+
Place { local, projection: self.tcx.mk_place_elems(projection.as_slice()) };
1714+
return Some(place);
1715+
} else if let Value::Projection(pointer, proj) = *self.get(index)
1716+
&& let Some(proj) = self.try_as_place_elem(proj, loc)
1717+
{
1718+
projection.push(proj);
1719+
index = pointer;
1720+
} else {
1721+
return None;
1722+
}
1723+
}
1724+
}
1725+
17151726
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
17161727
/// return it. If you used this local, add it to `reused_locals` to remove storage statements.
17171728
fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option<Local> {
@@ -1762,11 +1773,12 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
17621773
if let Some(value) = value {
17631774
if let Some(const_) = self.try_as_constant(value) {
17641775
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
1765-
} else if let Some(local) = self.try_as_local(value, location)
1766-
&& *rvalue != Rvalue::Use(Operand::Move(local.into()))
1776+
} else if let Some(place) = self.try_as_place(value, location)
1777+
&& *rvalue != Rvalue::Use(Operand::Move(place))
1778+
&& *rvalue != Rvalue::Use(Operand::Copy(place))
17671779
{
1768-
*rvalue = Rvalue::Use(Operand::Copy(local.into()));
1769-
self.reused_locals.insert(local);
1780+
*rvalue = Rvalue::Use(Operand::Copy(place));
1781+
self.reused_locals.insert(place.local);
17701782
}
17711783
}
17721784
}

Diff for: tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff

+2-4
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,13 @@
3131
(*_3) = const true;
3232
_4 = const ();
3333
StorageDead(_4);
34-
- StorageLive(_5);
35-
+ nop;
34+
StorageLive(_5);
3635
StorageLive(_6);
3736
_6 = copy (_2.1: bool);
3837
_5 = Not(move _6);
3938
StorageDead(_6);
4039
_0 = copy _5;
41-
- StorageDead(_5);
42-
+ nop;
40+
StorageDead(_5);
4341
StorageDead(_3);
4442
StorageDead(_2);
4543
return;

Diff for: tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff

+3-5
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@
6969

7070
bb0: {
7171
StorageLive(_1);
72-
- StorageLive(_2);
73-
+ nop;
72+
StorageLive(_2);
7473
StorageLive(_3);
7574
StorageLive(_11);
7675
StorageLive(_12);
@@ -119,8 +118,7 @@
119118
StorageDead(_11);
120119
_2 = &_3;
121120
_1 = copy _2;
122-
- StorageDead(_2);
123-
+ nop;
121+
StorageDead(_2);
124122
StorageLive(_4);
125123
- _9 = deref_copy _3;
126124
+ _9 = copy _3;
@@ -141,7 +139,7 @@
141139
StorageLive(_8);
142140
_8 = copy _5;
143141
- _7 = copy _8 as *mut () (PtrToPtr);
144-
+ _7 = copy _5 as *mut () (PtrToPtr);
142+
+ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute);
145143
StorageDead(_8);
146144
StorageDead(_7);
147145
- StorageDead(_5);

Diff for: tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff

+3-5
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,15 @@
3535

3636
bb0: {
3737
StorageLive(_1);
38-
- StorageLive(_2);
39-
+ nop;
38+
StorageLive(_2);
4039
StorageLive(_3);
4140
_3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue];
4241
}
4342

4443
bb1: {
4544
_2 = &_3;
4645
_1 = copy _2;
47-
- StorageDead(_2);
48-
+ nop;
46+
StorageDead(_2);
4947
StorageLive(_4);
5048
- _9 = deref_copy _3;
5149
+ _9 = copy _3;
@@ -66,7 +64,7 @@
6664
StorageLive(_8);
6765
_8 = copy _5;
6866
- _7 = copy _8 as *mut () (PtrToPtr);
69-
+ _7 = copy _5 as *mut () (PtrToPtr);
67+
+ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute);
7068
StorageDead(_8);
7169
StorageDead(_7);
7270
- StorageDead(_5);

Diff for: tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff

+3-5
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,7 @@
6969

7070
bb0: {
7171
StorageLive(_1);
72-
- StorageLive(_2);
73-
+ nop;
72+
StorageLive(_2);
7473
StorageLive(_3);
7574
StorageLive(_11);
7675
StorageLive(_12);
@@ -119,8 +118,7 @@
119118
StorageDead(_11);
120119
_2 = &_3;
121120
_1 = copy _2;
122-
- StorageDead(_2);
123-
+ nop;
121+
StorageDead(_2);
124122
StorageLive(_4);
125123
- _9 = deref_copy _3;
126124
+ _9 = copy _3;
@@ -141,7 +139,7 @@
141139
StorageLive(_8);
142140
_8 = copy _5;
143141
- _7 = copy _8 as *mut () (PtrToPtr);
144-
+ _7 = copy _5 as *mut () (PtrToPtr);
142+
+ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute);
145143
StorageDead(_8);
146144
StorageDead(_7);
147145
- StorageDead(_5);

Diff for: tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff

+3-5
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,15 @@
3535

3636
bb0: {
3737
StorageLive(_1);
38-
- StorageLive(_2);
39-
+ nop;
38+
StorageLive(_2);
4039
StorageLive(_3);
4140
_3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue];
4241
}
4342

4443
bb1: {
4544
_2 = &_3;
4645
_1 = copy _2;
47-
- StorageDead(_2);
48-
+ nop;
46+
StorageDead(_2);
4947
StorageLive(_4);
5048
- _9 = deref_copy _3;
5149
+ _9 = copy _3;
@@ -66,7 +64,7 @@
6664
StorageLive(_8);
6765
_8 = copy _5;
6866
- _7 = copy _8 as *mut () (PtrToPtr);
69-
+ _7 = copy _5 as *mut () (PtrToPtr);
67+
+ _7 = copy ((_9.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *mut () (Transmute);
7068
StorageDead(_8);
7169
StorageDead(_7);
7270
- StorageDead(_5);

Diff for: tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
bb0: {
1010
_3 = copy (*_1) as *const u8 (PtrToPtr);
1111
_4 = copy _2 as *const u8 (PtrToPtr);
12-
_0 = Eq(copy _3, copy _4);
12+
- _0 = Eq(copy _3, copy _4);
13+
+ _0 = Eq(copy (*_1), copy _2);
1314
return;
1415
}
1516
}

Diff for: tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
bb0: {
1010
_3 = copy (*_1) as *const u8 (PtrToPtr);
1111
_4 = copy _2 as *const u8 (PtrToPtr);
12-
_0 = Eq(copy _3, copy _4);
12+
- _0 = Eq(copy _3, copy _4);
13+
+ _0 = Eq(copy (*_1), copy _2);
1314
return;
1415
}
1516
}

Diff for: tests/mir-opt/gvn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ fn remove_casts_must_change_both_sides(mut_a: &*mut u8, mut_b: *mut u8) -> bool
10481048
let a = *mut_a as *const u8;
10491049
// CHECK: [[B:_.+]] = copy _2 as *const u8 (PtrToPtr);
10501050
let b = mut_b as *const u8;
1051-
// CHECK: _0 = Eq(copy [[A]], copy [[B]]);
1051+
// CHECK: _0 = Eq(copy (*_1), copy _2);
10521052
RET = a == b;
10531053
Return()
10541054
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
- // MIR for `compare_constant_index` before GVN
2+
+ // MIR for `compare_constant_index` after GVN
3+
4+
fn compare_constant_index(_1: [i32; 1], _2: [i32; 1]) -> std::cmp::Ordering {
5+
debug x => _1;
6+
debug y => _2;
7+
let mut _0: std::cmp::Ordering;
8+
let _3: &i32;
9+
let _4: usize;
10+
let mut _5: bool;
11+
let _6: &i32;
12+
let _7: usize;
13+
let mut _8: bool;
14+
scope 1 (inlined std::cmp::impls::<impl Ord for i32>::cmp) {
15+
let mut _9: i32;
16+
let mut _10: i32;
17+
}
18+
19+
bb0: {
20+
- StorageLive(_4);
21+
+ nop;
22+
_4 = const 0_usize;
23+
- _5 = Lt(copy _4, const 1_usize);
24+
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _4) -> [success: bb1, unwind unreachable];
25+
+ _5 = const true;
26+
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb1, unwind unreachable];
27+
}
28+
29+
bb1: {
30+
- _3 = &_1[_4];
31+
+ _3 = &_1[0 of 1];
32+
StorageLive(_7);
33+
_7 = const 0_usize;
34+
- _8 = Lt(copy _7, const 1_usize);
35+
- assert(move _8, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _7) -> [success: bb2, unwind unreachable];
36+
+ _8 = const true;
37+
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb2, unwind unreachable];
38+
}
39+
40+
bb2: {
41+
- _6 = &_2[_7];
42+
+ _6 = &_2[0 of 1];
43+
StorageLive(_9);
44+
- _9 = copy (*_3);
45+
+ _9 = copy _1[0 of 1];
46+
StorageLive(_10);
47+
- _10 = copy (*_6);
48+
+ _10 = copy _2[0 of 1];
49+
_0 = Cmp(move _9, move _10);
50+
StorageDead(_10);
51+
StorageDead(_9);
52+
StorageDead(_7);
53+
- StorageDead(_4);
54+
+ nop;
55+
return;
56+
}
57+
}
58+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
- // MIR for `compare_constant_index` before GVN
2+
+ // MIR for `compare_constant_index` after GVN
3+
4+
fn compare_constant_index(_1: [i32; 1], _2: [i32; 1]) -> std::cmp::Ordering {
5+
debug x => _1;
6+
debug y => _2;
7+
let mut _0: std::cmp::Ordering;
8+
let _3: &i32;
9+
let _4: usize;
10+
let mut _5: bool;
11+
let _6: &i32;
12+
let _7: usize;
13+
let mut _8: bool;
14+
scope 1 (inlined std::cmp::impls::<impl Ord for i32>::cmp) {
15+
let mut _9: i32;
16+
let mut _10: i32;
17+
}
18+
19+
bb0: {
20+
- StorageLive(_4);
21+
+ nop;
22+
_4 = const 0_usize;
23+
- _5 = Lt(copy _4, const 1_usize);
24+
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _4) -> [success: bb1, unwind continue];
25+
+ _5 = const true;
26+
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb1, unwind continue];
27+
}
28+
29+
bb1: {
30+
- _3 = &_1[_4];
31+
+ _3 = &_1[0 of 1];
32+
StorageLive(_7);
33+
_7 = const 0_usize;
34+
- _8 = Lt(copy _7, const 1_usize);
35+
- assert(move _8, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _7) -> [success: bb2, unwind continue];
36+
+ _8 = const true;
37+
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 1_usize, const 0_usize) -> [success: bb2, unwind continue];
38+
}
39+
40+
bb2: {
41+
- _6 = &_2[_7];
42+
+ _6 = &_2[0 of 1];
43+
StorageLive(_9);
44+
- _9 = copy (*_3);
45+
+ _9 = copy _1[0 of 1];
46+
StorageLive(_10);
47+
- _10 = copy (*_6);
48+
+ _10 = copy _2[0 of 1];
49+
_0 = Cmp(move _9, move _10);
50+
StorageDead(_10);
51+
StorageDead(_9);
52+
StorageDead(_7);
53+
- StorageDead(_4);
54+
+ nop;
55+
return;
56+
}
57+
}
58+

0 commit comments

Comments
 (0)