Skip to content

Commit 22f542c

Browse files
committed
Auto merge of #120689 - clubby789:copy-prop-consts, r=<try>
CopyProp: Propagate moves of constants Yet another try of #120650 - this time, keep track of SSA locals with a constant value and propagate it. Then, re-run `SimplifyConstCondition` to take advantage of it (simply reordering the pass regressed some tests). r? `@ghost`
2 parents 0d53135 + 7a6abd5 commit 22f542c

7 files changed

+479
-476
lines changed

compiler/rustc_mir_transform/src/copy_prop.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_data_structures::fx::FxIndexMap;
12
use rustc_index::bit_set::BitSet;
23
use rustc_index::IndexSlice;
34
use rustc_middle::mir::visit::*;
@@ -37,6 +38,8 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
3738

3839
let fully_moved = fully_moved_locals(&ssa, body);
3940
debug!(?fully_moved);
41+
let const_locals = const_locals(&ssa, body);
42+
debug!(?const_locals);
4043

4144
let mut storage_to_remove = BitSet::new_empty(fully_moved.domain_size());
4245
for (local, &head) in ssa.copy_classes().iter_enumerated() {
@@ -51,6 +54,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
5154
tcx,
5255
copy_classes: ssa.copy_classes(),
5356
fully_moved,
57+
const_locals,
5458
borrowed_locals,
5559
storage_to_remove,
5660
}
@@ -96,10 +100,28 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
96100
fully_moved
97101
}
98102

103+
/// Finds all locals that are only assigned to once with a deterministic constant
104+
#[instrument(level = "trace", skip(ssa, body))]
105+
fn const_locals<'body, 'tcx>(
106+
ssa: &'body SsaLocals,
107+
body: &'body Body<'tcx>,
108+
) -> FxIndexMap<Local, ConstOperand<'tcx>> {
109+
let mut const_locals = FxIndexMap::default();
110+
for (local, rvalue, _) in ssa.assignments(body) {
111+
let Rvalue::Use(Operand::Constant(val)) = rvalue else { continue };
112+
if !val.const_.is_deterministic() {
113+
continue;
114+
}
115+
const_locals.insert(local, **val);
116+
}
117+
const_locals
118+
}
119+
99120
/// Utility to help performing substitution of `*pattern` by `target`.
100121
struct Replacer<'a, 'tcx> {
101122
tcx: TyCtxt<'tcx>,
102123
fully_moved: BitSet<Local>,
124+
const_locals: FxIndexMap<Local, ConstOperand<'tcx>>,
103125
storage_to_remove: BitSet<Local>,
104126
borrowed_locals: BitSet<Local>,
105127
copy_classes: &'a IndexSlice<Local, Local>,
@@ -154,9 +176,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
154176
if let Operand::Move(place) = *operand
155177
// A move out of a projection of a copy is equivalent to a copy of the original projection.
156178
&& !place.is_indirect_first_projection()
157-
&& !self.fully_moved.contains(place.local)
158179
{
159-
*operand = Operand::Copy(place);
180+
if !self.fully_moved.contains(place.local) {
181+
*operand = Operand::Copy(place);
182+
} else if let Some(local) = place.as_local()
183+
&& let Some(val) = self.const_locals.get(&local)
184+
{
185+
*operand = Operand::Constant(Box::new(*val))
186+
}
160187
}
161188
self.super_operand(operand, loc);
162189
}

tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir

