Skip to content

Commit 9d6086f

Browse files
committed
wip
1 parent 4911572 commit 9d6086f

File tree

16 files changed

+242
-32
lines changed

16 files changed

+242
-32
lines changed

src/bootstrap/builder.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,9 @@ impl<'a> Builder<'a> {
10981098
}
10991099

11001100
if let Mode::Rustc | Mode::Codegen = mode {
1101+
if stage > 0 {
1102+
rustflags.arg("-Zcross-crate-inline-threshold=50");
1103+
}
11011104
rustflags.arg("-Zunstable-options");
11021105
rustflags.arg("-Wrustc::internal");
11031106
}

src/librustc/middle/codegen_fn_attrs.rs

-8
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,6 @@ impl CodegenFnAttrs {
9595
}
9696
}
9797

98-
/// Returns `true` if `#[inline]` or `#[inline(always)]` is present.
99-
pub fn requests_inline(&self) -> bool {
100-
match self.inline {
101-
InlineAttr::Hint | InlineAttr::Always => true,
102-
InlineAttr::None | InlineAttr::Never => false,
103-
}
104-
}
105-
10698
/// Returns `true` if it looks like this symbol needs to be exported, for example:
10799
///
108100
/// * `#[no_mangle]` is present

src/librustc/mir/mono.rs

+12
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ impl<'tcx> MonoItem<'tcx> {
9090

9191
match *self {
9292
MonoItem::Fn(ref instance) => {
93+
/*use rustc_hir::ItemKind;
94+
use rustc_hir::Node;
95+
tcx.hir().as_local_hir_id(instance.def_id()).map(|id| match tcx.hir().get(id) {
96+
Node::Item(item) => match item.kind {
97+
ItemKind::Static(..) | ItemKind::Const(..) => {
98+
panic!("STATIC!! {:?}", self);
99+
}
100+
_ => (),
101+
},
102+
_ => (),
103+
});*/
104+
93105
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
94106
// If this function isn't inlined or otherwise has explicit
95107
// linkage, then we'll be creating a globally shared version.

src/librustc/query/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,8 @@ rustc_queries! {
649649
query codegen_fn_attrs(_: DefId) -> CodegenFnAttrs {
650650
cache_on_disk_if { true }
651651
}
652+
653+
query cross_crate_inlinable(_: DefId) -> bool {}
652654
}
653655

654656
Other {

src/librustc/ty/instance.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,13 @@ impl<'tcx> InstanceDef<'tcx> {
204204
// drops of `Option::None` before LTO. We also respect the intent of
205205
// `#[inline]` on `Drop::drop` implementations.
206206
return ty.ty_adt_def().map_or(true, |adt_def| {
207-
adt_def.destructor(tcx).map_or(adt_def.is_enum(), |dtor| {
208-
tcx.codegen_fn_attrs(dtor.did).requests_inline()
209-
})
207+
adt_def
208+
.destructor(tcx)
209+
.map_or(adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did))
210210
});
211211
}
212-
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
212+
213+
tcx.cross_crate_inlinable(self.def_id())
213214
}
214215

215216
pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {

src/librustc_codegen_ssa/back/symbol_export.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ fn reachable_non_generics_provider(
8585
}
8686

8787
// Only consider nodes that actually have exported symbols.
88-
Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })
89-
| Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
88+
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
9089
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
9190
let def_id = tcx.hir().local_def_id(hir_id);
9291
let generics = tcx.generics_of(def_id);
@@ -101,6 +100,15 @@ fn reachable_non_generics_provider(
101100
}
102101
}
103102

103+
Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. }) => {
104+
let def_id = tcx.hir().local_def_id(hir_id);
105+
let generics = tcx.generics_of(def_id);
106+
let r =
107+
if !generics.requires_monomorphization(tcx) { Some(def_id) } else { None };
108+
//assert!(r.is_some());
109+
r
110+
}
111+
104112
_ => None,
105113
}
106114
})

src/librustc_metadata/rmeta/decoder.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
10991099
!self.is_proc_macro(id) && self.root.per_def.mir.get(self, id).is_some()
11001100
}
11011101

