@@ -6,6 +6,8 @@ const INSTR_COST: usize = 5;
6
6
const CALL_PENALTY : usize = 25 ;
7
7
const LANDINGPAD_PENALTY : usize = 50 ;
8
8
const RESUME_PENALTY : usize = 45 ;
9
+ const LARGE_SWITCH_PENALTY : usize = 20 ;
10
+ const CONST_SWITCH_BONUS : usize = 30 ;
9
11
10
12
/// Verify that the callee body is compatible with the caller.
11
13
#[ derive( Clone ) ]
@@ -42,13 +44,34 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> {
42
44
}
43
45
44
46
impl < ' tcx > Visitor < ' tcx > for CostChecker < ' _ , ' tcx > {
45
- fn visit_statement ( & mut self , statement : & Statement < ' tcx > , _ : Location ) {
46
- // Don't count StorageLive/StorageDead in the inlining cost .
47
+ fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
48
+ // Most costs are in rvalues and terminators, not in statements .
47
49
match statement. kind {
48
- StatementKind :: StorageLive ( _)
49
- | StatementKind :: StorageDead ( _)
50
- | StatementKind :: Deinit ( _)
51
- | StatementKind :: Nop => { }
50
+ StatementKind :: Intrinsic ( ref ndi) => {
51
+ self . penalty += match * * ndi {
52
+ NonDivergingIntrinsic :: Assume ( ..) => INSTR_COST ,
53
+ NonDivergingIntrinsic :: CopyNonOverlapping ( ..) => CALL_PENALTY ,
54
+ } ;
55
+ }
56
+ _ => self . super_statement ( statement, location) ,
57
+ }
58
+ }
59
+
60
+ fn visit_rvalue (
61
+ & mut self ,
62
+ rvalue : & Rvalue < ' tcx > ,
63
+ _location : Location ,
64
+ ) {
65
+ match rvalue {
66
+ Rvalue :: NullaryOp ( NullOp :: UbChecks , ..) if !self . tcx . sess . ub_checks ( ) => {
67
+ // If this is in optimized MIR it's because it's used later,
68
+ // so if we don't need UB checks this session, give a bonus
69
+ // here to offset the cost of the call later.
70
+ self . bonus += CALL_PENALTY ;
71
+ }
72
+ // These are essentially constants that didn't end up in an Operand,
73
+ // so treat them as also being free.
74
+ Rvalue :: NullaryOp ( ..) => { }
52
75
_ => self . penalty += INSTR_COST ,
53
76
}
54
77
}
@@ -82,8 +105,25 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
82
105
self . penalty += LANDINGPAD_PENALTY ;
83
106
}
84
107
}
85
- TerminatorKind :: Assert { unwind, .. } => {
86
- self . penalty += CALL_PENALTY ;
108
+ TerminatorKind :: SwitchInt { ref discr, ref targets } => {
109
+ if discr. constant ( ) . is_some ( ) {
110
+ // Not only will this become a `Goto`, but likely other
111
+ // things will be removable as unreachable.
112
+ self . bonus += CONST_SWITCH_BONUS ;
113
+ } else if targets. all_targets ( ) . len ( ) > 3 {
114
+ // More than false/true/unreachable gets extra cost.
115
+ self . penalty += LARGE_SWITCH_PENALTY ;
116
+ } else {
117
+ self . penalty += INSTR_COST ;
118
+ }
119
+ }
120
+ TerminatorKind :: Assert { unwind, ref msg, .. } => {
121
+ self . penalty +=
122
+ if msg. is_optional_overflow_check ( ) && !self . tcx . sess . overflow_checks ( ) {
123
+ INSTR_COST
124
+ } else {
125
+ CALL_PENALTY
126
+ } ;
87
127
if let UnwindAction :: Cleanup ( _) = unwind {
88
128
self . penalty += LANDINGPAD_PENALTY ;
89
129
}
0 commit comments