@@ -176,24 +176,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
176
176
177
177
let mut mir = tcx. instance_mir ( instance. def ) ;
178
178
179
- let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
180
- debug ! ( "fn_abi: {:?}" , fn_abi) ;
181
-
182
- if tcx. features ( ) . ergonomic_clones ( ) {
183
- let monomorphized_mir = instance. instantiate_mir_and_normalize_erasing_regions (
179
+ mir = {
180
+ let mut mir = instance. instantiate_mir_and_normalize_erasing_regions (
184
181
tcx,
185
182
ty:: TypingEnv :: fully_monomorphized ( ) ,
186
183
ty:: EarlyBinder :: bind ( mir. clone ( ) ) ,
187
184
) ;
188
- mir = tcx. arena . alloc ( optimize_use_clone :: < Bx > ( cx, monomorphized_mir) ) ;
189
- }
185
+
186
+ if tcx. features ( ) . ergonomic_clones ( ) {
187
+ mir = optimize_use_clone :: < Bx > ( cx, mir) ;
188
+ }
189
+ mir = optimize_noop_cleanup :: < Bx > ( cx, mir, instance) ;
190
+ tcx. arena . alloc ( mir)
191
+ } ;
192
+
193
+ let fn_abi = cx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
194
+ debug ! ( "fn_abi: {:?}" , fn_abi) ;
190
195
191
196
let debug_context = cx. create_function_debug_context ( instance, fn_abi, llfn, & mir) ;
192
197
193
198
let start_llbb = Bx :: append_block ( cx, llfn, "start" ) ;
194
199
let mut start_bx = Bx :: build ( cx, start_llbb) ;
195
200
196
- if mir. basic_blocks . iter ( ) . any ( |bb | {
201
+ if mir:: traversal :: mono_reachable ( & mir , tcx , instance ) . any ( |( _ , bb ) | {
197
202
bb. is_cleanup || matches ! ( bb. terminator( ) . unwind( ) , Some ( mir:: UnwindAction :: Terminate ( _) ) )
198
203
} ) {
199
204
start_bx. set_personality_fn ( cx. eh_personality ( ) ) ;
@@ -371,6 +376,116 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
371
376
mir
372
377
}
373
378
379
+ // FIXME: Move this function to mir::transform when post-mono MIR passes land.
380
+ //
381
+ /// Detect cases where monomorphized MIR has a cleanup block (or series of blocks) that never does
382
+ /// anything, just resumes unwinding.
383
+ ///
384
+ /// This usually results from pre-mono MIR having a no-op drop(...) for a specific type.
385
+ fn optimize_noop_cleanup < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
386
+ cx : & ' a Bx :: CodegenCx ,
387
+ mut mir : Body < ' tcx > ,
388
+ instance : Instance < ' tcx > ,
389
+ ) -> Body < ' tcx > {
390
+ let tcx = cx. tcx ( ) ;
391
+
392
+ let mut any_action = DenseBitSet :: new_empty ( mir. basic_blocks . len ( ) ) ;
393
+ for ( bb, block) in mir. basic_blocks . iter_enumerated ( ) {
394
+ if !block. is_cleanup {
395
+ // We don't care about non-cleanup blocks.
396
+ any_action. insert ( bb) ;
397
+ continue ;
398
+ }
399
+
400
+ let mut has_actions = false ;
401
+ for stmt in & block. statements {
402
+ match stmt. kind {
403
+ mir:: StatementKind :: SetDiscriminant { .. }
404
+ | mir:: StatementKind :: Deinit ( ..)
405
+ | mir:: StatementKind :: StorageLive ( ..)
406
+ | mir:: StatementKind :: StorageDead ( ..)
407
+ | mir:: StatementKind :: Retag ( ..)
408
+ | mir:: StatementKind :: Coverage ( ..)
409
+ | mir:: StatementKind :: Intrinsic ( ..)
410
+ | mir:: StatementKind :: Assign ( ..) => {
411
+ has_actions = true ;
412
+ break ;
413
+ }
414
+ mir:: StatementKind :: FakeRead ( ..)
415
+ | mir:: StatementKind :: PlaceMention ( ..)
416
+ | mir:: StatementKind :: AscribeUserType ( ..)
417
+ | mir:: StatementKind :: ConstEvalCounter
418
+ | mir:: StatementKind :: Nop
419
+ | mir:: StatementKind :: BackwardIncompatibleDropHint { .. } => { }
420
+ }
421
+ }
422
+ match block. terminator ( ) . kind {
423
+ mir:: TerminatorKind :: Goto { .. }
424
+ | mir:: TerminatorKind :: SwitchInt { .. }
425
+ | mir:: TerminatorKind :: UnwindResume
426
+ | mir:: TerminatorKind :: Unreachable => { }
427
+
428
+ mir:: TerminatorKind :: Call { .. }
429
+ | mir:: TerminatorKind :: Assert { .. }
430
+ | mir:: TerminatorKind :: Yield { .. }
431
+ | mir:: TerminatorKind :: InlineAsm { .. }
432
+ | mir:: TerminatorKind :: CoroutineDrop
433
+ | mir:: TerminatorKind :: TailCall { .. }
434
+ | mir:: TerminatorKind :: UnwindTerminate ( ..)
435
+ | mir:: TerminatorKind :: Return => has_actions = true ,
436
+
437
+ mir:: TerminatorKind :: Drop { place, .. } => {
438
+ let ty = place. ty ( & mir, tcx) . ty ;
439
+ debug ! ( "monomorphize: instance={:?}" , instance) ;
440
+ let ty = instance. instantiate_mir_and_normalize_erasing_regions (
441
+ tcx,
442
+ cx. typing_env ( ) ,
443
+ ty:: EarlyBinder :: bind ( ty) ,
444
+ ) ;
445
+ let drop_fn = Instance :: resolve_drop_in_place ( tcx, ty) ;
446
+ if let ty:: InstanceKind :: DropGlue ( _, None ) = drop_fn. def {
447
+ // no need to drop anything
448
+ } else {
449
+ has_actions = true ;
450
+ }
451
+ }
452
+
453
+ mir:: TerminatorKind :: FalseEdge { .. } | mir:: TerminatorKind :: FalseUnwind { .. } => {
454
+ bug ! ( "not present in optimized mir" )
455
+ }
456
+ }
457
+
458
+ if has_actions {
459
+ any_action. insert ( bb) ;
460
+ }
461
+ }
462
+
463
+ let mut to_replace = vec ! [ ] ;
464
+ for ( bb, block) in mir. basic_blocks . iter_enumerated ( ) {
465
+ if let Some ( mir:: UnwindAction :: Cleanup ( target) ) = block. terminator ( ) . unwind ( ) {
466
+ let mut stack = vec ! [ * target] ;
467
+ let mut found_action = false ;
468
+ while let Some ( next) = stack. pop ( ) {
469
+ if any_action. contains ( next) {
470
+ found_action = true ;
471
+ break ;
472
+ }
473
+ stack. extend ( mir. basic_blocks [ next] . terminator ( ) . successors ( ) ) ;
474
+ }
475
+ if !found_action {
476
+ to_replace. push ( bb) ;
477
+ }
478
+ }
479
+ }
480
+
481
+ for bb in to_replace {
482
+ * mir. basic_blocks_mut ( ) [ bb] . terminator_mut ( ) . unwind_mut ( ) . unwrap ( ) =
483
+ mir:: UnwindAction :: Continue ;
484
+ }
485
+
486
+ mir
487
+ }
488
+
374
489
/// Produces, for each argument, a `Value` pointing at the
375
490
/// argument's value. As arguments are places, these are always
376
491
/// indirect.
0 commit comments