1102+
fn is_item_cross_crate_inlinable(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> bool {
1103+
self.root
1104+
.per_def
1105+
.cross_crate_inlinable
1106+
.get(self, id)
1107+
.map(|v| v.decode((self, tcx)))
1108+
.unwrap_or(false)
1109+
}
1110+
11021111
fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyAndCache<'tcx> {
11031112
let mut cache = self
11041113
.root

src/librustc_metadata/rmeta/decoder/cstore_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
149149
impl_parent => { cdata.get_parent_impl(def_id.index) }
150150
trait_of_item => { cdata.get_trait_of_item(def_id.index) }
151151
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
152+
cross_crate_inlinable => { cdata.is_item_cross_crate_inlinable(tcx, def_id.index) }
152153

153154
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
154155
is_panic_runtime => { cdata.root.panic_runtime }

src/librustc_metadata/rmeta/encoder.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,9 @@ impl EncodeContext<'tcx> {
882882
ty::AssocKind::OpaqueTy => unreachable!(),
883883
}
884884
if trait_item.kind == ty::AssocKind::Method {
885+
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
886+
record!(self.per_def.cross_crate_inlinable[def_id] <- self.tcx.cross_crate_inlinable(def_id));
887+
}
885888
record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
886889
self.encode_variances_of(def_id);
887890
}
@@ -968,9 +971,11 @@ impl EncodeContext<'tcx> {
968971
let mir = match ast_item.kind {
969972
hir::ImplItemKind::Const(..) => true,
970973
hir::ImplItemKind::Fn(ref sig, _) => {
974+
record!(self.per_def.cross_crate_inlinable[def_id] <- self.tcx.cross_crate_inlinable(def_id));
975+
971976
let generics = self.tcx.generics_of(def_id);
972977
let needs_inline = (generics.requires_monomorphization(self.tcx)
973-
|| tcx.codegen_fn_attrs(def_id).requests_inline())
978+
|| tcx.cross_crate_inlinable(def_id))
974979
&& !self.metadata_output_only();
975980
let is_const_fn = sig.header.constness == hir::Constness::Const;
976981
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
@@ -1266,9 +1271,11 @@ impl EncodeContext<'tcx> {
12661271
let mir = match item.kind {
12671272
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
12681273
hir::ItemKind::Fn(ref sig, ..) => {
1274+
record!(self.per_def.cross_crate_inlinable[def_id] <- self.tcx.cross_crate_inlinable(def_id));
1275+
12691276
let generics = tcx.generics_of(def_id);
12701277
let needs_inline = (generics.requires_monomorphization(tcx)
1271-
|| tcx.codegen_fn_attrs(def_id).requests_inline())
1278+
|| tcx.cross_crate_inlinable(def_id))
12721279
&& !self.metadata_output_only();
12731280
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
12741281
needs_inline || sig.header.constness == hir::Constness::Const || always_encode_mir
@@ -1743,8 +1750,8 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
17431750
hir::ItemKind::Fn(ref sig, ..) => {
17441751
let def_id = tcx.hir().local_def_id(item.hir_id);
17451752
let generics = tcx.generics_of(def_id);
1746-
let needs_inline = generics.requires_monomorphization(tcx)
1747-
|| tcx.codegen_fn_attrs(def_id).requests_inline();
1753+
let needs_inline =
1754+
generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id);
17481755
if needs_inline || sig.header.constness == hir::Constness::Const {
17491756
self.prefetch_mir(def_id)
17501757
}
@@ -1768,8 +1775,8 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
17681775
hir::ImplItemKind::Fn(ref sig, _) => {
17691776
let def_id = tcx.hir().local_def_id(impl_item.hir_id);
17701777
let generics = tcx.generics_of(def_id);
1771-
let needs_inline = generics.requires_monomorphization(tcx)
1772-
|| tcx.codegen_fn_attrs(def_id).requests_inline();
1778+
let needs_inline =
1779+
generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id);
17731780
let is_const_fn = sig.header.constness == hir::Constness::Const;
17741781
if needs_inline || is_const_fn {
17751782
self.prefetch_mir(def_id)

src/librustc_metadata/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ define_per_def_tables! {
276276
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
277277
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
278278
mir: Table<DefIndex, Lazy!(mir::BodyAndCache<'tcx>)>,
279+
cross_crate_inlinable: Table<DefIndex, Lazy<bool>>,
279280
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>>)>,
280281
}
281282

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2+
use rustc::mir::{Body, TerminatorKind};
3+
use rustc::ty::query::Providers;
4+
use rustc::ty::TyCtxt;
5+
use rustc_attr::InlineAttr;
6+
use rustc_hir::def_id::DefId;
7+
//use rustc_hir::ItemKind;
8+
//use rustc_session::config::OptLevel;
9+
use rustc_session::config::Sanitizer;
10+
11+
pub fn provide(providers: &mut Providers<'_>) {
12+
providers.cross_crate_inlinable = cross_crate_inlinable;
13+
}
14+
15+
fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
16+
/*use rustc_hir::Node;
17+
tcx.hir().as_local_hir_id(def_id).map(|id| match tcx.hir().get(id) {
18+
Node::Item(item) => match item.kind {
19+
ItemKind::Static(..) | ItemKind::Const(..) => {
20+
panic!("STATIC!! {:?}", def_id);
21+
}
22+
_ => (),
23+
},
24+
_ => (),
25+
});*/
26+
27+
let attrs = tcx.codegen_fn_attrs(def_id);
28+
29+
match attrs.inline {
30+
InlineAttr::Hint | InlineAttr::Always => return true,
31+
InlineAttr::Never => return false,
32+
InlineAttr::None => (),
33+
}
34+
35+
if attrs.contains_extern_indicator() {
36+
return false;
37+
}
38+
39+
if tcx.lang_items().start_fn() == Some(def_id) {
40+
return false;
41+
}
42+
43+
// FIXME: Share some of this logic with the MIR inlining pass
44+
45+
// FIXME: Is this needed?
46+
if attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) {
47+
return false;
48+
}
49+
50+
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
51+
// since instrumentation might be enabled and performed on the caller.
52+
match tcx.sess.opts.debugging_opts.sanitizer {
53+
Some(Sanitizer::Address) => {
54+
if attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
55+
return false;
56+
}
57+
}
58+
Some(Sanitizer::Memory) => {
59+
if attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
60+
return false;
61+
}
62+
}
63+
Some(Sanitizer::Thread) => {
64+
if attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
65+
return false;
66+
}
67+
}
68+
Some(Sanitizer::Leak) => {}
69+
None => {}
70+
}
71+
72+
if tcx.sess.opts.debugging_opts.cross_crate_inline_threshold.is_none() {
73+
return false;
74+
}
75+
/*
76+
if tcx.sess.opts.optimize != OptLevel::Aggressive {
77+
return false;
78+
}
79+
*/
80+
let r = allow_cross_inline(tcx, def_id, &tcx.optimized_mir(def_id).unwrap_read_only());
81+
/*if r {
82+
eprintln!("cross_crate_inlinable({:?})", def_id);
83+
}*/
84+
r
85+
}
86+
87+
const THRESHOLD: usize = 30;
88+
89+
const INSTR_COST: usize = 2;
90+
const CALL_PENALTY: usize = 10;
91+
const LANDINGPAD_PENALTY: usize = 5;
92+
const RESUME_PENALTY: usize = 5;
93+
94+
const UNKNOWN_SIZE_COST: usize = 2;
95+
96+
fn allow_cross_inline<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> bool {
97+
// Generators should have been transformed here.
98+
debug_assert!(body.yield_ty.is_none());
99+
100+
let mut threshold =
101+
tcx.sess.opts.debugging_opts.cross_crate_inline_threshold.unwrap_or(THRESHOLD);
102+
103+
// Give a bonus functions with a small number of blocks,
104+
// We normally have two or three blocks for even
105+
// very small functions.
106+
if body.basic_blocks().len() <= 3 {
107+
threshold += threshold / 4;
108+
}
109+
110+
let mut cost = 0;
111+
112+
for block in body.basic_blocks() {
113+
cost += block.statements.len();
114+
115+
match block.terminator().kind {
116+
TerminatorKind::Drop { unwind, .. } | TerminatorKind::DropAndReplace { unwind, .. } => {
117+
cost += CALL_PENALTY;
118+
if unwind.is_some() {
119+
cost += LANDINGPAD_PENALTY;
120+
}
121+
}
122+
TerminatorKind::Call { cleanup, .. } => {
123+
cost += CALL_PENALTY;
124+
if cleanup.is_some() {
125+
cost += LANDINGPAD_PENALTY;
126+
}
127+
}
128+
TerminatorKind::Assert { cleanup, .. } => {
129+
cost += CALL_PENALTY;
130+
131+
if cleanup.is_some() {
132+
cost += LANDINGPAD_PENALTY;
133+
}
134+
}
135+
TerminatorKind::Resume => cost += RESUME_PENALTY,
136+
_ => cost += INSTR_COST,
137+
}
138+
}
139+
140+
// Count up the cost of local variables and temps, if we know the size
141+
// use that, otherwise we use a moderately-large dummy cost.
142+
143+
let ptr_size = tcx.data_layout.pointer_size.bytes();
144+
145+
let param_env = tcx.param_env(def_id);
146+
147+
for v in body.vars_and_temps_iter() {
148+
let v = &body.local_decls[v];
149+
// Cost of the var is the size in machine-words, if we know
150+
// it.
151+
if let Some(size) =
152+
tcx.layout_of(param_env.and(v.ty)).ok().map(|layout| layout.size.bytes())
153+
{
154+
cost += (size / ptr_size) as usize;
155+
} else {
156+
cost += UNKNOWN_SIZE_COST;
157+
}
158+
}
159+
160+
cost <= threshold
161+
}

src/librustc_mir/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern crate rustc;
3434

3535
mod borrow_check;
3636
pub mod const_eval;
37+
mod cross_crate_inline;
3738
pub mod dataflow;
3839
pub mod interpret;
3940
pub mod monomorphize;
@@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers<'_>) {
4748
borrow_check::provide(providers);
4849
const_eval::provide(providers);
4950
shim::provide(providers);
51+
cross_crate_inline::provide(providers);
5052
transform::provide(providers);
5153
monomorphize::partitioning::provide(providers);
5254
providers.const_eval_validated = const_eval::const_eval_validated_provider;

0 commit comments

Comments
 (0)