Skip to content

Commit 8b15741

Browse files
committed
Extract cost checker from inliner.
1 parent f31316f commit 8b15741

File tree

3 files changed

+98
-88
lines changed

3 files changed

+98
-88
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use rustc_middle::mir::visit::*;
2+
use rustc_middle::mir::*;
3+
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
4+
5+
const INSTR_COST: usize = 5;
6+
const CALL_PENALTY: usize = 25;
7+
const LANDINGPAD_PENALTY: usize = 50;
8+
const RESUME_PENALTY: usize = 45;
9+
10+
/// Verify that the callee body is compatible with the caller.
11+
#[derive(Clone)]
12+
pub(crate) struct CostChecker<'b, 'tcx> {
13+
tcx: TyCtxt<'tcx>,
14+
param_env: ParamEnv<'tcx>,
15+
cost: usize,
16+
callee_body: &'b Body<'tcx>,
17+
instance: ty::Instance<'tcx>,
18+
}
19+
20+
impl<'b, 'tcx> CostChecker<'b, 'tcx> {
21+
pub fn new(
22+
tcx: TyCtxt<'tcx>,
23+
param_env: ParamEnv<'tcx>,
24+
instance: ty::Instance<'tcx>,
25+
callee_body: &'b Body<'tcx>,
26+
) -> CostChecker<'b, 'tcx> {
27+
CostChecker { tcx, param_env, callee_body, instance, cost: 0 }
28+
}
29+
30+
pub fn cost(&self) -> usize {
31+
self.cost
32+
}
33+
}
34+
35+
impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
36+
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
37+
// Don't count StorageLive/StorageDead in the inlining cost.
38+
match statement.kind {
39+
StatementKind::StorageLive(_)
40+
| StatementKind::StorageDead(_)
41+
| StatementKind::Deinit(_)
42+
| StatementKind::Nop => {}
43+
_ => self.cost += INSTR_COST,
44+
}
45+
}
46+
47+
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) {
48+
let tcx = self.tcx;
49+
match terminator.kind {
50+
TerminatorKind::Drop { ref place, unwind, .. } => {
51+
// If the place doesn't actually need dropping, treat it like a regular goto.
52+
let ty = self.instance.instantiate_mir(
53+
tcx,
54+
ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty),
55+
);
56+
if ty.needs_drop(tcx, self.param_env) {
57+
self.cost += CALL_PENALTY;
58+
if let UnwindAction::Cleanup(_) = unwind {
59+
self.cost += LANDINGPAD_PENALTY;
60+
}
61+
} else {
62+
self.cost += INSTR_COST;
63+
}
64+
}
65+
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
66+
let fn_ty =
67+
self.instance.instantiate_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty()));
68+
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
69+
// Don't give intrinsics the extra penalty for calls
70+
INSTR_COST
71+
} else {
72+
CALL_PENALTY
73+
};
74+
if let UnwindAction::Cleanup(_) = unwind {
75+
self.cost += LANDINGPAD_PENALTY;
76+
}
77+
}
78+
TerminatorKind::Assert { unwind, .. } => {
79+
self.cost += CALL_PENALTY;
80+
if let UnwindAction::Cleanup(_) = unwind {
81+
self.cost += LANDINGPAD_PENALTY;
82+
}
83+
}
84+
TerminatorKind::UnwindResume => self.cost += RESUME_PENALTY,
85+
TerminatorKind::InlineAsm { unwind, .. } => {
86+
self.cost += INSTR_COST;
87+
if let UnwindAction::Cleanup(_) = unwind {
88+
self.cost += LANDINGPAD_PENALTY;
89+
}
90+
}
91+
_ => self.cost += INSTR_COST,
92+
}
93+
}
94+
}

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 3 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_session::config::OptLevel;
1414
use rustc_target::abi::FieldIdx;
1515
use rustc_target::spec::abi::Abi;
1616

17+
use crate::cost_checker::CostChecker;
1718
use crate::simplify::{remove_dead_blocks, CfgSimplifier};
1819
use crate::util;
1920
use crate::MirPass;
@@ -22,11 +23,6 @@ use std::ops::{Range, RangeFrom};
2223

2324
pub(crate) mod cycle;
2425

25-
const INSTR_COST: usize = 5;
26-
const CALL_PENALTY: usize = 25;
27-
const LANDINGPAD_PENALTY: usize = 50;
28-
const RESUME_PENALTY: usize = 45;
29-
3026
const TOP_DOWN_DEPTH_LIMIT: usize = 5;
3127

