@@ -16,9 +16,6 @@ use crate::transform::MirPass;
1616use  std:: iter; 
1717use  std:: ops:: { Range ,  RangeFrom } ; 
1818
19- const  DEFAULT_THRESHOLD :  usize  = 50 ; 
20- const  HINT_THRESHOLD :  usize  = 100 ; 
21- 
2219const  INSTR_COST :  usize  = 5 ; 
2320const  CALL_PENALTY :  usize  = 25 ; 
2421const  LANDINGPAD_PENALTY :  usize  = 50 ; 
@@ -31,7 +28,8 @@ pub struct Inline;
3128#[ derive( Copy ,  Clone ,  Debug ) ]  
3229struct  CallSite < ' tcx >  { 
3330    callee :  Instance < ' tcx > , 
34-     bb :  BasicBlock , 
31+     block :  BasicBlock , 
32+     target :  Option < BasicBlock > , 
3533    source_info :  SourceInfo , 
3634} 
3735
@@ -175,8 +173,7 @@ impl Inliner<'tcx> {
175173
176174        // Only consider direct calls to functions 
177175        let  terminator = bb_data. terminator ( ) ; 
178-         // FIXME: Handle inlining of diverging calls 
179-         if  let  TerminatorKind :: Call  {  func :  ref  op,  destination :  Some ( _) ,  .. }  = terminator. kind  { 
176+         if  let  TerminatorKind :: Call  {  func :  ref  op,  ref  destination,  .. }  = terminator. kind  { 
180177            if  let  ty:: FnDef ( callee_def_id,  substs)  = * op. ty ( caller_body,  self . tcx ) . kind ( )  { 
181178                // To resolve an instance its substs have to be fully normalized, so 
182179                // we do this here. 
@@ -190,7 +187,12 @@ impl Inliner<'tcx> {
190187                    return  None ; 
191188                } 
192189
193-                 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+                 } ) ; 
194196            } 
195197        } 
196198
@@ -248,7 +250,11 @@ impl Inliner<'tcx> {
248250            } 
249251        } 
250252
251-         let  mut  threshold = if  hinted {  HINT_THRESHOLD  }  else  {  DEFAULT_THRESHOLD  } ; 
253+         let  mut  threshold = if  hinted { 
254+             self . tcx . sess . opts . debugging_opts . inline_mir_hint_threshold 
255+         }  else  { 
256+             self . tcx . sess . opts . debugging_opts . inline_mir_threshold 
257+         } ; 
252258
253259        // Significantly lower the threshold for inlining cold functions 
254260        if  codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: COLD )  { 
@@ -398,9 +404,9 @@ impl Inliner<'tcx> {
398404        caller_body :  & mut  Body < ' tcx > , 
399405        mut  callee_body :  Body < ' tcx > , 
400406    )  { 
401-         let  terminator = caller_body[ callsite. bb ] . terminator . take ( ) . unwrap ( ) ; 
407+         let  terminator = caller_body[ callsite. block ] . terminator . take ( ) . unwrap ( ) ; 
402408        match  terminator. kind  { 
403-             TerminatorKind :: Call  {  args,  destination :   Some ( destination ) ,  cleanup,  .. }  => { 
409+             TerminatorKind :: Call  {  args,  destination,  cleanup,  .. }  => { 
404410                // If the call is something like `a[*i] = f(i)`, where 
405411                // `i : &mut usize`, then just duplicating the `a[*i]` 
406412                // Place could result in two different locations if `f` 
@@ -417,43 +423,39 @@ impl Inliner<'tcx> {
417423                    false 
418424                } 
419425
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) 
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+                     } 
441444                }  else  { 
442-                     destination. 0 
445+                     trace ! ( "creating temp for return place" ) ; 
446+                     Place :: from ( self . new_call_temp ( caller_body,  & callsite,  callee_body. return_ty ( ) ) ) 
443447                } ; 
444448
445-                 let  return_block = destination. 1 ; 
446- 
447449                // Copy the arguments if needed. 
448-                 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) ; 
449451
450452                let  mut  integrator = Integrator  { 
451453                    args :  & args, 
452454                    new_locals :  Local :: new ( caller_body. local_decls . len ( ) ) .., 
453455                    new_scopes :  SourceScope :: new ( caller_body. source_scopes . len ( ) ) .., 
454456                    new_blocks :  BasicBlock :: new ( caller_body. basic_blocks ( ) . len ( ) ) .., 
455457                    destination :  dest, 
456-                     return_block, 
458+                     return_block :  callsite . target , 
457459                    cleanup_block :  cleanup, 
458460                    in_cleanup_block :  false , 
459461                    tcx :  self . tcx , 
@@ -502,7 +504,7 @@ impl Inliner<'tcx> {
502504                caller_body. var_debug_info . extend ( callee_body. var_debug_info . drain ( ..) ) ; 
503505                caller_body. basic_blocks_mut ( ) . extend ( callee_body. basic_blocks_mut ( ) . drain ( ..) ) ; 
504506
505-                 caller_body[ callsite. bb ] . terminator  = Some ( Terminator  { 
507+                 caller_body[ callsite. block ] . terminator  = Some ( Terminator  { 
506508                    source_info :  callsite. source_info , 
507509                    kind :  TerminatorKind :: Goto  {  target :  integrator. map_block ( START_BLOCK )  } , 
508510                } ) ; 
@@ -526,7 +528,6 @@ impl Inliner<'tcx> {
526528        args :  Vec < Operand < ' tcx > > , 
527529        callsite :  & CallSite < ' tcx > , 
528530        caller_body :  & mut  Body < ' tcx > , 
529-         return_block :  BasicBlock , 
530531    )  -> Vec < Local >  { 
531532        let  tcx = self . tcx ; 
532533
@@ -557,18 +558,8 @@ impl Inliner<'tcx> {
557558        // `callee_body.spread_arg == None`, instead of special-casing closures. 
558559        if  tcx. is_closure ( callsite. callee . def_id ( ) )  { 
559560            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-             ) ; 
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) ; 
572563            assert ! ( args. next( ) . is_none( ) ) ; 
573564
574565            let  tuple = Place :: from ( tuple) ; 
@@ -588,13 +579,13 @@ impl Inliner<'tcx> {
588579                    Operand :: Move ( tcx. mk_place_field ( tuple,  Field :: new ( i) ,  ty. expect_ty ( ) ) ) ; 
589580
590581                // Spill to a local to make e.g., `tmp0`. 
591-                 self . create_temp_if_necessary ( tuple_field,  callsite,  caller_body,  return_block ) 
582+                 self . create_temp_if_necessary ( tuple_field,  callsite,  caller_body) 
592583            } ) ; 
593584
594585            closure_ref_arg. chain ( tuple_tmp_args) . collect ( ) 
595586        }  else  { 
596587            args. into_iter ( ) 
597-                 . 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) ) 
598589                . collect ( ) 
599590        } 
600591    } 
@@ -606,46 +597,52 @@ impl Inliner<'tcx> {
606597        arg :  Operand < ' tcx > , 
607598        callsite :  & CallSite < ' tcx > , 
608599        caller_body :  & mut  Body < ' tcx > , 
609-         return_block :  BasicBlock , 
610600    )  -> Local  { 
611-         // FIXME: Analysis of the usage of the arguments to avoid 
612-         // unnecessary temporaries. 
613- 
601+         // Reuse the operand if it is a moved temporary. 
614602        if  let  Operand :: Move ( place)  = & arg { 
615603            if  let  Some ( local)  = place. as_local ( )  { 
616604                if  caller_body. local_kind ( local)  == LocalKind :: Temp  { 
617-                     // Reuse the operand if it's a temporary already 
618605                    return  local; 
619606                } 
620607            } 
621608        } 
622609
610+         // Otherwise, create a temporary for the argument. 
623611        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  { 
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  { 
633615            source_info :  callsite. source_info , 
634-             kind :  StatementKind :: StorageLive ( arg_tmp ) , 
616+             kind :  StatementKind :: Assign ( box   ( Place :: from ( local ) ,   Rvalue :: Use ( arg ) ) ) , 
635617        } ) ; 
636-         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  { 
637631            source_info :  callsite. source_info , 
638-             kind :  StatementKind :: Assign ( box   ( Place :: from ( arg_tmp ) ,  arg ) ) , 
632+             kind :  StatementKind :: StorageLive ( local ) , 
639633        } ) ; 
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
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
649646    } 
650647} 
651648
@@ -670,7 +667,7 @@ struct Integrator<'a, 'tcx> {
670667    new_scopes :  RangeFrom < SourceScope > , 
671668    new_blocks :  RangeFrom < BasicBlock > , 
672669    destination :  Place < ' tcx > , 
673-     return_block :  BasicBlock , 
670+     return_block :  Option < BasicBlock > , 
674671    cleanup_block :  Option < BasicBlock > , 
675672    in_cleanup_block :  bool , 
676673    tcx :  TyCtxt < ' tcx > , 
@@ -816,7 +813,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
816813                } 
817814            } 
818815            TerminatorKind :: Return  => { 
819-                 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+                 } 
820821            } 
821822            TerminatorKind :: Resume  => { 
822823                if  let  Some ( tgt)  = self . cleanup_block  { 
0 commit comments