@@ -4,6 +4,7 @@ use crate::simplify::simplify_duplicate_switch_targets;
4
4
use crate :: take_array;
5
5
use rustc_ast:: attr;
6
6
use rustc_hir:: LangItem ;
7
+ use rustc_index:: IndexVec ;
7
8
use rustc_middle:: bug;
8
9
use rustc_middle:: mir:: * ;
9
10
use rustc_middle:: ty:: layout;
@@ -13,9 +14,25 @@ use rustc_span::sym;
13
14
use rustc_span:: symbol:: Symbol ;
14
15
use rustc_target:: spec:: abi:: Abi ;
15
16
16
- pub struct InstSimplify ;
17
+ pub enum InstSimplify {
18
+ BeforeInline ,
19
+ AfterSimplifyCfg ,
20
+ }
21
+
22
+ impl InstSimplify {
23
+ pub fn name ( & self ) -> & ' static str {
24
+ match self {
25
+ InstSimplify :: BeforeInline => "InstSimplify-before-inline" ,
26
+ InstSimplify :: AfterSimplifyCfg => "InstSimplify-after-simplifycfg" ,
27
+ }
28
+ }
29
+ }
17
30
18
31
impl < ' tcx > MirPass < ' tcx > for InstSimplify {
32
+ fn name ( & self ) -> & ' static str {
33
+ self . name ( )
34
+ }
35
+
19
36
fn is_enabled ( & self , sess : & rustc_session:: Session ) -> bool {
20
37
sess. mir_opt_level ( ) > 0
21
38
}
@@ -44,8 +61,8 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
44
61
_ => { }
45
62
}
46
63
}
47
-
48
64
ctx. simplify_primitive_clone ( block. terminator . as_mut ( ) . unwrap ( ) , & mut block. statements ) ;
65
+ ctx. simplify_copy_like ( & mut block. statements ) ;
49
66
ctx. simplify_intrinsic_assert ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
50
67
ctx. simplify_nounwind_call ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
51
68
simplify_duplicate_switch_targets ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
@@ -191,6 +208,95 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
191
208
}
192
209
}
193
210
211
+ /// Transform `Aggregate(Adt, [(*_1).0, (*_1).1])` ==> `Copy(*_1)`.
212
+ /// This comes from the simplification of the clone method by `simplify_primitive_clone`.
213
+ fn simplify_copy_like ( & self , statements : & mut Vec < Statement < ' tcx > > ) {
214
+ let mut assignments = IndexVec :: from_elem ( None :: < Place < ' tcx > > , self . local_decls ) ;
215
+ for statement in statements {
216
+ match statement. kind {
217
+ StatementKind :: Assign ( box ( dest, ref mut rvalue) ) => {
218
+ if let Rvalue :: Aggregate ( _, fields) = rvalue {
219
+ let mut from_local = None ;
220
+ if fields. iter_enumerated ( ) . all ( |( index, field) | {
221
+ let Some ( from_place) = field
222
+ . place ( )
223
+ . and_then ( |p| p. as_local ( ) )
224
+ . and_then ( |l| assignments[ l] )
225
+ else {
226
+ return false ;
227
+ } ;
228
+ // All fields must come from the same local.
229
+ if let Some ( from_local) = from_local {
230
+ if from_place. local != from_local {
231
+ return false ;
232
+ }
233
+ } else {
234
+ // We can only copy the same type.
235
+ let Some ( from_ty) =
236
+ self . local_decls [ from_place. local ] . ty . builtin_deref ( false )
237
+ else {
238
+ return false ;
239
+ } ;
240
+ let dest_ty = dest. ty ( self . local_decls , self . tcx ) . ty ;
241
+ if dest_ty != from_ty {
242
+ return false ;
243
+ } ;
244
+ from_local = Some ( from_place. local ) ;
245
+ }
246
+ // For more complex scenarios, we expect to get this simplified projection within a complete pipeline.
247
+ let [ ProjectionElem :: Deref , ProjectionElem :: Field ( from_index, _) ] =
248
+ * from_place. projection . as_slice ( )
249
+ else {
250
+ return false ;
251
+ } ;
252
+ from_index == index
253
+ } ) {
254
+ if let Some ( local) = from_local {
255
+ if self . should_simplify ( & statement. source_info , rvalue) {
256
+ * rvalue = Rvalue :: Use ( Operand :: Copy ( Place {
257
+ local,
258
+ projection : self
259
+ . tcx
260
+ . mk_place_elems ( & [ ProjectionElem :: Deref ] ) ,
261
+ } ) ) ;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ // Collect available assignments, including those transformed from `Aggregate`.
267
+ if let Some ( local) = dest. as_local ( ) {
268
+ assignments[ local] = if let Rvalue :: Use ( operand) = rvalue
269
+ && let Some ( place) = operand. place ( )
270
+ {
271
+ if let Some ( rvalue_local) = place. as_local ( ) {
272
+ let place = assignments[ rvalue_local] ;
273
+ if operand. is_move ( ) {
274
+ assignments[ rvalue_local] = None ;
275
+ }
276
+ place
277
+ } else {
278
+ Some ( place)
279
+ }
280
+ } else {
281
+ // This assignment generally comes from debuginfo (e.g., Ref),
282
+ // but we still need to check if a local is being overridden.
283
+ None
284
+ } ;
285
+ } else {
286
+ // We don't handle projection, so we drop all previous assignments.
287
+ assignments. reset_all ( None ) ;
288
+ }
289
+ }
290
+ StatementKind :: StorageLive ( _)
291
+ | StatementKind :: StorageDead ( _)
292
+ | StatementKind :: Nop => { }
293
+ _ => {
294
+ assignments. reset_all ( None ) ;
295
+ }
296
+ }
297
+ }
298
+ }
299
+
194
300
fn simplify_cast ( & self , rvalue : & mut Rvalue < ' tcx > ) {
195
301
if let Rvalue :: Cast ( kind, operand, cast_ty) = rvalue {
196
302
let operand_ty = operand. ty ( self . local_decls , self . tcx ) ;
0 commit comments