avoid duplicate translation of monomorphizations, drop glue, and visit glue

Use a shared lookup table of previously-translated monomorphizations/glue
functions to avoid translating those functions in every compilation unit where
they're used.  Instead, the function will be translated in whichever
compilation unit uses it first, and the remaining compilation units will link
against that original definition.
This commit is contained in:
Stuart Pernsteiner 2014-07-31 16:45:29 -07:00
parent da9606247d
commit e09bef810a
5 changed files with 114 additions and 31 deletions

View File

@ -2124,11 +2124,24 @@ impl<'a> Visitor<()> for TransItemVisitor<'a> {
}
}
pub fn update_linkage(ccx: &CrateContext, llval: ValueRef, id: ast::NodeId) {
if ccx.reachable().contains(&id) || ccx.sess().opts.cg.codegen_units > 1 {
llvm::SetLinkage(llval, llvm::ExternalLinkage);
} else {
llvm::SetLinkage(llval, llvm::InternalLinkage);
/// Set the appropriate linkage for an LLVM `ValueRef` (function or global).
/// If the `llval` is the direct translation of a specific Rust item, `id`
/// should be set to the `NodeId` of that item. (This mapping should be
/// 1-to-1, so monomorphizations and drop/visit glue should have `id` set to
/// `None`.)
pub fn update_linkage(ccx: &CrateContext, llval: ValueRef, id: Option<ast::NodeId>) {
match id {
Some(id) if ccx.reachable().contains(&id) => {
llvm::SetLinkage(llval, llvm::ExternalLinkage);
},
_ => {
// `id` does not refer to an item in `ccx.reachable`.
if ccx.sess().opts.cg.codegen_units > 1 {
llvm::SetLinkage(llval, llvm::ExternalLinkage);
} else {
llvm::SetLinkage(llval, llvm::InternalLinkage);
}
},
}
}
@ -2157,7 +2170,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
item.id,
item.attrs.as_slice());
}
update_linkage(ccx, llfn, item.id);
update_linkage(ccx, llfn, Some(item.id));
}
// Be sure to travel more than just one layer deep to catch nested
@ -2185,7 +2198,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
consts::trans_const(ccx, m, item.id);
let g = get_item_val(ccx, item.id);
update_linkage(ccx, g, item.id);
update_linkage(ccx, g, Some(item.id));
// Do static_assert checking. It can't really be done much earlier
// because we need to get the value of the bool out of LLVM

View File

@ -72,6 +72,10 @@ pub struct SharedCrateContext {
symbol_hasher: RefCell<Sha256>,
tcx: ty::ctxt,
stats: Stats,
available_monomorphizations: RefCell<HashSet<String>>,
available_drop_glues: RefCell<HashMap<ty::t, String>>,
available_visit_glues: RefCell<HashMap<ty::t, String>>,
}
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@ -233,6 +237,9 @@ impl SharedCrateContext {
llvm_insns: RefCell::new(HashMap::new()),
fn_stats: RefCell::new(Vec::new()),
},
available_monomorphizations: RefCell::new(HashSet::new()),
available_drop_glues: RefCell::new(HashMap::new()),
available_visit_glues: RefCell::new(HashMap::new()),
};
for i in range(0, local_count) {
@ -612,6 +619,18 @@ impl<'b> CrateContext<'b> {
&self.shared.stats
}
pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<HashSet<String>> {
&self.shared.available_monomorphizations
}
pub fn available_drop_glues<'a>(&'a self) -> &'a RefCell<HashMap<ty::t, String>> {
&self.shared.available_drop_glues
}
pub fn available_visit_glues<'a>(&'a self) -> &'a RefCell<HashMap<ty::t, String>> {
&self.shared.available_visit_glues
}
pub fn int_type(&self) -> Type {
self.local.int_type
}

View File

