@@ -4,7 +4,7 @@ use crate::MirPass;
44use rustc_hir:: Mutability ;
55use rustc_middle:: mir:: {
66 BinOp , Body , Constant , LocalDecls , Operand , Place , ProjectionElem , Rvalue , SourceInfo ,
7- StatementKind , UnOp ,
7+ Statement , StatementKind , Terminator , TerminatorKind , UnOp ,
88} ;
99use rustc_middle:: ty:: { self , TyCtxt } ;
1010
@@ -29,6 +29,11 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
2929 _ => { }
3030 }
3131 }
32+
33+ ctx. combine_primitive_clone (
34+ & mut block. terminator . as_mut ( ) . unwrap ( ) ,
35+ & mut block. statements ,
36+ ) ;
3237 }
3338 }
3439}
@@ -130,4 +135,70 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
130135 }
131136 }
132137 }
138+
139+ fn combine_primitive_clone (
140+ & self ,
141+ terminator : & mut Terminator < ' tcx > ,
142+ statements : & mut Vec < Statement < ' tcx > > ,
143+ ) {
144+ let TerminatorKind :: Call { func, args, destination, .. } = & mut terminator. kind
145+ else { return } ;
146+
147+ // It's definitely not a clone if there are multiple arguments
148+ if args. len ( ) != 1 {
149+ return ;
150+ }
151+
152+ let Some ( ( destination_place, destination_block) ) = * destination
153+ else { return } ;
154+
155+ // Only bother looking more if it's easy to know what we're calling
156+ let Some ( ( fn_def_id, fn_substs) ) = func. const_fn_def ( )
157+ else { return } ;
158+
159+ // Clone needs one subst, so we can cheaply rule out other stuff
160+ if fn_substs. len ( ) != 1 {
161+ return ;
162+ }
163+
164+ // These types are easily available from locals, so check that before
165+ // doing DefId lookups to figure out what we're actually calling.
166+ let arg_ty = args[ 0 ] . ty ( self . local_decls , self . tcx ) ;
167+
168+ let ty:: Ref ( _region, inner_ty, Mutability :: Not ) = * arg_ty. kind ( )
169+ else { return } ;
170+
171+ if !inner_ty. is_trivially_pure_clone_copy ( ) {
172+ return ;
173+ }
174+
175+ let trait_def_id = self . tcx . trait_of_item ( fn_def_id) ;
176+ if trait_def_id. is_none ( ) || trait_def_id != self . tcx . lang_items ( ) . clone_trait ( ) {
177+ return ;
178+ }
179+
180+ if !self . tcx . consider_optimizing ( || {
181+ format ! (
182+ "InstCombine - Call: {:?} SourceInfo: {:?}" ,
183+ ( fn_def_id, fn_substs) ,
184+ terminator. source_info
185+ )
186+ } ) {
187+ return ;
188+ }
189+
190+ let Some ( arg_place) = args. pop ( ) . unwrap ( ) . place ( )
191+ else { return } ;
192+
193+ statements. push ( Statement {
194+ source_info : terminator. source_info ,
195+ kind : StatementKind :: Assign ( box (
196+ destination_place,
197+ Rvalue :: Use ( Operand :: Copy (
198+ arg_place. project_deeper ( & [ ProjectionElem :: Deref ] , self . tcx ) ,
199+ ) ) ,
200+ ) ) ,
201+ } ) ;
202+ terminator. kind = TerminatorKind :: Goto { target : destination_block } ;
203+ }
133204}
0 commit comments