@@ -31,7 +31,8 @@ pub struct Inline;
3131#[ derive( Copy , Clone , Debug ) ]
3232struct CallSite < ' tcx > {
3333 callee : Instance < ' tcx > ,
34- bb : BasicBlock ,
34+ block : BasicBlock ,
35+ target : Option < BasicBlock > ,
3536 source_info : SourceInfo ,
3637}
3738
@@ -175,8 +176,7 @@ impl Inliner<'tcx> {
175176
176177 // Only consider direct calls to functions
177178 let terminator = bb_data. terminator ( ) ;
178- // FIXME: Handle inlining of diverging calls
179- if let TerminatorKind :: Call { func : ref op, destination : Some ( _) , .. } = terminator. kind {
179+ if let TerminatorKind :: Call { func : ref op, ref destination, .. } = terminator. kind {
180180 if let ty:: FnDef ( callee_def_id, substs) = * op. ty ( caller_body, self . tcx ) . kind ( ) {
181181 // To resolve an instance its substs have to be fully normalized, so
182182 // we do this here.
@@ -190,7 +190,12 @@ impl Inliner<'tcx> {
190190 return None ;
191191 }
192192
193- return Some ( CallSite { callee, bb, source_info : terminator. source_info } ) ;
193+ return Some ( CallSite {
194+ callee,
195+ block : bb,
196+ target : destination. map ( |( _, target) | target) ,
197+ source_info : terminator. source_info ,
198+ } ) ;
194199 }
195200 }
196201
@@ -398,9 +403,9 @@ impl Inliner<'tcx> {
398403 caller_body : & mut Body < ' tcx > ,
399404 mut callee_body : Body < ' tcx > ,
400405 ) {
401- let terminator = caller_body[ callsite. bb ] . terminator . take ( ) . unwrap ( ) ;
406+ let terminator = caller_body[ callsite. block ] . terminator . take ( ) . unwrap ( ) ;
402407 match terminator. kind {
403- TerminatorKind :: Call { args, destination : Some ( destination ) , cleanup, .. } => {
408+ TerminatorKind :: Call { args, destination, cleanup, .. } => {
404409 // If the call is something like `a[*i] = f(i)`, where
405410 // `i : &mut usize`, then just duplicating the `a[*i]`
406411 // Place could result in two different locations if `f`
@@ -417,43 +422,39 @@ impl Inliner<'tcx> {
417422 false
418423 }
419424
420- let dest = if dest_needs_borrow ( destination. 0 ) {
421- trace ! ( "creating temp for return destination" ) ;
422- let dest = Rvalue :: Ref (
423- self . tcx . lifetimes . re_erased ,
424- BorrowKind :: Mut { allow_two_phase_borrow : false } ,
425- destination. 0 ,
426- ) ;
427-
428- let ty = dest. ty ( caller_body, self . tcx ) ;
429-
430- let temp = LocalDecl :: new ( ty, callsite. source_info . span ) ;
431-
432- let tmp = caller_body. local_decls . push ( temp) ;
433- let tmp = Place :: from ( tmp) ;
434-
435- let stmt = Statement {
436- source_info : callsite. source_info ,
437- kind : StatementKind :: Assign ( box ( tmp, dest) ) ,
438- } ;
439- caller_body[ callsite. bb ] . statements . push ( stmt) ;
440- self . tcx . mk_place_deref ( tmp)
425+ let dest = if let Some ( ( destination_place, _) ) = destination {
426+ if dest_needs_borrow ( destination_place) {
427+ trace ! ( "creating temp for return destination" ) ;
428+ let dest = Rvalue :: Ref (
429+ self . tcx . lifetimes . re_erased ,
430+ BorrowKind :: Mut { allow_two_phase_borrow : false } ,
431+ destination_place,
432+ ) ;
433+ let dest_ty = dest. ty ( caller_body, self . tcx ) ;
434+ let temp = Place :: from ( self . new_call_temp ( caller_body, & callsite, dest_ty) ) ;
435+ caller_body[ callsite. block ] . statements . push ( Statement {
436+ source_info : callsite. source_info ,
437+ kind : StatementKind :: Assign ( box ( temp, dest) ) ,
438+ } ) ;
439+ self . tcx . mk_place_deref ( temp)
440+ } else {
441+ destination_place
442+ }
441443 } else {
442- destination. 0
444+ trace ! ( "creating temp for return place" ) ;
445+ Place :: from ( self . new_call_temp ( caller_body, & callsite, callee_body. return_ty ( ) ) )
443446 } ;
444447
445- let return_block = destination. 1 ;
446-
447448 // Copy the arguments if needed.
448- let args: Vec < _ > = self . make_call_args ( args, & callsite, caller_body, return_block ) ;
449+ let args: Vec < _ > = self . make_call_args ( args, & callsite, caller_body) ;
449450
450451 let mut integrator = Integrator {
451452 args : & args,
452453 new_locals : Local :: new ( caller_body. local_decls . len ( ) ) ..,
453454 new_scopes : SourceScope :: new ( caller_body. source_scopes . len ( ) ) ..,
454455 new_blocks : BasicBlock :: new ( caller_body. basic_blocks ( ) . len ( ) ) ..,
455456 destination : dest,
456- return_block,
457+ return_block : callsite . target ,
457458 cleanup_block : cleanup,
458459 in_cleanup_block : false ,
459460 tcx : self . tcx ,
@@ -502,7 +503,7 @@ impl Inliner<'tcx> {
502503 caller_body. var_debug_info . extend ( callee_body. var_debug_info . drain ( ..) ) ;
503504 caller_body. basic_blocks_mut ( ) . extend ( callee_body. basic_blocks_mut ( ) . drain ( ..) ) ;
504505
505- caller_body[ callsite. bb ] . terminator = Some ( Terminator {
506+ caller_body[ callsite. block ] . terminator = Some ( Terminator {
506507 source_info : callsite. source_info ,
507508 kind : TerminatorKind :: Goto { target : integrator. map_block ( START_BLOCK ) } ,
508509 } ) ;
@@ -526,7 +527,6 @@ impl Inliner<'tcx> {
526527 args : Vec < Operand < ' tcx > > ,
527528 callsite : & CallSite < ' tcx > ,
528529 caller_body : & mut Body < ' tcx > ,
529- return_block : BasicBlock ,
530530 ) -> Vec < Local > {
531531 let tcx = self . tcx ;
532532
@@ -557,18 +557,8 @@ impl Inliner<'tcx> {
557557 // `callee_body.spread_arg == None`, instead of special-casing closures.
558558 if tcx. is_closure ( callsite. callee . def_id ( ) ) {
559559 let mut args = args. into_iter ( ) ;
560- let self_ = self . create_temp_if_necessary (
561- args. next ( ) . unwrap ( ) ,
562- callsite,
563- caller_body,
564- return_block,
565- ) ;
566- let tuple = self . create_temp_if_necessary (
567- args. next ( ) . unwrap ( ) ,
568- callsite,
569- caller_body,
570- return_block,
571- ) ;
560+ let self_ = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_body) ;
561+ let tuple = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_body) ;
572562 assert ! ( args. next( ) . is_none( ) ) ;
573563
574564 let tuple = Place :: from ( tuple) ;
@@ -588,13 +578,13 @@ impl Inliner<'tcx> {
588578 Operand :: Move ( tcx. mk_place_field ( tuple, Field :: new ( i) , ty. expect_ty ( ) ) ) ;
589579
590580 // Spill to a local to make e.g., `tmp0`.
591- self . create_temp_if_necessary ( tuple_field, callsite, caller_body, return_block )
581+ self . create_temp_if_necessary ( tuple_field, callsite, caller_body)
592582 } ) ;
593583
594584 closure_ref_arg. chain ( tuple_tmp_args) . collect ( )
595585 } else {
596586 args. into_iter ( )
597- . map ( |a| self . create_temp_if_necessary ( a, callsite, caller_body, return_block ) )
587+ . map ( |a| self . create_temp_if_necessary ( a, callsite, caller_body) )
598588 . collect ( )
599589 }
600590 }
@@ -606,46 +596,52 @@ impl Inliner<'tcx> {
606596 arg : Operand < ' tcx > ,
607597 callsite : & CallSite < ' tcx > ,
608598 caller_body : & mut Body < ' tcx > ,
609- return_block : BasicBlock ,
610599 ) -> Local {
611- // FIXME: Analysis of the usage of the arguments to avoid
612- // unnecessary temporaries.
613-
600+ // Reuse the operand if it is a moved temporary.
614601 if let Operand :: Move ( place) = & arg {
615602 if let Some ( local) = place. as_local ( ) {
616603 if caller_body. local_kind ( local) == LocalKind :: Temp {
617- // Reuse the operand if it's a temporary already
618604 return local;
619605 }
620606 }
621607 }
622608
609+ // Otherwise, create a temporary for the argument.
623610 trace ! ( "creating temp for argument {:?}" , arg) ;
624- // Otherwise, create a temporary for the arg
625- let arg = Rvalue :: Use ( arg) ;
626-
627- let ty = arg. ty ( caller_body, self . tcx ) ;
628-
629- let arg_tmp = LocalDecl :: new ( ty, callsite. source_info . span ) ;
630- let arg_tmp = caller_body. local_decls . push ( arg_tmp) ;
631-
632- caller_body[ callsite. bb ] . statements . push ( Statement {
611+ let arg_ty = arg. ty ( caller_body, self . tcx ) ;
612+ let local = self . new_call_temp ( caller_body, callsite, arg_ty) ;
613+ caller_body[ callsite. block ] . statements . push ( Statement {
633614 source_info : callsite. source_info ,
634- kind : StatementKind :: StorageLive ( arg_tmp ) ,
615+ kind : StatementKind :: Assign ( box ( Place :: from ( local ) , Rvalue :: Use ( arg ) ) ) ,
635616 } ) ;
636- caller_body[ callsite. bb ] . statements . push ( Statement {
617+ local
618+ }
619+
620+ /// Introduces a new temporary into the caller body that is live for the duration of the call.
621+ fn new_call_temp (
622+ & self ,
623+ caller_body : & mut Body < ' tcx > ,
624+ callsite : & CallSite < ' tcx > ,
625+ ty : Ty < ' tcx > ,
626+ ) -> Local {
627+ let local = caller_body. local_decls . push ( LocalDecl :: new ( ty, callsite. source_info . span ) ) ;
628+
629+ caller_body[ callsite. block ] . statements . push ( Statement {
637630 source_info : callsite. source_info ,
638- kind : StatementKind :: Assign ( box ( Place :: from ( arg_tmp ) , arg ) ) ,
631+ kind : StatementKind :: StorageLive ( local ) ,
639632 } ) ;
640- caller_body[ return_block] . statements . insert (
641- 0 ,
642- Statement {
643- source_info : callsite. source_info ,
644- kind : StatementKind :: StorageDead ( arg_tmp) ,
645- } ,
646- ) ;
647-
648- arg_tmp
633+
634+ if let Some ( block) = callsite. target {
635+ caller_body[ block] . statements . insert (
636+ 0 ,
637+ Statement {
638+ source_info : callsite. source_info ,
639+ kind : StatementKind :: StorageDead ( local) ,
640+ } ,
641+ ) ;
642+ }
643+
644+ local
649645 }
650646}
651647
@@ -670,7 +666,7 @@ struct Integrator<'a, 'tcx> {
670666 new_scopes : RangeFrom < SourceScope > ,
671667 new_blocks : RangeFrom < BasicBlock > ,
672668 destination : Place < ' tcx > ,
673- return_block : BasicBlock ,
669+ return_block : Option < BasicBlock > ,
674670 cleanup_block : Option < BasicBlock > ,
675671 in_cleanup_block : bool ,
676672 tcx : TyCtxt < ' tcx > ,
@@ -810,7 +806,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
810806 }
811807 }
812808 TerminatorKind :: Return => {
813- terminator. kind = TerminatorKind :: Goto { target : self . return_block } ;
809+ terminator. kind = if let Some ( tgt) = self . return_block {
810+ TerminatorKind :: Goto { target : tgt }
811+ } else {
812+ TerminatorKind :: Unreachable
813+ }
814814 }
815815 TerminatorKind :: Resume => {
816816 if let Some ( tgt) = self . cleanup_block {
0 commit comments