+78-82
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,58 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
44
debug slice => _1;
55
debug f => _2;
66
let mut _0: ();
7-
let mut _13: std::slice::Iter<'_, T>;
7+
let mut _12: std::slice::Iter<'_, T>;
8+
let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>;
89
let mut _14: std::iter::Enumerate<std::slice::Iter<'_, T>>;
9-
let mut _15: std::iter::Enumerate<std::slice::Iter<'_, T>>;
10-
let mut _16: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
11-
let mut _17: std::option::Option<(usize, &T)>;
12-
let mut _18: isize;
13-
let mut _21: &impl Fn(usize, &T);
14-
let mut _22: (usize, &T);
15-
let _23: ();
10+
let mut _15: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
11+
let mut _16: std::option::Option<(usize, &T)>;
12+
let mut _17: isize;
13+
let mut _20: &impl Fn(usize, &T);
14+
let mut _21: (usize, &T);
15+
let _22: ();
1616
scope 1 {
17-
debug iter => _15;
18-
let _19: usize;
19-
let _20: &T;
17+
debug iter => _14;
18+
let _18: usize;
19+
let _19: &T;
2020
scope 2 {
21-
debug i => _19;
22-
debug x => _20;
21+
debug i => _18;
22+
debug x => _19;
2323
}
2424
}
2525
scope 3 (inlined core::slice::<impl [T]>::iter) {
2626
debug self => _1;
2727
scope 4 (inlined std::slice::Iter::<'_, T>::new) {
2828
debug slice => _1;
2929
let _4: *const T;
30-
let mut _5: bool;
31-
let mut _6: usize;
32-
let mut _8: usize;
33-
let mut _9: *mut T;
34-
let mut _11: std::ptr::NonNull<T>;
35-
let mut _12: *const T;
30+
let mut _5: usize;
31+
let mut _7: usize;
32+
let mut _8: *mut T;
33+
let mut _10: std::ptr::NonNull<T>;
34+
let mut _11: *const T;
3635
scope 5 {
3736
debug ptr => _4;
3837
scope 6 {
39-
let _7: *const T;
38+
let _6: *const T;
4039
scope 7 {
41-
debug end_or_len => _7;
40+
debug end_or_len => _6;
4241
scope 13 (inlined NonNull::<T>::new_unchecked) {
43-
debug ptr => _9;
44-
let mut _10: *const T;
45-
let mut _24: *mut T;
42+
debug ptr => _8;
43+
let mut _9: *const T;
44+
let mut _23: *mut T;
4645
scope 14 {
4746
scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) {
48-
debug ptr => _24;
47+
debug ptr => _23;
4948
scope 16 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null) {
50-
debug self => _24;
51-
let mut _25: *mut u8;
49+
debug self => _23;
50+
let mut _24: *mut u8;
5251
scope 17 {
5352
scope 18 (inlined std::ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) {
54-
debug ptr => _25;
53+
debug ptr => _24;
5554
scope 19 (inlined std::ptr::mut_ptr::<impl *mut u8>::addr) {
56-
debug self => _25;
55+
debug self => _24;
5756
scope 20 {
5857
scope 21 (inlined std::ptr::mut_ptr::<impl *mut u8>::cast::<()>) {
59-
debug self => _25;
58+
debug self => _24;
6059
}
6160
}
6261
}
@@ -68,13 +67,13 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
6867
}
6968
}
7069
scope 9 (inlined invalid::<T>) {
71-
debug addr => _8;
70+
debug addr => _7;
7271
scope 10 {
7372
}
7473
}
7574
scope 11 (inlined std::ptr::const_ptr::<impl *const T>::add) {
7675
debug self => _4;
77-
debug count => _6;
76+
debug count => _5;
7877
scope 12 {
7978
}
8079
}
@@ -87,88 +86,85 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
8786
}
8887
}
8988
scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::enumerate) {
90-
debug self => _13;
89+
debug self => _12;
9190
scope 23 (inlined Enumerate::<std::slice::Iter<'_, T>>::new) {
92-
debug iter => _13;
91+
debug iter => _12;
9392
}
9493
}
9594
scope 24 (inlined <Enumerate<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) {
96-
debug self => _14;
95+
debug self => _13;
9796
}
9897

9998
bb0: {
100-
StorageLive(_13);
99+
StorageLive(_12);
101100
StorageLive(_4);
102101
StorageLive(_3);
103102
_3 = &raw const (*_1);
104103
_4 = move _3 as *const T (PtrToPtr);
105104
StorageDead(_3);
106-
StorageLive(_7);
107-
StorageLive(_5);
108-
_5 = const _;
109-
switchInt(move _5) -> [0: bb1, otherwise: bb2];
105+
StorageLive(_6);
106+
switchInt(const _) -> [0: bb1, otherwise: bb2];
110107
}
111108

112109
bb1: {
113-
StorageLive(_6);
114-
_6 = Len((*_1));
115-
_7 = Offset(_4, _6);
116-
StorageDead(_6);
110+
StorageLive(_5);
111+
_5 = Len((*_1));
112+
_6 = Offset(_4, _5);
113+
StorageDead(_5);
117114
goto -> bb3;
118115
}
119116

120117
bb2: {
121-
StorageLive(_8);
122-
_8 = Len((*_1));
123-
_7 = _8 as *const T (Transmute);
124-
StorageDead(_8);
118+
StorageLive(_7);
119+
_7 = Len((*_1));
120+
_6 = _7 as *const T (Transmute);
121+
StorageDead(_7);
125122
goto -> bb3;
126123
}
127124

128125
bb3: {
129-
StorageDead(_5);
130-
StorageLive(_11);
131-
StorageLive(_9);
132-
_9 = _4 as *mut T (PtrToPtr);
133126
StorageLive(_10);
127+
StorageLive(_8);
128+
_8 = _4 as *mut T (PtrToPtr);
129+
StorageLive(_9);
130+
StorageLive(_23);
134131
StorageLive(_24);
135-
StorageLive(_25);
136-
_10 = _9 as *const T (PointerCoercion(MutToConstPointer));
137-
_11 = NonNull::<T> { pointer: _10 };
138-
StorageDead(_25);
132+
_9 = _8 as *const T (PointerCoercion(MutToConstPointer));
133+
_10 = NonNull::<T> { pointer: _9 };
139134
StorageDead(_24);
140-
StorageDead(_10);
135+
StorageDead(_23);
141136
StorageDead(_9);
142-
StorageLive(_12);
143-
_12 = _7;
144-
_13 = std::slice::Iter::<'_, T> { ptr: move _11, end_or_len: move _12, _marker: const ZeroSized: PhantomData<&T> };
145-
StorageDead(_12);
137+
StorageDead(_8);
138+
StorageLive(_11);
139+
_11 = _6;
140+
_12 = std::slice::Iter::<'_, T> { ptr: move _10, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> };
146141
StorageDead(_11);
147-
StorageDead(_7);
142+
StorageDead(_10);
143+
StorageDead(_6);
148144
StorageDead(_4);
149-
_14 = Enumerate::<std::slice::Iter<'_, T>> { iter: _13, count: const 0_usize };
150-
StorageDead(_13);
151-
StorageLive(_15);
152-
_15 = _14;
145+
_13 = Enumerate::<std::slice::Iter<'_, T>> { iter: _12, count: const 0_usize };
146+
StorageDead(_12);
147+
StorageLive(_14);
148+
_14 = _13;
153149
goto -> bb4;
154150
}
155151

156152
bb4: {
157-
StorageLive(_17);
158153
StorageLive(_16);
159-
_16 = &mut _15;
160-
_17 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _16) -> [return: bb5, unwind unreachable];
154+
StorageLive(_15);
155+
_15 = &mut _14;
156+
_16 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _15) -> [return: bb5, unwind unreachable];
161157
}
162158

163159
bb5: {
164-
StorageDead(_16);
165-
_18 = discriminant(_17);
166-
switchInt(move _18) -> [0: bb6, 1: bb8, otherwise: bb10];
160+
StorageDead(_15);
161+
_17 = discriminant(_16);
162+
switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10];
167163
}
168164

169165
bb6: {
170-
StorageDead(_17);
171-
StorageDead(_15);
166+
StorageDead(_16);
167+
StorageDead(_14);
172168
drop(_2) -> [return: bb7, unwind unreachable];
173169
}
174170

@@ -177,19 +173,19 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
177173
}
178174

179175
bb8: {
180-
_19 = (((_17 as Some).0: (usize, &T)).0: usize);
181-
_20 = (((_17 as Some).0: (usize, &T)).1: &T);
176+
_18 = (((_16 as Some).0: (usize, &T)).0: usize);
177+
_19 = (((_16 as Some).0: (usize, &T)).1: &T);
178+
StorageLive(_20);
179+
_20 = &_2;
182180
StorageLive(_21);
183-
_21 = &_2;
184-
StorageLive(_22);
185-
_22 = (_19, _20);
186-
_23 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _21, move _22) -> [return: bb9, unwind unreachable];
181+
_21 = (_18, _19);
182+
_22 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _20, move _21) -> [return: bb9, unwind unreachable];
187183
}
188184

189185
bb9: {
190-
StorageDead(_22);
191186
StorageDead(_21);
192-
StorageDead(_17);
187+
StorageDead(_20);
188+
StorageDead(_16);
193189
goto -> bb4;
194190
}
195191

0 commit comments

Comments
 (0)