@@ -28,7 +28,8 @@ pub struct Inline;
2828#[ derive( Copy , Clone , Debug ) ]
2929struct CallSite < ' tcx > {
3030 callee : Instance < ' tcx > ,
31- bb : BasicBlock ,
31+ block : BasicBlock ,
32+ target : Option < BasicBlock > ,
3233 source_info : SourceInfo ,
3334}
3435
@@ -172,8 +173,7 @@ impl Inliner<'tcx> {
172173
173174 // Only consider direct calls to functions
174175 let terminator = bb_data. terminator ( ) ;
175- // FIXME: Handle inlining of diverging calls
176- if let TerminatorKind :: Call { func : ref op, destination : Some ( _) , .. } = terminator. kind {
176+ if let TerminatorKind :: Call { func : ref op, ref destination, .. } = terminator. kind {
177177 if let ty:: FnDef ( callee_def_id, substs) = * op. ty ( caller_body, self . tcx ) . kind ( ) {
178178 // To resolve an instance its substs have to be fully normalized, so
179179 // we do this here.
@@ -187,7 +187,12 @@ impl Inliner<'tcx> {
187187 return None ;
188188 }
189189
190- return Some ( CallSite { callee, bb, source_info : terminator. source_info } ) ;
190+ return Some ( CallSite {
191+ callee,
192+ block : bb,
193+ target : destination. map ( |( _, target) | target) ,
194+ source_info : terminator. source_info ,
195+ } ) ;
191196 }
192197 }
193198
@@ -399,9 +404,9 @@ impl Inliner<'tcx> {
399404 caller_body : & mut Body < ' tcx > ,
400405 mut callee_body : Body < ' tcx > ,
401406 ) {
402- let terminator = caller_body[ callsite. bb ] . terminator . take ( ) . unwrap ( ) ;
407+ let terminator = caller_body[ callsite. block ] . terminator . take ( ) . unwrap ( ) ;
403408 match terminator. kind {
404- TerminatorKind :: Call { args, destination : Some ( destination ) , cleanup, .. } => {
409+ TerminatorKind :: Call { args, destination, cleanup, .. } => {
405410 // If the call is something like `a[*i] = f(i)`, where
406411 // `i : &mut usize`, then just duplicating the `a[*i]`
407412 // Place could result in two different locations if `f`
@@ -418,43 +423,39 @@ impl Inliner<'tcx> {
418423 false
419424 }
420425
421- let dest = if dest_needs_borrow ( destination. 0 ) {
422- trace ! ( "creating temp for return destination" ) ;
423- let dest = Rvalue :: Ref (
424- self . tcx . lifetimes . re_erased ,
425- BorrowKind :: Mut { allow_two_phase_borrow : false } ,
426- destination. 0 ,
427- ) ;
428-
429- let ty = dest. ty ( caller_body, self . tcx ) ;
430-
431- let temp = LocalDecl :: new ( ty, callsite. source_info . span ) ;
432-
433- let tmp = caller_body. local_decls . push ( temp) ;
434- let tmp = Place :: from ( tmp) ;
435-
436- let stmt = Statement {
437- source_info : callsite. source_info ,
438- kind : StatementKind :: Assign ( box ( tmp, dest) ) ,
439- } ;
440- caller_body[ callsite. bb ] . statements . push ( stmt) ;
441- self . tcx . mk_place_deref ( tmp)
426+ let dest = if let Some ( ( destination_place, _) ) = destination {
427+ if dest_needs_borrow ( destination_place) {
428+ trace ! ( "creating temp for return destination" ) ;
429+ let dest = Rvalue :: Ref (
430+ self . tcx . lifetimes . re_erased ,
431+ BorrowKind :: Mut { allow_two_phase_borrow : false } ,
432+ destination_place,
433+ ) ;
434+ let dest_ty = dest. ty ( caller_body, self . tcx ) ;
435+ let temp = Place :: from ( self . new_call_temp ( caller_body, & callsite, dest_ty) ) ;
436+ caller_body[ callsite. block ] . statements . push ( Statement {
437+ source_info : callsite. source_info ,
438+ kind : StatementKind :: Assign ( box ( temp, dest) ) ,
439+ } ) ;
440+ self . tcx . mk_place_deref ( temp)
441+ } else {
442+ destination_place
443+ }
442444 } else {
443- destination. 0
445+ trace ! ( "creating temp for return place" ) ;
446+ Place :: from ( self . new_call_temp ( caller_body, & callsite, callee_body. return_ty ( ) ) )
444447 } ;
445448
446- let return_block = destination. 1 ;
447-
448449 // Copy the arguments if needed.
449- let args: Vec < _ > = self . make_call_args ( args, & callsite, caller_body, return_block ) ;
450+ let args: Vec < _ > = self . make_call_args ( args, & callsite, caller_body) ;
450451
451452 let mut integrator = Integrator {
452453 args : & args,
453454 new_locals : Local :: new ( caller_body. local_decls . len ( ) ) ..,
454455 new_scopes : SourceScope :: new ( caller_body. source_scopes . len ( ) ) ..,
455456 new_blocks : BasicBlock :: new ( caller_body. basic_blocks ( ) . len ( ) ) ..,
456457 destination : dest,
457- return_block,
458+ return_block : callsite . target ,
458459 cleanup_block : cleanup,
459460 in_cleanup_block : false ,
460461 tcx : self . tcx ,
@@ -503,7 +504,7 @@ impl Inliner<'tcx> {
503504 caller_body. var_debug_info . extend ( callee_body. var_debug_info . drain ( ..) ) ;
504505 caller_body. basic_blocks_mut ( ) . extend ( callee_body. basic_blocks_mut ( ) . drain ( ..) ) ;
505506
506- caller_body[ callsite. bb ] . terminator = Some ( Terminator {
507+ caller_body[ callsite. block ] . terminator = Some ( Terminator {
507508 source_info : callsite. source_info ,
508509 kind : TerminatorKind :: Goto { target : integrator. map_block ( START_BLOCK ) } ,
509510 } ) ;
@@ -527,7 +528,6 @@ impl Inliner<'tcx> {
527528 args : Vec < Operand < ' tcx > > ,
528529 callsite : & CallSite < ' tcx > ,
529530 caller_body : & mut Body < ' tcx > ,
530- return_block : BasicBlock ,
531531 ) -> Vec < Local > {
532532 let tcx = self . tcx ;
533533
@@ -558,18 +558,8 @@ impl Inliner<'tcx> {
558558 // `callee_body.spread_arg == None`, instead of special-casing closures.
559559 if tcx. is_closure ( callsite. callee . def_id ( ) ) {
560560 let mut args = args. into_iter ( ) ;
561- let self_ = self . create_temp_if_necessary (
562- args. next ( ) . unwrap ( ) ,
563- callsite,
564- caller_body,
565- return_block,
566- ) ;
567- let tuple = self . create_temp_if_necessary (
568- args. next ( ) . unwrap ( ) ,
569- callsite,
570- caller_body,
571- return_block,
572- ) ;
561+ let self_ = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_body) ;
562+ let tuple = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_body) ;
573563 assert ! ( args. next( ) . is_none( ) ) ;
574564
575565 let tuple = Place :: from ( tuple) ;
@@ -589,13 +579,13 @@ impl Inliner<'tcx> {
589579 Operand :: Move ( tcx. mk_place_field ( tuple, Field :: new ( i) , ty. expect_ty ( ) ) ) ;
590580
591581 // Spill to a local to make e.g., `tmp0`.
592- self . create_temp_if_necessary ( tuple_field, callsite, caller_body, return_block )
582+ self . create_temp_if_necessary ( tuple_field, callsite, caller_body)
593583 } ) ;
594584
595585 closure_ref_arg. chain ( tuple_tmp_args) . collect ( )
596586 } else {
597587 args. into_iter ( )
598- . map ( |a| self . create_temp_if_necessary ( a, callsite, caller_body, return_block ) )
588+ . map ( |a| self . create_temp_if_necessary ( a, callsite, caller_body) )
599589 . collect ( )
600590 }
601591 }
@@ -607,46 +597,52 @@ impl Inliner<'tcx> {
607597 arg : Operand < ' tcx > ,
608598 callsite : & CallSite < ' tcx > ,
609599 caller_body : & mut Body < ' tcx > ,
610- return_block : BasicBlock ,
611600 ) -> Local {
612- // FIXME: Analysis of the usage of the arguments to avoid
613- // unnecessary temporaries.
614-
601+ // Reuse the operand if it is a moved temporary.
615602 if let Operand :: Move ( place) = & arg {
616603 if let Some ( local) = place. as_local ( ) {
617604 if caller_body. local_kind ( local) == LocalKind :: Temp {
618- // Reuse the operand if it's a temporary already
619605 return local;
620606 }
621607 }
622608 }
623609
610+ // Otherwise, create a temporary for the argument.
624611 trace ! ( "creating temp for argument {:?}" , arg) ;
625- // Otherwise, create a temporary for the arg
626- let arg = Rvalue :: Use ( arg) ;
627-
628- let ty = arg. ty ( caller_body, self . tcx ) ;
629-
630- let arg_tmp = LocalDecl :: new ( ty, callsite. source_info . span ) ;
631- let arg_tmp = caller_body. local_decls . push ( arg_tmp) ;
632-
633- caller_body[ callsite. bb ] . statements . push ( Statement {
612+ let arg_ty = arg. ty ( caller_body, self . tcx ) ;
613+ let local = self . new_call_temp ( caller_body, callsite, arg_ty) ;
614+ caller_body[ callsite. block ] . statements . push ( Statement {
634615 source_info : callsite. source_info ,
635- kind : StatementKind :: StorageLive ( arg_tmp ) ,
616+ kind : StatementKind :: Assign ( box ( Place :: from ( local ) , Rvalue :: Use ( arg ) ) ) ,
636617 } ) ;
637- caller_body[ callsite. bb ] . statements . push ( Statement {
618+ local
619+ }
620+
621+ /// Introduces a new temporary into the caller body that is live for the duration of the call.
622+ fn new_call_temp (
623+ & self ,
624+ caller_body : & mut Body < ' tcx > ,
625+ callsite : & CallSite < ' tcx > ,
626+ ty : Ty < ' tcx > ,
627+ ) -> Local {
628+ let local = caller_body. local_decls . push ( LocalDecl :: new ( ty, callsite. source_info . span ) ) ;
629+
630+ caller_body[ callsite. block ] . statements . push ( Statement {
638631 source_info : callsite. source_info ,
639- kind : StatementKind :: Assign ( box ( Place :: from ( arg_tmp ) , arg ) ) ,
632+ kind : StatementKind :: StorageLive ( local ) ,
640633 } ) ;
641- caller_body[ return_block] . statements . insert (
642- 0 ,
643- Statement {
644- source_info : callsite. source_info ,
645- kind : StatementKind :: StorageDead ( arg_tmp) ,
646- } ,
647- ) ;
648-
649- arg_tmp
634+
635+ if let Some ( block) = callsite. target {
636+ caller_body[ block] . statements . insert (
637+ 0 ,
638+ Statement {
639+ source_info : callsite. source_info ,
640+ kind : StatementKind :: StorageDead ( local) ,
641+ } ,
642+ ) ;
643+ }
644+
645+ local
650646 }
651647}
652648
@@ -671,7 +667,7 @@ struct Integrator<'a, 'tcx> {
671667 new_scopes : RangeFrom < SourceScope > ,
672668 new_blocks : RangeFrom < BasicBlock > ,
673669 destination : Place < ' tcx > ,
674- return_block : BasicBlock ,
670+ return_block : Option < BasicBlock > ,
675671 cleanup_block : Option < BasicBlock > ,
676672 in_cleanup_block : bool ,
677673 tcx : TyCtxt < ' tcx > ,
@@ -817,7 +813,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
817813 }
818814 }
819815 TerminatorKind :: Return => {
820- terminator. kind = TerminatorKind :: Goto { target : self . return_block } ;
816+ terminator. kind = if let Some ( tgt) = self . return_block {
817+ TerminatorKind :: Goto { target : tgt }
818+ } else {
819+ TerminatorKind :: Unreachable
820+ }
821821 }
822822 TerminatorKind :: Resume => {
823823 if let Some ( tgt) = self . cleanup_block {
0 commit comments