@ -171,11 +171,30 @@ pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef {
};
let llfnty = Type::glue_fn(ccx, llty);
let glue = declare_generic_glue(ccx, t, llfnty, "drop");
let (glue, new_sym) = match ccx.available_drop_glues().borrow().find(&t) {
Some(old_sym) => {
let glue = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil());
(glue, None)
},
None => {
let (sym, glue) = declare_generic_glue(ccx, t, llfnty, "drop");
(glue, Some(sym))
},
};
ccx.drop_glues().borrow_mut().insert(t, glue);
make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
// To avoid infinite recursion, don't `make_drop_glue` until after we've
// added the entry to the `drop_glues` cache.
match new_sym {
Some(sym) => {
ccx.available_drop_glues().borrow_mut().insert(t, sym);
// We're creating a new drop glue, so also generate a body.
make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
},
None => {},
}
glue
}
@ -189,9 +208,28 @@ pub fn lazily_emit_visit_glue(ccx: &CrateContext, ti: &tydesc_info) -> ValueRef
Some(visit_glue) => visit_glue,
None => {
debug!("+++ lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_string(ccx.tcx(), ti.ty));
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
let (glue_fn, new_sym) = match ccx.available_visit_glues().borrow().find(&ti.ty) {
Some(old_sym) => {
let glue_fn = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil());
(glue_fn, None)
},
None => {
let (sym, glue_fn) = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
(glue_fn, Some(sym))
},
};
ti.visit_glue.set(Some(glue_fn));
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
match new_sym {
Some(sym) => {
ccx.available_visit_glues().borrow_mut().insert(ti.ty, sym);
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
},
None => {},
}
debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_string(ccx.tcx(), ti.ty));
glue_fn
}
@ -602,15 +640,15 @@ pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info {
}
fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
name: &str) -> ValueRef {
name: &str) -> (String, ValueRef) {
let _icx = push_ctxt("declare_generic_glue");
let fn_nm = mangle_internal_name_by_type_and_seq(
ccx,
t,
format!("glue_{}", name).as_slice());
let llfn = decl_cdecl_fn(ccx, fn_nm.as_slice(), llfnty, ty::mk_nil());
note_unique_llvm_symbol(ccx, fn_nm);
return llfn;
note_unique_llvm_symbol(ccx, fn_nm.clone());
return (fn_nm, llfn);
}
fn make_generic_glue(ccx: &CrateContext,
@ -631,7 +669,8 @@ fn make_generic_glue(ccx: &CrateContext,
let bcx = init_function(&fcx, false, ty::mk_nil());
llvm::SetLinkage(llfn, llvm::InternalLinkage);
update_linkage(ccx, llfn, None);
ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1u);
// All glue functions take values passed *by alias*; this is a
// requirement since in many contexts glue is invoked indirectly and

View File

@ -85,7 +85,7 @@ pub fn trans_impl(ccx: &CrateContext,
&param_substs::empty(),
method.id,
[]);
update_linkage(ccx, llfn, method.id);
update_linkage(ccx, llfn, Some(method.id));
}
let mut v = TransItemVisitor {
ccx: ccx,

View File

@ -159,14 +159,18 @@ pub fn monomorphic_fn(ccx: &CrateContext,
..
} => {
let d = mk_lldecl(abi);
base::update_linkage(ccx, d, None);
set_llvm_fn_attrs(i.attrs.as_slice(), d);
if abi != abi::Rust {
foreign::trans_rust_fn_with_foreign_abi(
ccx, &**decl, &**body, [], d, &psubsts, fn_id.node,
Some(hash.as_slice()));
} else {
trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, []);
if !ccx.available_monomorphizations().borrow().contains(&s) {
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
if abi != abi::Rust {
foreign::trans_rust_fn_with_foreign_abi(
ccx, &**decl, &**body, [], d, &psubsts, fn_id.node,
Some(hash.as_slice()));
} else {
trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, []);
}
}
d
@ -201,14 +205,18 @@ pub fn monomorphic_fn(ccx: &CrateContext,
match *ii {
ast::MethodImplItem(mth) => {
let d = mk_lldecl(abi::Rust);
base::update_linkage(ccx, d, None);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx,
&*mth.pe_fn_decl(),
&*mth.pe_body(),
d,
&psubsts,
mth.id,
[]);
if !ccx.available_monomorphizations().borrow().contains(&s) {
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
trans_fn(ccx,
&*mth.pe_fn_decl(),
&*mth.pe_body(),
d,
&psubsts,
mth.id,
[]);
}
d
}
}
@ -217,9 +225,13 @@ pub fn monomorphic_fn(ccx: &CrateContext,
match *method {
ast::ProvidedMethod(mth) => {
let d = mk_lldecl(abi::Rust);
base::update_linkage(ccx, d, None);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d,
&psubsts, mth.id, []);
if !ccx.available_monomorphizations().borrow().contains(&s) {
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d,
&psubsts, mth.id, []);
}
d
}
_ => {