Skip to content

Commit

Permalink
Drive function item translation from collector
Browse files Browse the repository at this point in the history
Functions and method are declared ahead-of-time, including generic ones.

Closures are not considered trans items anymore, instead they are
translated on demands.
  • Loading branch information
Aatch authored and michaelwoerister committed Jul 8, 2016
1 parent 891c2a0 commit 6717106
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 175 deletions.
173 changes: 90 additions & 83 deletions src/librustc_trans/base.rs
Expand Up @@ -75,6 +75,7 @@ use debuginfo::{self, DebugLoc, ToDebugLoc};
use declare;
use expr;
use glue;
use inline;
use machine;
use machine::{llalign_of_min, llsize_of, llsize_of_real};
use meth;
Expand Down Expand Up @@ -1948,6 +1949,49 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
closure::ClosureEnv::NotClosure);
}

pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
let instance = inline::maybe_inline_instance(ccx, instance);

let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();

let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(fn_node_id));
debug!("trans_instance(instance={:?})", instance);
let _icx = push_ctxt("trans_instance");

let item = ccx.tcx().map.find(fn_node_id).unwrap();

let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty;
let fn_ty = ccx.tcx().erase_regions(&fn_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty);

let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
let abi = fn_ty.fn_abi();

let lldecl = match ccx.instances().borrow().get(&instance) {
Some(&val) => val,
None => bug!("Instance `{:?}` not already declared", instance)
};

match item {
hir_map::NodeItem(&hir::Item {
node: hir::ItemFn(ref decl, _, _, _, _, ref body), ..
}) |
hir_map::NodeTraitItem(&hir::TraitItem {
node: hir::MethodTraitItem(
hir::MethodSig { ref decl, .. }, Some(ref body)), ..
}) |
hir_map::NodeImplItem(&hir::ImplItem {
node: hir::ImplItemKind::Method(
hir::MethodSig { ref decl, .. }, ref body), ..
}) => {
trans_closure(ccx, decl, body, lldecl, instance,
fn_node_id, &sig, abi, closure::ClosureEnv::NotClosure);
}
_ => bug!("Instance is a {:?}?", item)
}
}

pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
ctor_ty: Ty<'tcx>,
disr: Disr,
Expand Down Expand Up @@ -2267,79 +2311,33 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
let _icx = push_ctxt("trans_item");

let tcx = ccx.tcx();
let from_external = ccx.external_srcs().borrow().contains_key(&item.id);

