@@ -6,6 +6,7 @@ use std::ops::{Range, RangeFrom};
6
6
7
7
use rustc_abi:: { ExternAbi , FieldIdx } ;
8
8
use rustc_attr_data_structures:: { InlineAttr , OptimizeAttr } ;
9
+ use rustc_hir:: LangItem ;
9
10
use rustc_hir:: def:: DefKind ;
10
11
use rustc_hir:: def_id:: DefId ;
11
12
use rustc_index:: Idx ;
@@ -116,6 +117,9 @@ trait Inliner<'tcx> {
116
117
/// Has the caller body been changed?
117
118
fn changed ( self ) -> bool ;
118
119
120
+ /// Whether to also attempt to inline `Drop` terminators (not just `Call`s)
121
+ fn consider_drops ( & self ) -> bool ;
122
+
119
123
/// Should inlining happen for a given callee?
120
124
fn should_inline_for_callee ( & self , def_id : DefId ) -> bool ;
121
125
@@ -187,6 +191,10 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
187
191
self . changed
188
192
}
189
193
194
+ fn consider_drops ( & self ) -> bool {
195
+ false
196
+ }
197
+
190
198
fn should_inline_for_callee ( & self , def_id : DefId ) -> bool {
191
199
ForceInline :: should_run_pass_for_callee ( self . tcx ( ) , def_id)
192
200
}
@@ -272,6 +280,7 @@ struct NormalInliner<'tcx> {
272
280
typing_env : ty:: TypingEnv < ' tcx > ,
273
281
/// `DefId` of caller.
274
282
def_id : DefId ,
283
+ caller_is_coroutine : bool ,
275
284
/// Stack of inlined instances.
276
285
/// We only check the `DefId` and not the args because we want to
277
286
/// avoid inlining cases of polymorphic recursion.
@@ -304,6 +313,7 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> {
304
313
tcx,
305
314
typing_env,
306
315
def_id,
316
+ caller_is_coroutine : tcx. is_coroutine ( def_id) ,
307
317
history : Vec :: new ( ) ,
308
318
top_down_counter : 0 ,
309
319
changed : false ,
@@ -334,6 +344,10 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> {
334
344
self . changed
335
345
}
336
346
347
+ fn consider_drops ( & self ) -> bool {
348
+ !self . caller_is_coroutine
349
+ }
350
+
337
351
fn should_inline_for_callee ( & self , _: DefId ) -> bool {
338
352
true
339
353
}
@@ -549,50 +563,77 @@ fn resolve_callsite<'tcx, I: Inliner<'tcx>>(
549
563
bb_data : & BasicBlockData < ' tcx > ,
550
564
) -> Option < CallSite < ' tcx > > {
551
565
let tcx = inliner. tcx ( ) ;
552
- // Only consider direct calls to functions
553
566
let terminator = bb_data. terminator ( ) ;
554
567
555
568
// FIXME(explicit_tail_calls): figure out if we can inline tail calls
556
- if let TerminatorKind :: Call { ref func, fn_span, .. } = terminator. kind {
557
- let func_ty = func. ty ( caller_body, tcx) ;
558
- if let ty:: FnDef ( def_id, args) = * func_ty. kind ( ) {
559
- if !inliner. should_inline_for_callee ( def_id) {
560
- debug ! ( "not enabled" ) ;
561
- return None ;
562
- }
569
+ let ( def_id, args, fn_span) = match & terminator. kind {
570
+ TerminatorKind :: Call { func, fn_span, .. } => {
571
+ let func_ty = func. ty ( caller_body, tcx) ;
572
+ if let ty:: FnDef ( def_id, args) = * func_ty. kind ( ) {
573
+ if !inliner. should_inline_for_callee ( def_id) {
574
+ debug ! ( "not enabled" ) ;
575
+ return None ;
576
+ }
563
577
564
- // To resolve an instance its args have to be fully normalized.
565
- let args = tcx. try_normalize_erasing_regions ( inliner. typing_env ( ) , args) . ok ( ) ?;
566
- let callee =
567
- Instance :: try_resolve ( tcx, inliner. typing_env ( ) , def_id, args) . ok ( ) . flatten ( ) ?;
578
+ // Allow RemoveUnneededDrops to handle these, rather than inlining,
579
+ // since it doesn't add the extra locals nor the metadata.
580
+ if inliner. consider_drops ( )
581
+ && tcx. is_lang_item ( def_id, LangItem :: DropInPlace )
582
+ && let drop_ty = args. type_at ( 0 )
583
+ && !drop_ty. needs_drop ( tcx, inliner. typing_env ( ) )
584
+ {
585
+ return None ;
586
+ }
568
587
569
- if let InstanceKind :: Virtual ( ..) | InstanceKind :: Intrinsic ( _) = callee. def {
588
+ ( def_id, args, * fn_span)
589
+ } else {
570
590
return None ;
571
591
}
572
-
573
- if inliner. history ( ) . contains ( & callee. def_id ( ) ) {
592
+ }
593
+ TerminatorKind :: Drop { place, .. } if inliner. consider_drops ( ) => {
594
+ let drop_ty = place. ty ( & caller_body. local_decls , tcx) . ty ;
595
+ if !drop_ty. needs_drop ( tcx, inliner. typing_env ( ) )
596
+ // FIXME: Box's shim looks like it inlines fine, but it's quite
597
+ // a bit of MIR right now, so is currently skipped to avoid churn.
598
+ || drop_ty. is_box ( )
599
+ {
574
600
return None ;
575
601
}
576
602
577
- let fn_sig = tcx. fn_sig ( def_id) . instantiate ( tcx, args) ;
603
+ let drop_def_id =
604
+ tcx. require_lang_item ( LangItem :: DropInPlace , terminator. source_info . span ) ;
605
+ let args = tcx. mk_args ( & [ drop_ty. into ( ) ] ) ;
606
+ ( drop_def_id, args, rustc_span:: DUMMY_SP )
607
+ }
608
+ _ => return None ,
609
+ } ;
578
610
579
- // Additionally, check that the body that we're inlining actually agrees
580
- // with the ABI of the trait that the item comes from.
581
- if let InstanceKind :: Item ( instance_def_id) = callee. def
582
- && tcx. def_kind ( instance_def_id) == DefKind :: AssocFn
583
- && let instance_fn_sig = tcx. fn_sig ( instance_def_id) . skip_binder ( )
584
- && instance_fn_sig. abi ( ) != fn_sig. abi ( )
585
- {
586
- return None ;
587
- }
611
+ // To resolve an instance its args have to be fully normalized.
612
+ let args = tcx. try_normalize_erasing_regions ( inliner. typing_env ( ) , args) . ok ( ) ?;
613
+ let callee = Instance :: try_resolve ( tcx, inliner. typing_env ( ) , def_id, args) . ok ( ) . flatten ( ) ?;
588
614
589
- let source_info = SourceInfo { span : fn_span, ..terminator. source_info } ;
615
+ if let InstanceKind :: Virtual ( ..) | InstanceKind :: Intrinsic ( _) = callee. def {
616
+ return None ;
617
+ }
590
618
591
- return Some ( CallSite { callee, fn_sig, block : bb, source_info } ) ;
592
- }
619
+ if inliner. history ( ) . contains ( & callee. def_id ( ) ) {
620
+ return None ;
621
+ }
622
+
623
+ let fn_sig = tcx. fn_sig ( def_id) . instantiate ( tcx, args) ;
624
+
625
+ // Additionally, check that the body that we're inlining actually agrees
626
+ // with the ABI of the trait that the item comes from.
627
+ if let InstanceKind :: Item ( instance_def_id) = callee. def
628
+ && tcx. def_kind ( instance_def_id) == DefKind :: AssocFn
629
+ && let instance_fn_sig = tcx. fn_sig ( instance_def_id) . skip_binder ( )
630
+ && instance_fn_sig. abi ( ) != fn_sig. abi ( )
631
+ {
632
+ return None ;
593
633
}
594
634
595
- None
635
+ let source_info = SourceInfo { span : fn_span, ..terminator. source_info } ;
636
+ Some ( CallSite { callee, fn_sig, block : bb, source_info } )
596
637
}
597
638
598
639
/// Attempts to inline a callsite into the caller body. When successful returns basic blocks
@@ -604,14 +645,72 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
604
645
callsite : & CallSite < ' tcx > ,
605
646
) -> Result < std:: ops:: Range < BasicBlock > , & ' static str > {
606
647
let tcx = inliner. tcx ( ) ;
648
+
607
649
check_mir_is_available ( inliner, caller_body, callsite. callee ) ?;
608
650
609
651
let callee_attrs = tcx. codegen_fn_attrs ( callsite. callee . def_id ( ) ) ;
610
652
check_inline:: is_inline_valid_on_fn ( tcx, callsite. callee . def_id ( ) ) ?;
611
653
check_codegen_attributes ( inliner, callsite, callee_attrs) ?;
612
654
inliner. check_codegen_attributes_extra ( callee_attrs) ?;
613
655
614
- let terminator = caller_body[ callsite. block ] . terminator . as_ref ( ) . unwrap ( ) ;
656
+ let callee_body = try_instance_mir ( tcx, callsite. callee . def ) ?;
657
+ check_inline:: is_inline_valid_on_body ( tcx, callee_body) ?;
658
+ inliner. check_callee_mir_body ( callsite, callee_body, callee_attrs) ?;
659
+
660
+ if inliner. consider_drops ( ) {
661
+ let block_mut = & mut caller_body. basic_blocks . as_mut ( ) [ callsite. block ] ;
662
+ let terminator = block_mut. terminator . as_mut ( ) . unwrap ( ) ;
663
+ if let TerminatorKind :: Drop {
664
+ place,
665
+ target,
666
+ unwind,
667
+ replace : _,
668
+ drop : None ,
669
+ async_fut : None ,
670
+ } = terminator. kind
671
+ {
672
+ // Rather than updating everything after here to also handle `Drop`,
673
+ // just replace the terminator with a `Call`, since we'll need things
674
+ // like the local for the argument anyway.
675
+ let source_info = terminator. source_info ;
676
+ let drop_ty = place. ty ( & caller_body. local_decls , tcx) . ty ;
677
+ if !drop_ty. needs_drop ( tcx, inliner. typing_env ( ) ) {
678
+ //return None;
679
+ bug ! ( "Why does it think {drop_ty:?} needs a drop *now*?" ) ;
680
+ }
681
+
682
+ let drop_ty_mut = Ty :: new_mut_ptr ( tcx, drop_ty) ;
683
+ let arg = caller_body. local_decls . push ( LocalDecl :: new ( drop_ty_mut, source_info. span ) ) ;
684
+ block_mut. statements . push ( Statement :: new (
685
+ source_info,
686
+ StatementKind :: Assign ( Box :: new ( (
687
+ Place :: from ( arg) ,
688
+ Rvalue :: RawPtr ( RawPtrKind :: Mut , place) ,
689
+ ) ) ) ,
690
+ ) ) ;
691
+ let unit_local =
692
+ caller_body. local_decls . push ( LocalDecl :: new ( tcx. types . unit , source_info. span ) ) ;
693
+ terminator. kind = TerminatorKind :: Call {
694
+ func : Operand :: function_handle (
695
+ tcx,
696
+ callsite. callee . def_id ( ) ,
697
+ [ drop_ty. into ( ) ] ,
698
+ source_info. span ,
699
+ ) ,
700
+ args : Box :: new ( [ Spanned {
701
+ node : Operand :: Move ( Place :: from ( arg) ) ,
702
+ span : source_info. span ,
703
+ } ] ) ,
704
+ destination : Place :: from ( unit_local) ,
705
+ target : Some ( target) ,
706
+ unwind,
707
+ call_source : CallSource :: Misc ,
708
+ fn_span : source_info. span ,
709
+ } ;
710
+ }
711
+ }
712
+
713
+ let terminator = caller_body[ callsite. block ] . terminator ( ) ;
615
714
let TerminatorKind :: Call { args, destination, .. } = & terminator. kind else { bug ! ( ) } ;
616
715
let destination_ty = destination. ty ( & caller_body. local_decls , tcx) . ty ;
617
716
for arg in args {
@@ -622,10 +721,6 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
622
721
}
623
722
}
624
723
625
- let callee_body = try_instance_mir ( tcx, callsite. callee . def ) ?;
626
- check_inline:: is_inline_valid_on_body ( tcx, callee_body) ?;
627
- inliner. check_callee_mir_body ( callsite, callee_body, callee_attrs) ?;
628
-
629
724
let Ok ( callee_body) = callsite. callee . try_instantiate_mir_and_normalize_erasing_regions (
630
725
tcx,
631
726
inliner. typing_env ( ) ,
0 commit comments