3228
pub struct Inline;
@@ -479,13 +475,7 @@ impl<'tcx> Inliner<'tcx> {
479475

480476
// FIXME: Give a bonus to functions with only a single caller
481477

482-
let mut checker = CostChecker {
483-
tcx: self.tcx,
484-
param_env: self.param_env,
485-
instance: callsite.callee,
486-
callee_body,
487-
cost: 0,
488-
};
478+
let mut checker = CostChecker::new(self.tcx, self.param_env, callsite.callee, callee_body);
489479

490480
// Traverse the MIR manually so we can account for the effects of inlining on the CFG.
491481
let mut work_list = vec![START_BLOCK];
@@ -530,7 +520,7 @@ impl<'tcx> Inliner<'tcx> {
530520
// That attribute is often applied to very large functions that exceed LLVM's (very
531521
// generous) inlining threshold. Such functions are very poor MIR inlining candidates.
532522
// Always inlining #[inline(always)] functions in MIR, on net, slows down the compiler.
533-
let cost = checker.cost;
523+
let cost = checker.cost();
534524
if cost <= threshold {
535525
debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold);
536526
Ok(())
@@ -803,81 +793,6 @@ impl<'tcx> Inliner<'tcx> {
803793
}
804794
}
805795

806-
/// Verify that the callee body is compatible with the caller.
807-
///
808-
/// This visitor mostly computes the inlining cost,
809-
/// but also needs to verify that types match because of normalization failure.
810-
struct CostChecker<'b, 'tcx> {
811-
tcx: TyCtxt<'tcx>,
812-
param_env: ParamEnv<'tcx>,
813-
cost: usize,
814-
callee_body: &'b Body<'tcx>,
815-
instance: ty::Instance<'tcx>,
816-
}
817-
818-
impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
819-
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
820-
// Don't count StorageLive/StorageDead in the inlining cost.
821-
match statement.kind {
822-
StatementKind::StorageLive(_)
823-
| StatementKind::StorageDead(_)
824-
| StatementKind::Deinit(_)
825-
| StatementKind::Nop => {}
826-
_ => self.cost += INSTR_COST,
827-
}
828-
}
829-
830-
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) {
831-
let tcx = self.tcx;
832-
match terminator.kind {
833-
TerminatorKind::Drop { ref place, unwind, .. } => {
834-
// If the place doesn't actually need dropping, treat it like a regular goto.
835-
let ty = self.instance.instantiate_mir(
836-
tcx,
837-
ty::EarlyBinder::bind(&place.ty(self.callee_body, tcx).ty),
838-
);
839-
if ty.needs_drop(tcx, self.param_env) {
840-
self.cost += CALL_PENALTY;
841-
if let UnwindAction::Cleanup(_) = unwind {
842-
self.cost += LANDINGPAD_PENALTY;
843-
}
844-
} else {
845-
self.cost += INSTR_COST;
846-
}
847-
}
848-
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
849-
let fn_ty =
850-
self.instance.instantiate_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty()));
851-
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind()
852-
&& tcx.is_intrinsic(def_id)
853-
{
854-
// Don't give intrinsics the extra penalty for calls
855-
INSTR_COST
856-
} else {
857-
CALL_PENALTY
858-
};
859-
if let UnwindAction::Cleanup(_) = unwind {
860-
self.cost += LANDINGPAD_PENALTY;
861-
}
862-
}
863-
TerminatorKind::Assert { unwind, .. } => {
864-
self.cost += CALL_PENALTY;
865-
if let UnwindAction::Cleanup(_) = unwind {
866-
self.cost += LANDINGPAD_PENALTY;
867-
}
868-
}
869-
TerminatorKind::UnwindResume => self.cost += RESUME_PENALTY,
870-
TerminatorKind::InlineAsm { unwind, .. } => {
871-
self.cost += INSTR_COST;
872-
if let UnwindAction::Cleanup(_) = unwind {
873-
self.cost += LANDINGPAD_PENALTY;
874-
}
875-
}
876-
_ => self.cost += INSTR_COST,
877-
}
878-
}
879-
}
880-
881796
/**
882797
* Integrator.
883798
*

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ mod const_goto;
6161
mod const_prop;
6262
mod const_prop_lint;
6363
mod copy_prop;
64+
mod cost_checker;
6465
mod coverage;
6566
mod cross_crate_inline;
6667
mod ctfe_limit;

0 commit comments

Comments
 (0)