match item.node {
hir::ItemFn(ref decl, _, _, _, ref generics, ref body) => {
if !generics.is_type_parameterized() {
let trans_everywhere = attr::requests_inline(&item.attrs);
// Ignore `trans_everywhere` for cross-crate inlined items
// (`from_external`). `trans_item` will be called once for each
// compilation unit that references the item, so it will still get
// translated everywhere it's needed.
for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) {
let def_id = tcx.map.local_def_id(item.id);
let empty_substs = ccx.empty_substs_for_def_id(def_id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
trans_fn(ccx, &decl, &body, llfn, empty_substs, item.id);
set_link_section(ccx, llfn, &item.attrs);
update_linkage(ccx,
llfn,
Some(item.id),
if is_origin {
OriginalTranslation
} else {
InlinedCopy
});

if is_entry_fn(ccx.sess(), item.id) {
create_entry_wrapper(ccx, item.span, llfn);
// check for the #[rustc_error] annotation, which forces an
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
if tcx.has_attr(def_id, "rustc_error") {
tcx.sess.span_fatal(item.span, "compilation successful");
}
}
hir::ItemFn(_, _, _, _, _, _) => {
let def_id = tcx.map.local_def_id(item.id);
// check for the #[rustc_error] annotation, which forces an
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
if is_entry_fn(ccx.sess(), item.id) {
let empty_substs = ccx.empty_substs_for_def_id(def_id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
create_entry_wrapper(ccx, item.span, llfn);
if tcx.has_attr(def_id, "rustc_error") {
tcx.sess.span_fatal(item.span, "compilation successful");
}
}
}
hir::ItemImpl(_, _, ref generics, _, _, ref impl_items) => {
// Both here and below with generic methods, be sure to recurse and look for
// items that we need to translate.
if !generics.ty_params.is_empty() {
return;
}

for impl_item in impl_items {
if let hir::ImplItemKind::Method(ref sig, ref body) = impl_item.node {
if sig.generics.ty_params.is_empty() {
let trans_everywhere = attr::requests_inline(&impl_item.attrs);
for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) {
let def_id = tcx.map.local_def_id(impl_item.id);
let empty_substs = ccx.empty_substs_for_def_id(def_id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
trans_fn(ccx, &sig.decl, body, llfn, empty_substs, impl_item.id);
update_linkage(ccx, llfn, Some(impl_item.id),
if is_origin {
OriginalTranslation
} else {
InlinedCopy
});
}
}
}
}
// Function is actually translated in trans_instance
}
hir::ItemEnum(ref enum_definition, ref gens) => {
if gens.ty_params.is_empty() {
// sizes only make sense for non-generic types
enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
}
}
hir::ItemImpl(..) |
hir::ItemStatic(..) => {
// Don't do anything here. Translation of statics has been moved to
// Don't do anything here. Translation has been moved to
// being "collector-driven".
}
_ => {}
Expand Down Expand Up @@ -2482,16 +2480,16 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
let linkage = llvm::LLVMGetLinkage(val);
// We only care about external declarations (not definitions)
// and available_externally definitions.
if !(linkage == llvm::ExternalLinkage as c_uint &&
llvm::LLVMIsDeclaration(val) != 0) &&
!(linkage == llvm::AvailableExternallyLinkage as c_uint) {
continue;
let is_available_externally = linkage == llvm::AvailableExternallyLinkage as c_uint;
let is_decl = llvm::LLVMIsDeclaration(val) != 0;

if is_decl || is_available_externally {
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes()
.to_vec();
declared.insert(name);
}

let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes()
.to_vec();
declared.insert(name);
}
}

Expand All @@ -2501,21 +2499,27 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
for ccx in cx.iter() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
let linkage = llvm::LLVMGetLinkage(val);

let is_external = linkage == llvm::ExternalLinkage as c_uint;
let is_weak_odr = linkage == llvm::WeakODRLinkage as c_uint;
let is_decl = llvm::LLVMIsDeclaration(val) != 0;

// We only care about external definitions.
if !((linkage == llvm::ExternalLinkage as c_uint ||
linkage == llvm::WeakODRLinkage as c_uint) &&
llvm::LLVMIsDeclaration(val) == 0) {
continue;
}
if (is_external || is_weak_odr) && !is_decl {

let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes()
.to_vec();

let is_declared = declared.contains(&name);
let reachable = reachable.contains(str::from_utf8(&name).unwrap());

if !is_declared && !reachable {
llvm::SetLinkage(val, llvm::InternalLinkage);
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
llvm::UnsetComdat(val);
}

let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes()
.to_vec();
if !declared.contains(&name) &&
!reachable.contains(str::from_utf8(&name).unwrap()) {
llvm::SetLinkage(val, llvm::InternalLinkage);
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
llvm::UnsetComdat(val);
}
}
}
Expand Down Expand Up @@ -2744,6 +2748,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
}
}
TransItem::Fn(instance) => {
trans_instance(&ccx, instance);
}
_ => { }
}
}
Expand Down Expand Up @@ -2980,7 +2987,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
let mut item_keys: Vec<_> = items
.iter()
.map(|i| {
let mut output = i.to_string(scx.tcx());
let mut output = i.to_string(scx);
output.push_str(" @@");
let mut empty = Vec::new();
let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_trans/closure.rs
Expand Up @@ -10,7 +10,7 @@

use arena::TypedArena;
use back::symbol_names;
use llvm::{ValueRef, get_param, get_params};
use llvm::{self, ValueRef, get_param, get_params};
use rustc::hir::def_id::DefId;
use abi::{Abi, FnType};
use adt;
Expand Down Expand Up @@ -167,7 +167,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
variadic: false
})
}));
let llfn = declare::define_internal_fn(ccx, &symbol, function_type);
let llfn = declare::declare_fn(ccx, &symbol, function_type);

