Skip to content

Commit ef04fc8

Browse files
committed
Auto merge of #38944 - michaelwoerister:incr-generics-partitioning, r=nikomatsakis
trans: Treat generics like regular functions, not like #[inline] function, during CGU partitioning This PR makes generics be treated just like regular functions during CGU partitioning: + the function instantiation is placed in a codegen unit based on the function's DefPath, + unless it is marked with `#[inline]` -- which causes a private copy of the function to be placed in every referencing codegen unit. This has the following effects: + Multi codegen unit builds will become faster because code for generic functions is duplicated less. + Multi codegen unit builds might have lower runtime performance, since generics are not available for inlining automatically any more. + Single codegen unit builds are not affected one way or the other. This partitioning scheme is particularly good for incremental compilation as it drastically reduces the number of false positives during codegen unit invalidation. I'd love to have a benchmark suite for estimating the effect on runtime performance for changes like this one. r? @nikomatsakis cc @rust-lang/compiler
2 parents b4c0207 + fc9dfca commit ef04fc8

File tree

15 files changed

+175
-187
lines changed

15 files changed

+175
-187
lines changed

src/librustc/middle/cstore.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ pub trait CrateStore<'tcx> {
211211
fn is_foreign_item(&self, did: DefId) -> bool;
212212
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
213213
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool;
214+
fn is_exported_symbol(&self, def_id: DefId) -> bool;
214215

215216
// crate metadata
216217
fn dylib_dependency_formats(&self, cnum: CrateNum)
@@ -258,11 +259,6 @@ pub trait CrateStore<'tcx> {
258259
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
259260
fn is_item_mir_available(&self, def: DefId) -> bool;
260261

261-
/// Take a look if we need to inline or monomorphize this. If so, we
262-
/// will emit code for this item in the local crate, and thus
263-
/// create a translation item for it.
264-
fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool;
265-
266262
// This is basically a 1-based range of ints, which is a little
267263
// silly - I may fix that.
268264
fn crates(&self) -> Vec<CrateNum>;
@@ -368,6 +364,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
368364
fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
369365
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
370366
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false }
367+
fn is_exported_symbol(&self, def_id: DefId) -> bool { false }
371368

372369
// crate metadata
373370
fn dylib_dependency_formats(&self, cnum: CrateNum)
@@ -436,9 +433,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
436433
fn is_item_mir_available(&self, def: DefId) -> bool {
437434
bug!("is_item_mir_available")
438435
}
439-
fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool {
440-
bug!("can_have_local_instance")
441-
}
442436

443437
// This is basically a 1-based range of ints, which is a little
444438
// silly - I may fix that.

src/librustc_metadata/creader.rs

+3
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,13 @@ impl<'a> CrateLoader<'a> {
302302
crate_root.def_path_table.decode(&metadata)
303303
});
304304

305+
let exported_symbols = crate_root.exported_symbols.decode(&metadata).collect();
306+
305307
let mut cmeta = cstore::CrateMetadata {
306308
name: name,
307309
extern_crate: Cell::new(None),
308310
def_path_table: def_path_table,
311+
exported_symbols: exported_symbols,
309312
proc_macros: crate_root.macro_derive_registrar.map(|_| {
310313
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
311314
}),

src/librustc_metadata/cstore.rs

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub struct CrateMetadata {
8080
/// compilation support.
8181
pub def_path_table: DefPathTable,
8282

83+
pub exported_symbols: FxHashSet<DefIndex>,
84+
8385
pub dep_kind: Cell<DepKind>,
8486
pub source: CrateSource,
8587

src/librustc_metadata/cstore_impl.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
226226
self.do_is_statically_included_foreign_item(def_id)
227227
}
228228

229+
fn is_exported_symbol(&self, def_id: DefId) -> bool {
230+
self.get_crate_data(def_id.krate).exported_symbols.contains(&def_id.index)
231+
}
232+
229233
fn is_dllimport_foreign_item(&self, def_id: DefId) -> bool {
230234
if def_id.krate == LOCAL_CRATE {
231235
self.dllimport_foreign_items.borrow().contains(&def_id.index)
@@ -466,11 +470,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
466470
self.get_crate_data(def.krate).is_item_mir_available(def.index)
467471
}
468472

469-
fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool {
470-
self.dep_graph.read(DepNode::MetaData(def));
471-
def.is_local() || self.get_crate_data(def.krate).can_have_local_instance(tcx, def.index)
472-
}
473-
474473
fn crates(&self) -> Vec<CrateNum>
475474
{
476475
let mut result = vec![];

src/librustc_metadata/decoder.rs

+7-33
Original file line numberDiff line numberDiff line change
@@ -445,14 +445,6 @@ impl<'tcx> EntryKind<'tcx> {
445445
EntryKind::Closure(_) => return None,
446446
})
447447
}
448-
fn is_const_fn(&self, meta: &CrateMetadata) -> bool {
449-
let constness = match *self {
450-
EntryKind::Method(data) => data.decode(meta).fn_data.constness,
451-
EntryKind::Fn(data) => data.decode(meta).constness,
452-
_ => hir::Constness::NotConst,
453-
};
454-
constness == hir::Constness::Const
455-
}
456448
}
457449

