Skip to content

Commit 21e1e12

Browse files
committed
Auto merge of rust-lang#126578 - scottmcm:inlining-bonuses-too, r=<try>
Account for things that optimize out in inlining costs r? ghost
2 parents 1138036 + c586408 commit 21e1e12

File tree

2 files changed

+63
-24
lines changed

2 files changed

+63
-24
lines changed

compiler/rustc_mir_transform/src/cost_checker.rs

+59-22
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ const INSTR_COST: usize = 5;
66
const CALL_PENALTY: usize = 25;
77
const LANDINGPAD_PENALTY: usize = 50;
88
const RESUME_PENALTY: usize = 45;
9+
const LARGE_SWITCH_PENALTY: usize = 20;
10+
const CONST_SWITCH_BONUS: usize = 30;
911

1012
/// Verify that the callee body is compatible with the caller.
1113
#[derive(Clone)]
1214
pub(crate) struct CostChecker<'b, 'tcx> {
1315
tcx: TyCtxt<'tcx>,
1416
param_env: ParamEnv<'tcx>,
15-
cost: usize,
17+
penalty: usize,
18+
bonus: usize,
1619
callee_body: &'b Body<'tcx>,
1720
instance: Option<ty::Instance<'tcx>>,
1821
}
@@ -24,11 +27,11 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> {
2427
instance: Option<ty::Instance<'tcx>>,
2528
callee_body: &'b Body<'tcx>,
2629
) -> CostChecker<'b, 'tcx> {
27-
CostChecker { tcx, param_env, callee_body, instance, cost: 0 }
30+
CostChecker { tcx, param_env, callee_body, instance, penalty: 0, bonus: 0 }
2831
}
2932

3033
pub fn cost(&self) -> usize {
31-
self.cost
34+
usize::saturating_sub(self.penalty, self.bonus)
3235
}
3336

3437
fn instantiate_ty(&self, v: Ty<'tcx>) -> Ty<'tcx> {
@@ -41,14 +44,31 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> {
4144
}
4245

4346
impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
44-
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
45-
// 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.
4649
match statement.kind {
47-
StatementKind::StorageLive(_)
48-
| StatementKind::StorageDead(_)
49-
| StatementKind::Deinit(_)
50-
| StatementKind::Nop => {}
51-
_ => self.cost += INSTR_COST,
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(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) {
61+
match rvalue {
62+
Rvalue::NullaryOp(NullOp::UbChecks, ..) if !self.tcx.sess.ub_checks() => {
63+
// If this is in optimized MIR it's because it's used later,
64+
// so if we don't need UB checks this session, give a bonus
65+
// here to offset the cost of the call later.
66+
self.bonus += CALL_PENALTY;
67+
}
68+
// These are essentially constants that didn't end up in an Operand,
69+
// so treat them as also being free.
70+
Rvalue::NullaryOp(..) => {}
71+
_ => self.penalty += INSTR_COST,
5272
}
5373
}
5474

@@ -59,17 +79,17 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
5979
// If the place doesn't actually need dropping, treat it like a regular goto.
6080
let ty = self.instantiate_ty(place.ty(self.callee_body, tcx).ty);
6181
if ty.needs_drop(tcx, self.param_env) {
62-
self.cost += CALL_PENALTY;
82+
self.penalty += CALL_PENALTY;
6383
if let UnwindAction::Cleanup(_) = unwind {
64-
self.cost += LANDINGPAD_PENALTY;
84+
self.penalty += LANDINGPAD_PENALTY;
6585
}
6686
} else {
67-
self.cost += INSTR_COST;
87+
self.penalty += INSTR_COST;
6888
}
6989
}
7090
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
7191
let fn_ty = self.instantiate_ty(f.const_.ty());
72-
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind()
92+
self.penalty += if let ty::FnDef(def_id, _) = *fn_ty.kind()
7393
&& tcx.intrinsic(def_id).is_some()
7494
{
7595
// Don't give intrinsics the extra penalty for calls
@@ -78,23 +98,40 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
7898
CALL_PENALTY
7999
};
80100
if let UnwindAction::Cleanup(_) = unwind {
81-
self.cost += LANDINGPAD_PENALTY;
101+
self.penalty += LANDINGPAD_PENALTY;
102+
}
103+
}
104+
TerminatorKind::SwitchInt { ref discr, ref targets } => {
105+
if discr.constant().is_some() {
106+
// Not only will this become a `Goto`, but likely other
107+
// things will be removable as unreachable.
108+
self.bonus += CONST_SWITCH_BONUS;
109+
} else if targets.all_targets().len() > 3 {
110+
// More than false/true/unreachable gets extra cost.
111+
self.penalty += LARGE_SWITCH_PENALTY;
112+
} else {
113+
self.penalty += INSTR_COST;
82114
}
83115
}
84-
TerminatorKind::Assert { unwind, .. } => {
85-
self.cost += CALL_PENALTY;
116+
TerminatorKind::Assert { unwind, ref msg, .. } => {
117+
self.penalty +=
118+
if msg.is_optional_overflow_check() && !self.tcx.sess.overflow_checks() {
119+
INSTR_COST
120+
} else {
121+
CALL_PENALTY
122+
};
86123
if let UnwindAction::Cleanup(_) = unwind {
87-
self.cost += LANDINGPAD_PENALTY;
124+
self.penalty += LANDINGPAD_PENALTY;
88125
}
89126
}
90-
TerminatorKind::UnwindResume => self.cost += RESUME_PENALTY,
127+
TerminatorKind::UnwindResume => self.penalty += RESUME_PENALTY,
91128
TerminatorKind::InlineAsm { unwind, .. } => {
92-
self.cost += INSTR_COST;
129+
self.penalty += INSTR_COST;
93130
if let UnwindAction::Cleanup(_) = unwind {
94-
self.cost += LANDINGPAD_PENALTY;
131+
self.penalty += LANDINGPAD_PENALTY;
95132
}
96133
}
97-
_ => self.cost += INSTR_COST,
134+
_ => self.penalty += INSTR_COST,
98135
}
99136
}
100137
}

library/core/src/slice/iter/macros.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ macro_rules! iterator {
103103
// so this new pointer is inside `self` and thus guaranteed to be non-null.
104104
unsafe {
105105
if_zst!(mut self,
106-
len => *len = len.unchecked_sub(offset),
106+
// Using the intrinsic directly avoids emitting a UbCheck
107+
len => *len = crate::intrinsics::unchecked_sub(*len, offset),
107108
_end => self.ptr = self.ptr.add(offset),
108109
);
109110
}
@@ -119,7 +120,8 @@ macro_rules! iterator {
119120
// SAFETY: By our precondition, `offset` can be at most the
120121
// current length, so the subtraction can never overflow.
121122
len => unsafe {
122-
*len = len.unchecked_sub(offset);
123+
// Using the intrinsic directly avoids emitting a UbCheck
124+
*len = crate::intrinsics::unchecked_sub(*len, offset);
123125
self.ptr
124126
},
125127
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,

0 commit comments

Comments
 (0)