// set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint);
Expand Down Expand Up @@ -211,6 +211,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
id, closure_def_id, closure_substs);

let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
llvm::SetLinkage(llfn, llvm::WeakODRLinkage);

// Get the type of this closure. Use the current `param_substs` as
// the closure substitutions. This makes sense because the closure
Expand Down Expand Up @@ -377,7 +378,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
// Create the by-value helper.
let function_name =
symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
attributes::set_frame_pointer_elimination(ccx, lloncefn);

let (block_arena, fcx): (TypedArena<_>, FunctionContext);
Expand Down
41 changes: 26 additions & 15 deletions src/librustc_trans/collector.rs
Expand Up @@ -325,7 +325,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
// We've been here already, no need to search again.
return;
}
debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx()));
debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx));

let mut neighbors = Vec::new();
let recursion_depth_reset;
Expand Down Expand Up @@ -396,7 +396,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
recursion_depths.insert(def_id, depth);
}

debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx()));
debug!("END collect_items_rec({})", starting_point.to_string(scx));
}

fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Expand Down Expand Up @@ -456,12 +456,25 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
match *rvalue {
mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id,
ref substs), _) => {
assert!(can_have_local_instance(self.scx.tcx(), def_id));
let trans_item = create_fn_trans_item(self.scx.tcx(),
def_id,
substs.func_substs,
self.param_substs);
self.output.push(trans_item);
let mir = errors::expect(self.scx.sess().diagnostic(), self.scx.get_mir(def_id),
|| format!("Could not find MIR for closure: {:?}", def_id));

let concrete_substs = monomorphize::apply_param_substs(self.scx.tcx(),
self.param_substs,
&substs.func_substs);
let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs);

let mut visitor = MirNeighborCollector {
scx: self.scx,
mir: &mir,
output: self.output,
param_substs: concrete_substs
};

visitor.visit_mir(&mir);
for promoted in &mir.promoted {
visitor.visit_mir(promoted);
}
}
// When doing an cast from a regular pointer to a fat pointer, we
// have to instantiate all methods of the trait being cast to, so we
Expand Down Expand Up @@ -1107,9 +1120,8 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
self.scx.tcx().map.local_def_id(item.id)));
self.output.push(TransItem::Static(item.id));
}
hir::ItemFn(_, _, constness, _, ref generics, _) => {
if !generics.is_type_parameterized() &&
constness == hir::Constness::NotConst {
hir::ItemFn(_, _, _, _, ref generics, _) => {
if !generics.is_type_parameterized() {
let def_id = self.scx.tcx().map.local_def_id(item.id);

debug!("RootCollector: ItemFn({})",
Expand All @@ -1129,9 +1141,8 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
match ii.node {
hir::ImplItemKind::Method(hir::MethodSig {
ref generics,
constness,
..
}, _) if constness == hir::Constness::NotConst => {
}, _) => {
let hir_map = &self.scx.tcx().map;
let parent_node_id = hir_map.get_parent_node(ii.id);
let is_impl_generic = match hir_map.expect_item(parent_node_id) {
Expand Down Expand Up @@ -1260,7 +1271,7 @@ pub fn print_collection_results<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) {
let mut item_keys = FnvHashMap();

for (item, item_state) in trans_items.iter() {
let k = item.to_string(scx.tcx());
let k = item.to_string(scx);

if item_keys.contains_key(&k) {
let prev: (TransItem, TransItemState) = item_keys[&k];
Expand Down Expand Up @@ -1288,7 +1299,7 @@ pub fn print_collection_results<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) {
let mut generated = FnvHashSet();

for (item, item_state) in trans_items.iter() {
let item_key = item.to_string(scx.tcx());
let item_key = item.to_string(scx);

match *item_state {
TransItemState::PredictedAndGenerated => {
Expand Down

0 comments on commit 6717106

Please sign in to comment.