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