@@ -28,7 +28,11 @@ use rustc::ty::{self, Ty, TyCtxt};
28
28
use rustc:: ty:: subst:: { Subst , Substs } ;
29
29
use rustc:: util:: nodemap:: { DefIdMap , DefIdSet } ;
30
30
31
+ use super :: simplify_cfg:: { remove_dead_blocks, CfgSimplifier } ;
32
+ use super :: copy_prop:: CopyPropagation ;
33
+
31
34
use syntax:: attr;
35
+ use syntax:: abi:: Abi ;
32
36
use syntax_pos:: Span ;
33
37
34
38
use callgraph;
@@ -50,7 +54,7 @@ impl<'tcx> MirMapPass<'tcx> for Inline {
50
54
& mut self ,
51
55
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
52
56
map : & mut MirMap < ' tcx > ,
53
- _ : & mut [ Box <for <' s > MirPassHook < ' s > >] ) {
57
+ hooks : & mut [ Box <for <' s > MirPassHook < ' s > >] ) {
54
58
55
59
match tcx. sess . opts . debugging_opts . mir_opt_level {
56
60
Some ( 0 ) |
@@ -68,10 +72,32 @@ impl<'tcx> MirMapPass<'tcx> for Inline {
68
72
foreign_mirs : DefIdMap ( )
69
73
} ;
70
74
75
+ let def_ids = map. map . keys ( ) ;
76
+ for & def_id in & def_ids {
77
+ let _task = tcx. dep_graph . in_task ( DepNode :: Mir ( def_id) ) ;
78
+ let mir = map. map . get_mut ( & def_id) . unwrap ( ) ;
79
+ let id = tcx. map . as_local_node_id ( def_id) . unwrap ( ) ;
80
+ let src = MirSource :: from_node ( tcx, id) ;
81
+
82
+ for hook in & mut * hooks {
83
+ hook. on_mir_pass ( tcx, src, mir, self , false ) ;
84
+ }
85
+ }
86
+
71
87
for scc in callgraph. scc_iter ( ) {
72
- debug ! ( "Inlining SCC {:?}" , scc) ;
73
88
inliner. inline_scc ( map, & callgraph, & scc) ;
74
89
}
90
+
91
+ for def_id in def_ids {
92
+ let _task = tcx. dep_graph . in_task ( DepNode :: Mir ( def_id) ) ;
93
+ let mir = map. map . get_mut ( & def_id) . unwrap ( ) ;
94
+ let id = tcx. map . as_local_node_id ( def_id) . unwrap ( ) ;
95
+ let src = MirSource :: from_node ( tcx, id) ;
96
+
97
+ for hook in & mut * hooks {
98
+ hook. on_mir_pass ( tcx, src, mir, self , true ) ;
99
+ }
100
+ }
75
101
}
76
102
}
77
103
@@ -97,6 +123,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
97
123
let mut callsites = Vec :: new ( ) ;
98
124
let mut in_scc = DefIdSet ( ) ;
99
125
126
+ let mut inlined_into = DefIdSet ( ) ;
127
+
100
128
for & node in scc {
101
129
let def_id = callgraph. def_id ( node) ;
102
130
@@ -190,6 +218,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
190
218
continue ;
191
219
}
192
220
221
+ inlined_into. insert ( callsite. caller ) ;
222
+
193
223
// Add callsites from inlined function
194
224
for ( bb, bb_data) in caller_mir. basic_blocks ( ) . iter_enumerated ( ) . skip ( start) {
195
225
// Only consider direct calls to functions
@@ -228,6 +258,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
228
258
}
229
259
}
230
260
261
+ // Simplify functions we inlined into.
262
+ for def_id in inlined_into {
263
+ let caller_mir = map. map . get_mut ( & def_id) . unwrap ( ) ;
264
+ debug ! ( "Running simplify cfg on {:?}" , def_id) ;
265
+ CfgSimplifier :: new ( caller_mir) . simplify ( ) ;
266
+ remove_dead_blocks ( caller_mir) ;
267
+ }
231
268
changed
232
269
}
233
270
@@ -266,7 +303,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
266
303
267
304
let hinted = match hint {
268
305
// Just treat inline(always) as a hint for now,
269
- // there are cases that prevent unwinding that we
306
+ // there are cases that prevent inlining that we
270
307
// need to check for first.
271
308
attr:: InlineAttr :: Always => true ,
272
309
attr:: InlineAttr :: Never => return false ,
@@ -318,31 +355,24 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
318
355
// Don't count StorageLive/StorageDead in the inlining cost.
319
356
match stmt. kind {
320
357
StatementKind :: StorageLive ( _) |
321
- StatementKind :: StorageDead ( _) => { }
358
+ StatementKind :: StorageDead ( _) |
359
+ StatementKind :: Nop => { }
322
360
_ => cost += INSTR_COST
323
361
}
324
362
}
325
363
match blk. terminator ( ) . kind {
326
- TerminatorKind :: Drop { ref location, unwind , .. } |
327
- TerminatorKind :: DropAndReplace { ref location, unwind , .. } => {
364
+ TerminatorKind :: Drop { ref location, .. } |
365
+ TerminatorKind :: DropAndReplace { ref location, .. } => {
328
366
// If the location doesn't actually need dropping, treat it like
329
367
// a regular goto.
330
368
let ty = location. ty ( & callee_mir, tcx) . subst ( tcx, callsite. substs ) ;
331
369
let ty = ty. to_ty ( tcx) ;
332
370
if tcx. type_needs_drop_given_env ( ty, & param_env) {
333
- if unwind. is_some ( ) {
334
- // FIXME: Should be able to handle this better
335
- return false ;
336
- } else {
337
- cost += CALL_PENALTY ;
338
- }
371
+ cost += CALL_PENALTY ;
339
372
} else {
340
373
cost += INSTR_COST ;
341
374
}
342
375
}
343
- // FIXME: Should be able to handle this better
344
- TerminatorKind :: Call { cleanup : Some ( _) , .. } |
345
- TerminatorKind :: Assert { cleanup : Some ( _) , .. } => return false ,
346
376
347
377
TerminatorKind :: Unreachable |
348
378
TerminatorKind :: Call { destination : None , .. } if first_block => {
@@ -351,7 +381,16 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
351
381
threshold = 0 ;
352
382
}
353
383
354
- TerminatorKind :: Call { .. } |
384
+ TerminatorKind :: Call { func : Operand :: Constant ( ref f) , .. } => {
385
+ if let ty:: TyFnDef ( .., f) = f. ty . sty {
386
+ // Don't give intrinsics the extra penalty for calls
387
+ if f. abi == Abi :: RustIntrinsic || f. abi == Abi :: PlatformIntrinsic {
388
+ cost += INSTR_COST ;
389
+ } else {
390
+ cost += CALL_PENALTY ;
391
+ }
392
+ }
393
+ }
355
394
TerminatorKind :: Assert { .. } => cost += CALL_PENALTY ,
356
395
_ => cost += INSTR_COST
357
396
}
@@ -405,8 +444,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
405
444
406
445
let terminator = caller_mir[ callsite. bb ] . terminator . take ( ) . unwrap ( ) ;
407
446
match terminator. kind {
408
- TerminatorKind :: Call {
409
- func : _, args, destination : Some ( destination) , cleanup } => {
447
+ TerminatorKind :: Call { args, destination : Some ( destination) , cleanup, .. } => {
410
448
411
449
debug ! ( "Inlined {:?} into {:?}" , callsite. callee, callsite. caller) ;
412
450
@@ -532,7 +570,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
532
570
inline_location : callsite. location ,
533
571
destination : dest,
534
572
return_block : return_block,
535
- cleanup_block : cleanup
573
+ cleanup_block : cleanup,
574
+ in_cleanup_block : false
536
575
} ;
537
576
538
577
@@ -548,6 +587,12 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
548
587
549
588
caller_mir[ callsite. bb ] . terminator = Some ( terminator) ;
550
589
590
+ // Run copy propagation on the function to clean up any unnecessary
591
+ // assignments from integration. This also increases the chance that
592
+ // this function will be inlined as well
593
+ debug ! ( "Running copy propagation" ) ;
594
+ CopyPropagation . propagate_copies ( caller_mir) ;
595
+
551
596
true
552
597
}
553
598
kind => {
@@ -580,7 +625,8 @@ struct Integrator<'a, 'tcx: 'a> {
580
625
inline_location : SourceInfo ,
581
626
destination : Lvalue < ' tcx > ,
582
627
return_block : BasicBlock ,
583
- cleanup_block : Option < BasicBlock >
628
+ cleanup_block : Option < BasicBlock > ,
629
+ in_cleanup_block : bool ,
584
630
}
585
631
586
632
impl < ' a , ' tcx > Integrator < ' a , ' tcx > {
@@ -594,29 +640,25 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
594
640
impl < ' a , ' tcx > MutVisitor < ' tcx > for Integrator < ' a , ' tcx > {
595
641
fn visit_lvalue ( & mut self ,
596
642
lvalue : & mut Lvalue < ' tcx > ,
597
- _ctxt : LvalueContext ,
643
+ _ctxt : LvalueContext < ' tcx > ,
598
644
_location : Location ) {
599
645
match * lvalue {
600
646
Lvalue :: Var ( ref mut var) => {
601
647
if let Some ( v) = self . var_map . get ( * var) . cloned ( ) {
602
- debug ! ( "Replacing {:?} with {:?}" , var, v) ;
603
648
* var = v;
604
649
}
605
650
}
606
651
Lvalue :: Temp ( ref mut tmp) => {
607
652
if let Some ( t) = self . tmp_map . get ( * tmp) . cloned ( ) {
608
- debug ! ( "Replacing {:?} with {:?}" , tmp, t) ;
609
653
* tmp = t;
610
654
}
611
655
}
612
656
Lvalue :: ReturnPointer => {
613
- debug ! ( "Replacing return pointer with {:?}" , self . destination) ;
614
657
* lvalue = self . destination . clone ( ) ;
615
658
}
616
659
Lvalue :: Arg ( arg) => {
617
660
let idx = arg. index ( ) ;
618
661
if let Operand :: Consume ( ref lval) = self . args [ idx] {
619
- debug ! ( "Replacing {:?} with {:?}" , lvalue, lval) ;
620
662
* lvalue = lval. clone ( ) ;
621
663
}
622
664
}
@@ -628,13 +670,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
628
670
if let Operand :: Consume ( Lvalue :: Arg ( arg) ) = * operand {
629
671
let idx = arg. index ( ) ;
630
672
let new_arg = self . args [ idx] . clone ( ) ;
631
- debug ! ( "Replacing use of {:?} with {:?}" , arg, new_arg) ;
632
673
* operand = new_arg;
633
674
} else {
634
675
self . super_operand ( operand, location) ;
635
676
}
636
677
}
637
678
679
+ fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
680
+ self . in_cleanup_block = data. is_cleanup ;
681
+ self . super_basic_block_data ( block, data) ;
682
+ self . in_cleanup_block = false ;
683
+ }
684
+
638
685
fn visit_terminator_kind ( & mut self , block : BasicBlock ,
639
686
kind : & mut TerminatorKind < ' tcx > , loc : Location ) {
640
687
match * kind {
@@ -656,44 +703,32 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
656
703
* target = self . update_target ( * target) ;
657
704
if let Some ( tgt) = * unwind {
658
705
* unwind = Some ( self . update_target ( tgt) ) ;
659
- } else {
660
- if Some ( * target) != self . cleanup_block {
661
- * unwind = self . cleanup_block ;
662
- }
663
- }
664
-
665
- if Some ( * target) == * unwind {
666
- * unwind == None ;
706
+ } else if !self . in_cleanup_block {
707
+ // Unless this drop is in a cleanup block, add an unwind edge to
708
+ // the orignal call's cleanup block
709
+ * unwind = self . cleanup_block ;
667
710
}
668
711
}
669
712
TerminatorKind :: Call { ref mut destination, ref mut cleanup, .. } => {
670
- let mut target = None ;
671
713
if let Some ( ( _, ref mut tgt) ) = * destination {
672
714
* tgt = self . update_target ( * tgt) ;
673
- target = Some ( * tgt) ;
674
715
}
675
716
if let Some ( tgt) = * cleanup {
676
717
* cleanup = Some ( self . update_target ( tgt) ) ;
677
- } else {
718
+ } else if !self . in_cleanup_block {
719
+ // Unless this call is in a cleanup block, add an unwind edge to
720
+ // the orignal call's cleanup block
678
721
* cleanup = self . cleanup_block ;
679
722
}
680
-
681
- if target == * cleanup {
682
- * cleanup == None ;
683
- }
684
723
}
685
724
TerminatorKind :: Assert { ref mut target, ref mut cleanup, .. } => {
686
725
* target = self . update_target ( * target) ;
687
726
if let Some ( tgt) = * cleanup {
688
727
* cleanup = Some ( self . update_target ( tgt) ) ;
689
- } else {
690
- if Some ( * target) != self . cleanup_block {
691
- * cleanup = self . cleanup_block ;
692
- }
693
- }
694
-
695
- if Some ( * target) == * cleanup {
696
- * cleanup == None ;
728
+ } else if !self . in_cleanup_block {
729
+ // Unless this assert is in a cleanup block, add an unwind edge to
730
+ // the orignal call's cleanup block
731
+ * cleanup = self . cleanup_block ;
697
732
}
698
733
}
699
734
TerminatorKind :: Return => {
0 commit comments