@@ -28,7 +28,8 @@ pub struct Inline;
28
28
#[ derive( Copy , Clone , Debug ) ]
29
29
struct CallSite < ' tcx > {
30
30
callee : Instance < ' tcx > ,
31
- bb : BasicBlock ,
31
+ block : BasicBlock ,
32
+ target : Option < BasicBlock > ,
32
33
source_info : SourceInfo ,
33
34
}
34
35
@@ -172,8 +173,7 @@ impl Inliner<'tcx> {
172
173
173
174
// Only consider direct calls to functions
174
175
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 {
177
177
if let ty:: FnDef ( callee_def_id, substs) = * op. ty ( caller_body, self . tcx ) . kind ( ) {
178
178
// To resolve an instance its substs have to be fully normalized, so
179
179
// we do this here.
@@ -187,7 +187,12 @@ impl Inliner<'tcx> {
187
187
return None ;
188
188
}
189
189
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
+ } ) ;
191
196
}
192
197
}
193
198
@@ -399,9 +404,9 @@ impl Inliner<'tcx> {
399
404
caller_body : & mut Body < ' tcx > ,
400
405
mut callee_body : Body < ' tcx > ,
401
406
) {
402
- let terminator = caller_body[ callsite. bb ] . terminator . take ( ) . unwrap ( ) ;
407
+ let terminator = caller_body[ callsite. block ] . terminator . take ( ) . unwrap ( ) ;
403
408
match terminator. kind {
404
- TerminatorKind :: Call { args, destination : Some ( destination ) , cleanup, .. } => {
409
+ TerminatorKind :: Call { args, destination, cleanup, .. } => {
405
410
// If the call is something like `a[*i] = f(i)`, where
406
411
// `i : &mut usize`, then just duplicating the `a[*i]`
407
412
// Place could result in two different locations if `f`
@@ -418,43 +423,39 @@ impl Inliner<'tcx> {
418
423
false
419
424
}
420
425
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
+ }
442
444
} 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 ( ) ) )
444
447
} ;
445
448
446
- let return_block = destination. 1 ;
447
-
448
449
// 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) ;
450
451
451
452
let mut integrator = Integrator {
452
453
args : & args,
453
454
new_locals : Local :: new ( caller_body. local_decls . len ( ) ) ..,
454
455
new_scopes : SourceScope :: new ( caller_body. source_scopes . len ( ) ) ..,
455
456
new_blocks : BasicBlock :: new ( caller_body. basic_blocks ( ) . len ( ) ) ..,
456
457
destination : dest,
457
- return_block,
458
+ return_block : callsite . target ,
458
459
cleanup_block : cleanup,
459
460
in_cleanup_block : false ,
460
461
tcx : self . tcx ,
@@ -503,7 +504,7 @@ impl Inliner<'tcx> {
503
504
caller_body. var_debug_info . extend ( callee_body. var_debug_info . drain ( ..) ) ;
504
505
caller_body. basic_blocks_mut ( ) . extend ( callee_body. basic_blocks_mut ( ) . drain ( ..) ) ;
505
506
506
- caller_body[ callsite. bb ] . terminator = Some ( Terminator {
507
+ caller_body[ callsite. block ] . terminator = Some ( Terminator {
507
508
source_info : callsite. source_info ,
508
509
kind : TerminatorKind :: Goto { target : integrator. map_block ( START_BLOCK ) } ,
509
510
} ) ;
@@ -527,7 +528,6 @@ impl Inliner<'tcx> {
527
528
args : Vec < Operand < ' tcx > > ,
528
529
callsite : & CallSite < ' tcx > ,
529
530
caller_body : & mut Body < ' tcx > ,
530
- return_block : BasicBlock ,
531
531
) -> Vec < Local > {
532
532
let tcx = self . tcx ;
533
533
@@ -558,18 +558,8 @@ impl Inliner<'tcx> {
558
558
// `callee_body.spread_arg == None`, instead of special-casing closures.
559
559
if tcx. is_closure ( callsite. callee . def_id ( ) ) {
560
560
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) ;
573
563
assert ! ( args. next( ) . is_none( ) ) ;
574
564
575
565
let tuple = Place :: from ( tuple) ;
@@ -589,13 +579,13 @@ impl Inliner<'tcx> {
589
579
Operand :: Move ( tcx. mk_place_field ( tuple, Field :: new ( i) , ty. expect_ty ( ) ) ) ;
590
580
591
581
// 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)
593
583
} ) ;
594
584
595
585
closure_ref_arg. chain ( tuple_tmp_args) . collect ( )
596
586
} else {
597
587
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) )
599
589
. collect ( )
600
590
}
601
591
}
@@ -607,46 +597,52 @@ impl Inliner<'tcx> {
607
597
arg : Operand < ' tcx > ,
608
598
callsite : & CallSite < ' tcx > ,
609
599
caller_body : & mut Body < ' tcx > ,
610
- return_block : BasicBlock ,
611
600
) -> 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.
615
602
if let Operand :: Move ( place) = & arg {
616
603
if let Some ( local) = place. as_local ( ) {
617
604
if caller_body. local_kind ( local) == LocalKind :: Temp {
618
- // Reuse the operand if it's a temporary already
619
605
return local;
620
606
}
621
607
}
622
608
}
623
609
610
+ // Otherwise, create a temporary for the argument.
624
611
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 {
634
615
source_info : callsite. source_info ,
635
- kind : StatementKind :: StorageLive ( arg_tmp ) ,
616
+ kind : StatementKind :: Assign ( box ( Place :: from ( local ) , Rvalue :: Use ( arg ) ) ) ,
636
617
} ) ;
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 {
638
631
source_info : callsite. source_info ,
639
- kind : StatementKind :: Assign ( box ( Place :: from ( arg_tmp ) , arg ) ) ,
632
+ kind : StatementKind :: StorageLive ( local ) ,
640
633
} ) ;
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
650
646
}
651
647
}
652
648
@@ -671,7 +667,7 @@ struct Integrator<'a, 'tcx> {
671
667
new_scopes : RangeFrom < SourceScope > ,
672
668
new_blocks : RangeFrom < BasicBlock > ,
673
669
destination : Place < ' tcx > ,
674
- return_block : BasicBlock ,
670
+ return_block : Option < BasicBlock > ,
675
671
cleanup_block : Option < BasicBlock > ,
676
672
in_cleanup_block : bool ,
677
673
tcx : TyCtxt < ' tcx > ,
@@ -817,7 +813,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
817
813
}
818
814
}
819
815
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
+ }
821
821
}
822
822
TerminatorKind :: Resume => {
823
823
if let Some ( tgt) = self . cleanup_block {
0 commit comments