trans: Only translate #[inline] functions if they are used somewhere.

This commit is contained in:
Michael Woerister 2016-09-15 11:40:16 -04:00
parent 97b561a094
commit c10176ef66
4 changed files with 25 additions and 87 deletions

View File

@ -1591,7 +1591,11 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet {
node: hir::ImplItemKind::Method(..), .. }) => {
let def_id = tcx.map.local_def_id(id);
let generics = tcx.lookup_generics(def_id);
generics.parent_types == 0 && generics.types.is_empty()
let attributes = tcx.get_attrs(def_id);
(generics.parent_types == 0 && generics.types.is_empty()) &&
// Functions marked with #[inline] are only ever translated
// with "internal" linkage and are never exported.
!attr::requests_inline(&attributes[..])
}
_ => false

View File

@ -401,7 +401,7 @@ fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
callees: &[TransItem<'tcx>],
inlining_map: &mut InliningMap<'tcx>) {
let is_inlining_candidate = |trans_item: &TransItem<'tcx>| {
trans_item.is_from_extern_crate() || trans_item.requests_inline(tcx)
trans_item.needs_local_copy(tcx)
};
let inlining_candidates = callees.into_iter()

View File

@ -261,12 +261,6 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
{
let tcx = scx.tcx();
if let PartitioningStrategy::FixedUnitCount(1) = strategy {
// If there is only a single codegen-unit, we can use a very simple
// scheme and don't have to bother with doing much analysis.
return vec![single_codegen_unit(tcx, trans_items, reachable)];
}
// In the first step, we place all regular translation items into their
// respective 'home' codegen unit. Regular translation items are all
// functions and statics defined in the local crate.
@ -320,7 +314,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
let mut codegen_units = FnvHashMap();
for trans_item in trans_items {
let is_root = !trans_item.is_instantiated_only_on_demand();
let is_root = !trans_item.is_instantiated_only_on_demand(tcx);
if is_root {
let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item);
@ -454,7 +448,6 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
// reliably in that case.
new_codegen_unit.items.insert(trans_item, llvm::InternalLinkage);
} else {
assert!(trans_item.is_instantiated_only_on_demand());
// We can't be sure if this will also be instantiated
// somewhere else, so we add an instance here with
// InternalLinkage so we don't get any conflicts.
@ -550,68 +543,6 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return token::intern_and_get_ident(&mod_path[..]);
}
fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trans_items: I,
reachable: &NodeSet)
-> CodegenUnit<'tcx>
where I: Iterator<Item = TransItem<'tcx>>
{
let mut items = FnvHashMap();
for trans_item in trans_items {
let linkage = trans_item.explicit_linkage(tcx).unwrap_or_else(|| {
match trans_item {
TransItem::Static(node_id) => {
if reachable.contains(&node_id) {
llvm::ExternalLinkage
} else {
llvm::PrivateLinkage
}
}
TransItem::DropGlue(_) => {
llvm::InternalLinkage
}
TransItem::Fn(instance) => {
if trans_item.is_generic_fn() {
// FIXME(mw): Assigning internal linkage to all
// monomorphizations is potentially a waste of space
// since monomorphizations could be shared between
// crates. The main reason for making them internal is
// a limitation in MingW's binutils that cannot deal
// with COFF object that have more than 2^15 sections,
// which is something that can happen for large programs
// when every function gets put into its own COMDAT
// section.
llvm::InternalLinkage
} else if trans_item.is_from_extern_crate() {
// FIXME(mw): It would be nice if we could mark these as
// `AvailableExternallyLinkage`, since they should have
// been instantiated in the extern crate. But this
// sometimes leads to crashes on Windows because LLVM
// does not handle exception handling table instantiation
// reliably in that case.
llvm::InternalLinkage
} else if reachable.contains(&tcx.map
.as_local_node_id(instance.def)
.unwrap()) {
llvm::ExternalLinkage
} else {
// Functions that are not visible outside this crate can
// be marked as internal.
llvm::InternalLinkage
}
}
}
});
items.insert(trans_item, linkage);
}
CodegenUnit::new(
numbered_codegen_unit_name(&tcx.crate_name[..], 0),
items)
}
fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
token::intern_and_get_ident(&format!("{}{}{}",
crate_name,

View File

@ -241,19 +241,6 @@ impl<'a, 'tcx> TransItem<'tcx> {
}
}
pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
match *self {
TransItem::Fn(ref instance) => {
instance.substs.types().next().is_some() || {
let attributes = tcx.get_attrs(instance.def);
attr::requests_inline(&attributes[..])
}
}
TransItem::DropGlue(..) => true,
TransItem::Static(..) => false,
}
}
pub fn is_from_extern_crate(&self) -> bool {
match *self {
TransItem::Fn(ref instance) => !instance.def.is_local(),
@ -262,10 +249,14 @@ impl<'a, 'tcx> TransItem<'tcx> {
}
}
pub fn is_instantiated_only_on_demand(&self) -> bool {
/// True if the translation item should only be translated to LLVM IR if
/// it is referenced somewhere (like inline functions, for example).
pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt) -> bool {
match *self {
TransItem::Fn(ref instance) => {
!instance.def.is_local() || instance.substs.types().next().is_some()
!instance.def.is_local() ||
instance.substs.types().next().is_some() ||
attr::requests_inline(&tcx.get_attrs(instance.def)[..])
}
TransItem::DropGlue(..) => true,
TransItem::Static(..) => false,
@ -282,6 +273,18 @@ impl<'a, 'tcx> TransItem<'tcx> {
}
}
/// Returns true if there has to be a local copy of this TransItem in every
/// codegen unit that references it (as with inlined functions, for example)
pub fn needs_local_copy(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
// Currently everything that is instantiated only on demand is done so
// with "internal" linkage, so we need a copy to be present in every
// codegen unit.
// This is coincidental: We could also instantiate something only if it
// is referenced (e.g. a regular, private function) but place it in its
// own codegen unit with "external" linkage.
self.is_instantiated_only_on_demand(tcx)
}
pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Linkage> {
let def_id = match *self {
TransItem::Fn(ref instance) => instance.def,