1
1
use std:: iter;
2
2
3
+ use rustc_hir as hir;
3
4
use rustc_index:: IndexVec ;
4
5
use rustc_index:: bit_set:: DenseBitSet ;
5
6
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
6
- use rustc_middle:: mir:: { Local , UnwindTerminateReason , traversal} ;
7
+ use rustc_middle:: mir:: { Body , Local , UnwindTerminateReason , traversal} ;
7
8
use rustc_middle:: ty:: layout:: { FnAbiOf , HasTyCtxt , HasTypingEnv , TyAndLayout } ;
8
9
use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt , TypeFoldable , TypeVisitableExt } ;
9
10
use rustc_middle:: { bug, mir, span_bug} ;
@@ -171,18 +172,24 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
171
172
assert ! ( !instance. args. has_infer( ) ) ;
172
173
173
174
let llfn = cx. get_fn ( instance) ;
175
+ let tcx = cx. tcx ( ) ;
174
176
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
+ ) ;
176
183
177
184
let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
178
185
debug ! ( "fn_abi: {:?}" , fn_abi) ;
179
186
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 ) {
181
188
crate :: mir:: naked_asm:: codegen_naked_asm :: < Bx > ( cx, & mir, instance) ;
182
189
return ;
183
190
}
184
191
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) ;
186
193
187
194
let start_llbb = Bx :: append_block ( cx, llfn, "start" ) ;
188
195
let mut start_bx = Bx :: build ( cx, start_llbb) ;
@@ -194,7 +201,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
194
201
}
195
202
196
203
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) ) ;
198
205
199
206
let cached_llbbs: IndexVec < mir:: BasicBlock , CachedLlbb < Bx :: BasicBlock > > =
200
207
mir. basic_blocks
@@ -204,6 +211,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
204
211
} )
205
212
. collect ( ) ;
206
213
214
+ let mir = tcx. arena . alloc ( optimize_use_clone ( tcx, mir) ) ;
215
+
207
216
let mut fx = FunctionCx {
208
217
instance,
209
218
mir,
@@ -217,7 +226,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
217
226
cleanup_kinds,
218
227
landing_pads : IndexVec :: from_elem ( None , & mir. basic_blocks ) ,
219
228
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) ,
221
230
locals : locals:: Locals :: empty ( ) ,
222
231
debug_context,
223
232
per_local_var_debug_info : None ,
@@ -233,7 +242,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
233
242
fx. compute_per_local_var_debug_info ( & mut start_bx) . unzip ( ) ;
234
243
fx. per_local_var_debug_info = per_local_var_debug_info;
235
244
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) ;
237
246
let memory_locals = analyze:: non_ssa_locals ( & fx, & traversal_order) ;
238
247
239
248
// Allocate variable and temp allocas
@@ -310,6 +319,71 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
310
319
}
311
320
}
312
321
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
+
313
387
/// Produces, for each argument, a `Value` pointing at the
314
388
/// argument's value. As arguments are places, these are always
315
389
/// indirect.
0 commit comments