@@ -4,6 +4,7 @@ use crate::simplify::simplify_duplicate_switch_targets;
44use crate :: take_array;
55use rustc_ast:: attr;
66use rustc_hir:: LangItem ;
7+ use rustc_index:: IndexVec ;
78use rustc_middle:: bug;
89use rustc_middle:: mir:: * ;
910use rustc_middle:: ty:: layout;
@@ -13,9 +14,25 @@ use rustc_span::sym;
1314use rustc_span:: symbol:: Symbol ;
1415use rustc_target:: spec:: abi:: Abi ;
1516
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+ }
1730
1831impl < ' tcx > MirPass < ' tcx > for InstSimplify {
32+ fn name ( & self ) -> & ' static str {
33+ self . name ( )
34+ }
35+
1936 fn is_enabled ( & self , sess : & rustc_session:: Session ) -> bool {
2037 sess. mir_opt_level ( ) > 0
2138 }
@@ -44,8 +61,8 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
4461 _ => { }
4562 }
4663 }
47-
4864 ctx. simplify_primitive_clone ( block. terminator . as_mut ( ) . unwrap ( ) , & mut block. statements ) ;
65+ ctx. simplify_copy_like ( & mut block. statements ) ;
4966 ctx. simplify_intrinsic_assert ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
5067 ctx. simplify_nounwind_call ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
5168 simplify_duplicate_switch_targets ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
@@ -191,6 +208,95 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
191208 }
192209 }
193210
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+
194300 fn simplify_cast ( & self , rvalue : & mut Rvalue < ' tcx > ) {
195301 if let Rvalue :: Cast ( kind, operand, cast_ty) = rvalue {
196302 let operand_ty = operand. ty ( self . local_decls , self . tcx ) ;
0 commit comments