11use std:: iter;
22
3+ use rustc_hir as hir;
34use rustc_index:: IndexVec ;
45use rustc_index:: bit_set:: DenseBitSet ;
56use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
6- use rustc_middle:: mir:: { Local , UnwindTerminateReason , traversal} ;
7+ use rustc_middle:: mir:: { Body , Local , UnwindTerminateReason , traversal} ;
78use rustc_middle:: ty:: layout:: { FnAbiOf , HasTyCtxt , HasTypingEnv , TyAndLayout } ;
89use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt , TypeFoldable , TypeVisitableExt } ;
910use rustc_middle:: { bug, mir, span_bug} ;
@@ -171,18 +172,24 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
171172 assert ! ( !instance. args. has_infer( ) ) ;
172173
173174 let llfn = cx. get_fn ( instance) ;
175+ let tcx = cx. tcx ( ) ;
174176
175- let mir = cx. tcx ( ) . instance_mir ( instance. def ) ;
177+ let mir = tcx. instance_mir ( instance. def ) ;
178+ let mir = instance. instantiate_mir_and_normalize_erasing_regions (
179+ tcx,
180+ ty:: TypingEnv :: fully_monomorphized ( ) ,
181+ ty:: EarlyBinder :: bind ( mir. clone ( ) ) ,
182+ ) ;
176183
177184 let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
178185 debug ! ( "fn_abi: {:?}" , fn_abi) ;
179186
180- if cx . tcx ( ) . codegen_fn_attrs ( instance. def_id ( ) ) . flags . contains ( CodegenFnAttrFlags :: NAKED ) {
187+ if tcx. codegen_fn_attrs ( instance. def_id ( ) ) . flags . contains ( CodegenFnAttrFlags :: NAKED ) {
181188 crate :: mir:: naked_asm:: codegen_naked_asm :: < Bx > ( cx, & mir, instance) ;
182189 return ;
183190 }
184191
185- let debug_context = cx. create_function_debug_context ( instance, fn_abi, llfn, mir) ;
192+ let debug_context = cx. create_function_debug_context ( instance, fn_abi, llfn, & mir) ;
186193
187194 let start_llbb = Bx :: append_block ( cx, llfn, "start" ) ;
188195 let mut start_bx = Bx :: build ( cx, start_llbb) ;
@@ -194,7 +201,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
194201 }
195202
196203 let cleanup_kinds =
197- base:: wants_new_eh_instructions ( cx . tcx ( ) . sess ) . then ( || analyze:: cleanup_kinds ( mir) ) ;
204+ base:: wants_new_eh_instructions ( tcx. sess ) . then ( || analyze:: cleanup_kinds ( & mir) ) ;
198205
199206 let cached_llbbs: IndexVec < mir:: BasicBlock , CachedLlbb < Bx :: BasicBlock > > =
200207 mir. basic_blocks
@@ -204,6 +211,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
204211 } )
205212 . collect ( ) ;
206213
214+ let mir = tcx. arena . alloc ( optimize_use_clone ( tcx, mir) ) ;
215+
207216 let mut fx = FunctionCx {
208217 instance,
209218 mir,
@@ -217,7 +226,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
217226 cleanup_kinds,
218227 landing_pads : IndexVec :: from_elem ( None , & mir. basic_blocks ) ,
219228 funclets : IndexVec :: from_fn_n ( |_| None , mir. basic_blocks . len ( ) ) ,
220- cold_blocks : find_cold_blocks ( cx . tcx ( ) , mir) ,
229+ cold_blocks : find_cold_blocks ( tcx, mir) ,
221230 locals : locals:: Locals :: empty ( ) ,
222231 debug_context,
223232 per_local_var_debug_info : None ,
@@ -233,7 +242,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
233242 fx. compute_per_local_var_debug_info ( & mut start_bx) . unzip ( ) ;
234243 fx. per_local_var_debug_info = per_local_var_debug_info;
235244
236- let traversal_order = traversal:: mono_reachable_reverse_postorder ( mir, cx . tcx ( ) , instance) ;
245+ let traversal_order = traversal:: mono_reachable_reverse_postorder ( mir, tcx, instance) ;
237246 let memory_locals = analyze:: non_ssa_locals ( & fx, & traversal_order) ;
238247
239248 // Allocate variable and temp allocas
@@ -310,6 +319,71 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
310319 }
311320}
312321
322+ // FIXME: Move this function to mir::transform when post-mono MIR passes land.
323+ fn optimize_use_clone < ' tcx > ( tcx : TyCtxt < ' tcx > , mut mir : Body < ' tcx > ) -> Body < ' tcx > {
324+ if tcx. features ( ) . ergonomic_clones ( ) {
325+ for bb in mir. basic_blocks . as_mut ( ) {
326+ let mir:: TerminatorKind :: Call {
327+ func,
328+ args,
329+ destination,
330+ target,
331+ call_source : mir:: CallSource :: Use ,
332+ ..
333+ } = & bb. terminator ( ) . kind
334+ else {
335+ continue ;
336+ } ;
337+
338+ // It's definitely not a clone if there are multiple arguments
339+ let [ arg] = & args[ ..] else { continue } ;
340+
341+ // These types are easily available from locals, so check that before
342+ // doing DefId lookups to figure out what we're actually calling.
343+ let arg_ty = arg. node . ty ( & mir. local_decls , tcx) ;
344+
345+ // monomorphize
346+ // is already monomorphized
347+ // let arg_ty = instance.instantiate_mir_and_normalize_erasing_regions(
348+ // cx.tcx(),
349+ // cx.typing_env(),
350+ // ty::EarlyBinder::bind(arg_ty),
351+ // );
352+
353+ // Only bother looking more if it's easy to know what we're calling
354+ let Some ( ( fn_def_id, _) ) = func. const_fn_def ( ) else { continue } ;
355+
356+ let ty:: Ref ( _region, inner_ty, mir:: Mutability :: Not ) = * arg_ty. kind ( ) else { continue } ;
357+
358+ if !inner_ty. is_trivially_pure_clone_copy ( ) {
359+ continue ;
360+ }
361+
362+ if !tcx. is_lang_item ( fn_def_id, hir:: LangItem :: CloneFn ) {
363+ continue ;
364+ }
365+
366+ let Some ( arg_place) = arg. node . place ( ) else { continue } ;
367+
368+ let destination_block = target. unwrap ( ) ;
369+
370+ bb. statements . push ( mir:: Statement {
371+ source_info : bb. terminator ( ) . source_info ,
372+ kind : mir:: StatementKind :: Assign ( Box :: new ( (
373+ * destination,
374+ mir:: Rvalue :: Use ( mir:: Operand :: Copy (
375+ arg_place. project_deeper ( & [ mir:: ProjectionElem :: Deref ] , tcx) ,
376+ ) ) ,
377+ ) ) ) ,
378+ } ) ;
379+
380+ bb. terminator_mut ( ) . kind = mir:: TerminatorKind :: Goto { target : destination_block } ;
381+ }
382+ }
383+
384+ mir
385+ }
386+
313387/// Produces, for each argument, a `Value` pointing at the
314388/// argument's value. As arguments are places, these are always
315389/// indirect.
0 commit comments