458450
impl<'a, 'tcx> CrateMetadata {
@@ -804,29 +796,6 @@ impl<'a, 'tcx> CrateMetadata {
804796
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
805797
}
806798

807-
pub fn can_have_local_instance(&self,
808-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
809-
id: DefIndex) -> bool {
810-
self.maybe_entry(id).map_or(false, |item| {
811-
let item = item.decode(self);
812-
// if we don't have a MIR, then this item was never meant to be locally instantiated
813-
// or we have a bug in the metadata serialization
814-
item.mir.is_some() && (
815-
// items with generics always can have local instances if monomorphized
816-
item.generics.map_or(false, |generics| {
817-
let generics = generics.decode((self, tcx));
818-
generics.parent_types != 0 || !generics.types.is_empty()
819-
}) ||
820-
match item.kind {
821-
EntryKind::Closure(_) => true,
822-
_ => false,
823-
} ||
824-
item.kind.is_const_fn(self) ||
825-
attr::requests_inline(&self.get_attributes(&item))
826-
)
827-
})
828-
}
829-
830799
pub fn maybe_get_item_mir(&self,
831800
tcx: TyCtxt<'a, 'tcx, 'tcx>,
832801
id: DefIndex)
@@ -1031,7 +1000,7 @@ impl<'a, 'tcx> CrateMetadata {
10311000
}
10321001

10331002
pub fn get_exported_symbols(&self) -> Vec<DefId> {
1034-
self.root.exported_symbols.decode(self).map(|index| self.local_def_id(index)).collect()
1003+
self.exported_symbols.iter().map(|&index| self.local_def_id(index)).collect()
10351004
}
10361005

10371006
pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) {
@@ -1043,7 +1012,12 @@ impl<'a, 'tcx> CrateMetadata {
10431012
}
10441013

10451014
pub fn is_const_fn(&self, id: DefIndex) -> bool {
1046-
self.entry(id).kind.is_const_fn(self)
1015+
let constness = match self.entry(id).kind {
1016+
EntryKind::Method(data) => data.decode(self).fn_data.constness,
1017+
EntryKind::Fn(data) => data.decode(self).constness,
1018+
_ => hir::Constness::NotConst,
1019+
};
1020+
constness == hir::Constness::Const
10471021
}
10481022

10491023
pub fn is_foreign_item(&self, id: DefIndex) -> bool {

src/librustc_trans/back/symbol_names.rs

+9
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,15 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
152152
assert!(!substs.has_erasable_regions());
153153
assert!(!substs.needs_subst());
154154
substs.visit_with(&mut hasher);
155+
156+
// If this is an instance of a generic function, we also hash in
157+
// the ID of the instantiating crate. This avoids symbol conflicts
158+
// in case the same instances is emitted in two crates of the same
159+
// project.
160+
if substs.types().next().is_some() {
161+
hasher.hash(scx.tcx().crate_name.as_str());
162+
hasher.hash(scx.sess().local_crate_disambiguator().as_str());
163+
}
155164
}
156165
});
157166

src/librustc_trans/collector.rs

+53-27
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ use glue::{self, DropGlueKind};
212212
use monomorphize::{self, Instance};
213213
use util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
214214

215-
use trans_item::{TransItem, DefPathBasedNames};
215+
use trans_item::{TransItem, DefPathBasedNames, InstantiationMode};
216216

217217
use std::iter;
218218

@@ -337,6 +337,10 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
337337
}
338338
TransItem::Static(node_id) => {
339339
let def_id = scx.tcx().map.local_def_id(node_id);
340+
341+
// Sanity check whether this ended up being collected accidentally
342+
debug_assert!(should_trans_locally(scx.tcx(), def_id));
343+
340344
let ty = scx.tcx().item_type(def_id);
341345
let ty = glue::get_drop_glue_type(scx, ty);
342346
neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
@@ -346,6 +350,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
346350
collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors);
347351
}
348352
TransItem::Fn(instance) => {
353+
// Sanity check whether this ended up being collected accidentally
354+
debug_assert!(should_trans_locally(scx.tcx(), instance.def));
355+
349356
// Keep track of the monomorphization recursion depth
350357
recursion_depth_reset = Some(check_recursion_limit(scx.tcx(),
351358
instance,
@@ -374,7 +381,7 @@ fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
374381
callees: &[TransItem<'tcx>],
375382
inlining_map: &mut InliningMap<'tcx>) {
376383
let is_inlining_candidate = |trans_item: &TransItem<'tcx>| {
377-
trans_item.needs_local_copy(tcx)
384+
trans_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
378385
};
379386

380387
let inlining_candidates = callees.into_iter()
@@ -490,15 +497,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
490497
.require(ExchangeMallocFnLangItem)
491498
.unwrap_or_else(|e| self.scx.sess().fatal(&e));
492499

493-
assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id));
494-
let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id);
495-
let exchange_malloc_fn_trans_item =
496-
create_fn_trans_item(self.scx,
497-
exchange_malloc_fn_def_id,
498-
empty_substs,
499-
self.param_substs);
500+
if should_trans_locally(self.scx.tcx(), exchange_malloc_fn_def_id) {
501+
let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id);
502+
let exchange_malloc_fn_trans_item =
503+
create_fn_trans_item(self.scx,
504+
exchange_malloc_fn_def_id,
505+
empty_substs,
506+
self.param_substs);
500507

