trans: Only translate #[inline] functions if they are used somewhere.
This commit is contained in:
parent
97b561a094
commit
c10176ef66
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user