@@ -49,12 +49,13 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
49
49
50
50
let any_replacement = ssa. copy_classes ( ) . iter_enumerated ( ) . any ( |( l, & h) | l != h) ;
51
51
52
- let storage_to_remove = if any_replacement {
53
- // The replacer will remove tautological moves from the head to the local,
54
- // so we remove them before running `MaybeUninitializedPlaces`.
55
- TautologicalMoveAssignmentRemover {
52
+ if any_replacement {
53
+ let storage_to_remove = DenseBitSet :: new_empty ( fully_moved . domain_size ( ) ) ;
54
+
55
+ Replacer {
56
56
tcx,
57
57
copy_classes : ssa. copy_classes ( ) ,
58
+ fully_moved,
58
59
borrowed_locals : ssa. borrowed_locals ( ) ,
59
60
}
60
61
. visit_body_preserves_cfg ( body) ;
@@ -65,29 +66,18 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
65
66
. iterate_to_fixpoint ( tcx, body, Some ( "mir_opt::copy_prop" ) )
66
67
. into_results_cursor ( body) ;
67
68
68
- let mut storage_checker = StorageChecker {
69
- copy_classes : ssa. copy_classes ( ) ,
70
- maybe_uninit,
71
- head_storage_to_check,
72
- storage_to_remove : DenseBitSet :: new_empty ( fully_moved. domain_size ( ) ) ,
73
- } ;
69
+ debug ! ( ?head_storage_to_check) ;
74
70
75
- storage_checker. visit_body ( body) ;
71
+ let storage_to_remove = {
72
+ let mut storage_checker =
73
+ StorageChecker { maybe_uninit, head_storage_to_check, storage_to_remove } ;
76
74
77
- storage_checker. storage_to_remove
78
- } else {
79
- // Will be empty anyway.
80
- head_storage_to_check
81
- } ;
75
+ storage_checker. visit_body ( body) ;
82
76
83
- Replacer {
84
- tcx,
85
- copy_classes : ssa. copy_classes ( ) ,
86
- fully_moved,
87
- borrowed_locals : ssa. borrowed_locals ( ) ,
88
- storage_to_remove,
77
+ storage_checker. storage_to_remove
78
+ } ;
79
+ StorageRemover { tcx, storage_to_remove } . visit_body_preserves_cfg ( body) ;
89
80
}
90
- . visit_body_preserves_cfg ( body) ;
91
81
92
82
if any_replacement {
93
83
crate :: simplify:: remove_unused_definitions ( body) ;
@@ -134,46 +124,10 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> DenseBitSet<Local> {
134
124
fully_moved
135
125
}
136
126
137
- // We don't want to consider tautological moves in `MaybeUninitializedPlaces`, so we remove them before running it.
138
- struct TautologicalMoveAssignmentRemover < ' a , ' tcx > {
139
- tcx : TyCtxt < ' tcx > ,
140
- copy_classes : & ' a IndexSlice < Local , Local > ,
141
- borrowed_locals : & ' a DenseBitSet < Local > ,
142
- }
143
-
144
- impl < ' tcx > MutVisitor < ' tcx > for TautologicalMoveAssignmentRemover < ' _ , ' tcx > {
145
- fn tcx ( & self ) -> TyCtxt < ' tcx > {
146
- self . tcx
147
- }
148
-
149
- fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , loc : Location ) {
150
- self . super_statement ( stmt, loc) ;
151
-
152
- // Similar to `Replacer::visit_statement`, but only handle moves.
153
- if let StatementKind :: Assign ( box ( lhs, ref rhs) ) = stmt. kind
154
- && let Rvalue :: Use ( Operand :: Move ( rhs) ) = * rhs
155
- {
156
- if self . borrowed_locals . contains ( lhs. local ) || self . borrowed_locals . contains ( rhs. local )
157
- {
158
- return ;
159
- }
160
-
161
- let new_lhs_local = self . copy_classes [ lhs. local ] ;
162
- let new_rhs_local = self . copy_classes [ rhs. local ] ;
163
-
164
- if new_lhs_local == new_rhs_local && lhs. projection == rhs. projection {
165
- debug ! ( ?loc, ?lhs, ?rhs, "removing a to-be-tautological assignment" ) ;
166
- stmt. make_nop ( ) ;
167
- }
168
- }
169
- }
170
- }
171
-
172
127
/// Utility to help performing substitution of `*pattern` by `target`.
173
128
struct Replacer < ' a , ' tcx > {
174
129
tcx : TyCtxt < ' tcx > ,
175
130
fully_moved : DenseBitSet < Local > ,
176
- storage_to_remove : DenseBitSet < Local > ,
177
131
borrowed_locals : & ' a DenseBitSet < Local > ,
178
132
copy_classes : & ' a IndexSlice < Local , Local > ,
179
133
}
@@ -225,14 +179,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
225
179
}
226
180
227
181
fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , loc : Location ) {
228
- // When removing storage statements, we need to remove both (#107511).
229
- if let StatementKind :: StorageLive ( l) | StatementKind :: StorageDead ( l) = stmt. kind
230
- && self . storage_to_remove . contains ( l)
231
- {
232
- stmt. make_nop ( ) ;
233
- return ;
234
- }
235
-
236
182
self . super_statement ( stmt, loc) ;
237
183
238
184
// Do not leave tautological assignments around.
@@ -241,6 +187,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
241
187
* rhs
242
188
&& lhs == rhs
243
189
{
190
+ debug ! ( ?stmt, ?loc, ?lhs, ?rhs, "removing tautological assignment" ) ;
244
191
stmt. make_nop ( ) ;
245
192
}
246
193
}
@@ -250,42 +197,63 @@ struct StorageChecker<'a, 'tcx> {
250
197
storage_to_remove : DenseBitSet < Local > ,
251
198
head_storage_to_check : DenseBitSet < Local > ,
252
199
maybe_uninit : ResultsCursor < ' a , ' tcx , MaybeUninitializedPlaces < ' a , ' tcx > > ,
253
- copy_classes : & ' a IndexSlice < Local , Local > ,
254
200
}
255
201
256
202
impl < ' a , ' tcx > Visitor < ' tcx > for StorageChecker < ' a , ' tcx > {
257
203
fn visit_local ( & mut self , local : Local , context : PlaceContext , loc : Location ) {
258
- if !context. is_use ( ) {
259
- return ;
204
+ // We don't need to check storage statements and stores (for which the local doesn't need to be initialized).
205
+ match context {
206
+ PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) | PlaceContext :: NonUse ( _) => {
207
+ return ;
208
+ }
209
+ _ => { }
210
+ } ;
211
+
212
+ // The head must be initialized at the location of the local, otherwise we must remove it's storage statements.
213
+ if self . head_storage_to_check . contains ( local) {
214
+ if let Some ( move_idx) =
215
+ self . maybe_uninit . analysis ( ) . move_data ( ) . rev_lookup . find_local ( local)
216
+ {
217
+ self . maybe_uninit . seek_before_primary_effect ( loc) ;
218
+
219
+ if self . maybe_uninit . get ( ) . contains ( move_idx) {
220
+ debug ! (
221
+ ?loc,
222
+ ?context,
223
+ ?local,
224
+ ?move_idx,
225
+ "found a head at a location in which it is maybe uninit, marking head for storage statement removal"
226
+ ) ;
227
+ self . storage_to_remove . insert ( local) ;
228
+
229
+ // Once we found a use of the head that is maybe uninit, we do not need to check it again.
230
+ self . head_storage_to_check . remove ( local) ;
231
+ }
232
+ }
260
233
}
234
+ }
235
+ }
236
+
237
+ /// Utility to help performing substitution of `*pattern` by `target`.
238
+ struct StorageRemover < ' tcx > {
239
+ tcx : TyCtxt < ' tcx > ,
240
+ storage_to_remove : DenseBitSet < Local > ,
241
+ }
261
242
262
- let head = self . copy_classes [ local] ;
243
+ impl < ' tcx > MutVisitor < ' tcx > for StorageRemover < ' tcx > {
244
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
245
+ self . tcx
246
+ }
263
247
264
- if local == head {
265
- // Every original use of the head is known to be initialized, so we don't need to check it.
248
+ fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , loc : Location ) {
249
+ // When removing storage statements, we need to remove both (#107511).
250
+ if let StatementKind :: StorageLive ( l) | StatementKind :: StorageDead ( l) = stmt. kind
251
+ && self . storage_to_remove . contains ( l)
252
+ {
253
+ stmt. make_nop ( ) ;
266
254
return ;
267
255
}
268
256
269
- // The head must be initialized at the location of the local, otherwise we must remove it's storage statements.
270
- if self . head_storage_to_check . contains ( head)
271
- && let Some ( move_idx) =
272
- self . maybe_uninit . analysis ( ) . move_data ( ) . rev_lookup . find_local ( head)
273
- {
274
- self . maybe_uninit . seek_after_primary_effect ( loc) ;
275
-
276
- if self . maybe_uninit . get ( ) . contains ( move_idx) {
277
- debug ! (
278
- ?loc,
279
- ?local,
280
- ?head,
281
- ?move_idx,
282
- "found use of local with head at a location in which it is maybe uninit, marking head for storage statement removal"
283
- ) ;
284
- self . storage_to_remove . insert ( head) ;
285
-
286
- // Once we found a use of the head that is maybe uninit, we do not need to check it again.
287
- self . head_storage_to_check . remove ( head) ;
288
- }
289
- }
257
+ self . super_statement ( stmt, loc) ;
290
258
}
291
259
}
0 commit comments