501-
self.output.push(exchange_malloc_fn_trans_item);
508+
self.output.push(exchange_malloc_fn_trans_item);
509+
}
502510
}
503511
_ => { /* not interesting */ }
504512
}
@@ -609,7 +617,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
609617
match tcx.item_type(def_id).sty {
610618
ty::TyFnDef(def_id, _, f) => {
611619
// Some constructors also have type TyFnDef but they are
612-
// always instantiated inline and don't result in
620+
// always instantiated inline and don't result in a
613621
// translation item. Same for FFI functions.
614622
if let Some(hir_map::NodeForeignItem(_)) = tcx.map.get_if_local(def_id) {
615623
return false;
@@ -625,7 +633,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
625633
_ => return false
626634
}
627635

628-
can_have_local_instance(tcx, def_id)
636+
should_trans_locally(tcx, def_id)
629637
}
630638
}
631639

@@ -675,10 +683,27 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
675683
}
676684
}
677685

678-
fn can_have_local_instance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
679-
def_id: DefId)
680-
-> bool {
681-
tcx.sess.cstore.can_have_local_instance(tcx, def_id)
686+
// Returns true if we should translate an instance in the local crate.
687+
// Returns false if we can just link to the upstream crate and therefore don't
688+
// need a translation item.
689+
fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
690+
def_id: DefId)
691+
-> bool {
692+
if def_id.is_local() {
693+
true
694+
} else {
695+
if tcx.sess.cstore.is_exported_symbol(def_id) ||
696+
tcx.sess.cstore.is_foreign_item(def_id) {
697+
// We can link to the item in question, no instance needed in this
698+
// crate
699+
false
700+
} else {
701+
if !tcx.sess.cstore.is_item_mir_available(def_id) {
702+
bug!("Cannot create local trans-item for {:?}", def_id)
703+
}
704+
true
705+
}
706+
}
682707
}
683708

684709
fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
@@ -698,14 +723,15 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
698723
// Make sure the BoxFreeFn lang-item gets translated if there is a boxed value.
699724
if let ty::TyBox(content_type) = ty.sty {
700725
let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem);
701-
assert!(can_have_local_instance(scx.tcx(), def_id));
702-
let box_free_fn_trans_item =
703-
create_fn_trans_item(scx,
704-
def_id,
705-
scx.tcx().mk_substs(iter::once(Kind::from(content_type))),
706-
scx.tcx().intern_substs(&[]));
707-
708-
output.push(box_free_fn_trans_item);
726+
727+
if should_trans_locally(scx.tcx(), def_id) {
728+
let box_free_fn_trans_item =
729+
create_fn_trans_item(scx,
730+
def_id,
731+
scx.tcx().mk_substs(iter::once(Kind::from(content_type))),
732+
scx.tcx().intern_substs(&[]));
733+
output.push(box_free_fn_trans_item);
734+
}
709735
}
710736

711737
// If the type implements Drop, also add a translation item for the
@@ -735,7 +761,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
735761
_ => bug!()
736762
};
737763

738-
if can_have_local_instance(scx.tcx(), destructor_did) {
764+
if should_trans_locally(scx.tcx(), destructor_did) {
739765
let trans_item = create_fn_trans_item(scx,
740766
destructor_did,
741767
substs,
@@ -1080,7 +1106,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
10801106
None
10811107
}
10821108
})
1083-
.filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
1109+
.filter(|&(def_id, _)| should_trans_locally(scx.tcx(), def_id))
10841110
.map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
10851111
output.extend(methods);
10861112
}
@@ -1255,7 +1281,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
12551281
continue;
12561282
}
12571283

1258-
if can_have_local_instance(tcx, method.def_id) {
1284+
if should_trans_locally(tcx, method.def_id) {
12591285
let item = create_fn_trans_item(scx,
12601286
method.def_id,
12611287
callee_substs,

0 commit comments

Comments
 (0)