Skip to content

Commit da96062

Browse files
committed
translate into multiple llvm contexts
Rotate between compilation units while translating. The "worker threads" commit added support for multiple compilation units, but only translated into one, leaving the rest empty. With this commit, `trans` rotates between various compilation units while translating, using a simple stragtegy: upon entering a module, switch to translating into whichever compilation unit currently contains the fewest LLVM instructions. Most of the actual changes here involve getting symbol linkage right, so that items translated into different compilation units will link together properly at the end.
1 parent 2e7bc0f commit da96062

File tree

8 files changed

+149
-50
lines changed

8 files changed

+149
-50
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,8 +2124,17 @@ impl<'a> Visitor<()> for TransItemVisitor<'a> {
21242124
}
21252125
}
21262126

2127+
pub fn update_linkage(ccx: &CrateContext, llval: ValueRef, id: ast::NodeId) {
2128+
if ccx.reachable().contains(&id) || ccx.sess().opts.cg.codegen_units > 1 {
2129+
llvm::SetLinkage(llval, llvm::ExternalLinkage);
2130+
} else {
2131+
llvm::SetLinkage(llval, llvm::InternalLinkage);
2132+
}
2133+
}
2134+
21272135
pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
21282136
let _icx = push_ctxt("trans_item");
2137+
21292138
match item.node {
21302139
ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => {
21312140
if !generics.is_type_parameterized() {
@@ -2148,6 +2157,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
21482157
item.id,
21492158
item.attrs.as_slice());
21502159
}
2160+
update_linkage(ccx, llfn, item.id);
21512161
}
21522162

21532163
// Be sure to travel more than just one layer deep to catch nested
@@ -2163,7 +2173,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
21632173
item.id);
21642174
}
21652175
ast::ItemMod(ref m) => {
2166-
trans_mod(ccx, m);
2176+
trans_mod(&ccx.rotate(), m);
21672177
}
21682178
ast::ItemEnum(ref enum_definition, _) => {
21692179
enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
@@ -2173,6 +2183,10 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
21732183
let mut v = TransItemVisitor{ ccx: ccx };
21742184
v.visit_expr(&**expr, ());
21752185
consts::trans_const(ccx, m, item.id);
2186+
2187+
let g = get_item_val(ccx, item.id);
2188+
update_linkage(ccx, g, item.id);
2189+
21762190
// Do static_assert checking. It can't really be done much earlier
21772191
// because we need to get the value of the bool out of LLVM
21782192
if attr::contains_name(item.attrs.as_slice(), "static_assert") {
@@ -2221,10 +2235,6 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N
22212235
llfn: ValueRef) {
22222236
ccx.item_symbols().borrow_mut().insert(node_id, sym);
22232237

2224-
if !ccx.reachable().contains(&node_id) {
2225-
llvm::SetLinkage(llfn, llvm::InternalLinkage);
2226-
}
2227-
22282238
// The stack exhaustion lang item shouldn't have a split stack because
22292239
// otherwise it would continue to be exhausted (bad), and both it and the
22302240
// eh_personality functions need to be externally linkable.
@@ -2592,7 +2602,6 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
25922602
None => {}
25932603
}
25942604

2595-
let mut foreign = false;
25962605
let item = ccx.tcx().map.get(id);
25972606
let val = match item {
25982607
ast_map::NodeItem(i) => {
@@ -2620,10 +2629,6 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
26202629
llvm::LLVMAddGlobal(ccx.llmod(), llty, buf)
26212630
});
26222631

2623-
if !ccx.reachable().contains(&id) {
2624-
llvm::SetLinkage(g, llvm::InternalLinkage);
2625-
}
2626-
26272632
// Apply the `unnamed_addr` attribute if
26282633
// requested
26292634
if !ast_util::static_has_significant_address(
@@ -2714,8 +2719,6 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
27142719
}
27152720

27162721
ast_map::NodeForeignItem(ni) => {
2717-
foreign = true;
2718-
27192722
match ni.node {
27202723
ast::ForeignItemFn(..) => {
27212724
let abi = ccx.tcx().map.get_foreign_abi(id);
@@ -2787,12 +2790,14 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
27872790
}
27882791
};
27892792

2790-
// foreign items (extern fns and extern statics) don't have internal
2791-
// linkage b/c that doesn't quite make sense. Otherwise items can
2792-
// have internal linkage if they're not reachable.
2793-
if !foreign && !ccx.reachable().contains(&id) {
2794-
llvm::SetLinkage(val, llvm::InternalLinkage);
2795-
}
2793+
// All LLVM globals and functions are initially created as external-linkage
2794+
// declarations. If `trans_item`/`trans_fn` later turns the declaration
2795+
// into a definition, it adjusts the linkage then (using `update_linkage`).
2796+
//
2797+
// The exception is foreign items, which have their linkage set inside the
2798+
// call to `foreign::register_*` above. We don't touch the linkage after
2799+
// that (`foreign::trans_foreign_mod` doesn't adjust the linkage like the
2800+
// other item translation functions do).
27962801

27972802
ccx.item_vals().borrow_mut().insert(id, val);
27982803
val
@@ -2815,7 +2820,8 @@ pub fn p2i(ccx: &CrateContext, v: ValueRef) -> ValueRef {
28152820
}
28162821
}
28172822

2818-
pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::EncodeInlinedItem<'r>)
2823+
pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r SharedCrateContext,
2824+
ie: encoder::EncodeInlinedItem<'r>)
28192825
-> encoder::EncodeParams<'r> {
28202826
encoder::EncodeParams {
28212827
diag: cx.sess().diagnostic(),
@@ -2830,7 +2836,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::EncodeI
28302836
}
28312837
}
28322838

2833-
pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
2839+
pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
28342840
use flate;
28352841

28362842
let any_library = cx.sess().crate_types.borrow().iter().any(|ty| {
@@ -2905,7 +2911,7 @@ pub fn trans_crate(krate: ast::Crate,
29052911
link_meta.clone(),
29062912
reachable);
29072913

2908-
let metadata = {
2914+
{
29092915
let ccx = shared_ccx.get_ccx(0);
29102916

29112917
// First, verify intrinsics.
@@ -2916,15 +2922,17 @@ pub fn trans_crate(krate: ast::Crate,
29162922
let _icx = push_ctxt("text");
29172923
trans_mod(&ccx, &krate.module);
29182924
}
2925+
}
29192926

2927+
for ccx in shared_ccx.iter() {
29202928
glue::emit_tydescs(&ccx);
29212929
if ccx.sess().opts.debuginfo != NoDebugInfo {
29222930
debuginfo::finalize(&ccx);
29232931
}
2932+
}
29242933

2925-
// Translate the metadata.
2926-
write_metadata(&ccx, &krate)
2927-
};
2934+
// Translate the metadata.
2935+
let metadata = write_metadata(&shared_ccx, &krate);
29282936

29292937
if shared_ccx.sess().trans_stats() {
29302938
let stats = shared_ccx.stats();

src/librustc/middle/trans/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl<'a> Builder<'a> {
5050
.n_llvm_insns
5151
.get() + 1);
5252
}
53+
self.ccx.count_llvm_insn();
5354
if self.ccx.sess().count_llvm_insns() {
5455
base::with_insn_ctxt(|v| {
5556
let mut h = self.ccx.stats().llvm_insns.borrow_mut();

src/librustc/middle/trans/consts.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,15 @@ pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
692692
// constant's initializer to determine its LLVM type.
693693
let v = ccx.const_values().borrow().get_copy(&id);
694694
llvm::LLVMSetInitializer(g, v);
695+
696+
// `get_item_val` left `g` with external linkage, but we just set an
697+
// initializer for it. But we don't know yet if `g` should really be
698+
// defined in this compilation unit, so we set its linkage to
699+
// `AvailableExternallyLinkage`. (It's still a definition, but acts
700+
// like a declaration for most purposes.) If `g` really should be
701+
// declared here, then `trans_item` will fix up the linkage later on.
702+
llvm::SetLinkage(g, llvm::AvailableExternallyLinkage);
703+
695704
if m != ast::MutMutable {
696705
llvm::LLVMSetGlobalConstant(g, True);
697706
}

src/librustc/middle/trans/context.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ pub struct LocalCrateContext {
141141
eh_personality: RefCell<Option<ValueRef>>,
142142

143143
intrinsics: RefCell<HashMap<&'static str, ValueRef>>,
144+
145+
/// Number of LLVM instructions translated into this `LocalCrateContext`.
146+
/// This is used to perform some basic load-balancing to keep all LLVM
147+
/// contexts around the same size.
148+
n_llvm_insns: Cell<uint>,
144149
}
145150

146151
pub struct CrateContext<'a> {
@@ -261,6 +266,18 @@ impl SharedCrateContext {
261266
}
262267
}
263268

269+
fn get_smallest_ccx<'a>(&'a self) -> CrateContext<'a> {
270+
let local_ccx =
271+
self.local_ccxs
272+
.iter()
273+
.min_by(|&local_ccx| local_ccx.n_llvm_insns.get())
274+
.unwrap();
275+
CrateContext {
276+
shared: self,
277+
local: local_ccx,
278+
}
279+
}
280+
264281

265282
pub fn metadata_llmod(&self) -> ModuleRef {
266283
self.metadata_llmod
@@ -364,6 +381,7 @@ impl LocalCrateContext {
364381
dbg_cx: dbg_cx,
365382
eh_personality: RefCell::new(None),
366383
intrinsics: RefCell::new(HashMap::new()),
384+
n_llvm_insns: Cell::new(0u),
367385
};
368386

369387
local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared));
@@ -415,6 +433,12 @@ impl<'b> CrateContext<'b> {
415433
}
416434

417435

436+
/// Get a (possibly) different `CrateContext` from the same
437+
/// `SharedCrateContext`.
438+
pub fn rotate(&self) -> CrateContext<'b> {
439+
self.shared.get_smallest_ccx()
440+
}
441+
418442
pub fn tcx<'a>(&'a self) -> &'a ty::ctxt {
419443
&self.shared.tcx
420444
}
@@ -467,14 +491,6 @@ impl<'b> CrateContext<'b> {
467491
self.local.llcx
468492
}
469493

470-
pub fn metadata_llmod(&self) -> ModuleRef {
471-
self.shared.metadata_llmod
472-
}
473-
474-
pub fn metadata_llcx(&self) -> ContextRef {
475-
self.shared.metadata_llcx
476-
}
477-
478494
pub fn td<'a>(&'a self) -> &'a TargetData {
479495
&self.local.td
480496
}
@@ -619,6 +635,10 @@ impl<'b> CrateContext<'b> {
619635
fn intrinsics<'a>(&'a self) -> &'a RefCell<HashMap<&'static str, ValueRef>> {
620636
&self.local.intrinsics
621637
}
638+
639+
pub fn count_llvm_insn(&self) {
640+
self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1);
641+
}
622642
}
623643

624644
fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {

src/librustc/middle/trans/expr.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,13 +817,28 @@ fn trans_def<'a>(bcx: &'a Block<'a>,
817817
trans_def_fn_unadjusted(bcx, ref_expr, def)
818818
}
819819
def::DefStatic(did, _) => {
820+
// There are three things that may happen here:
821+
// 1) If the static item is defined in this crate, it will be
822+
// translated using `get_item_val`, and we return a pointer to
823+
// the result.
824+
// 2) If the static item is defined in another crate, but is
825+
// marked inlineable, then it will be inlined into this crate
826+
// and then translated with `get_item_val`. Again, we return a
827+
// pointer to the result.
828+
// 3) If the static item is defined in another crate and is not
829+
// marked inlineable, then we add (or reuse) a declaration of
830+
// an external global, and return a pointer to that.
820831
let const_ty = expr_ty(bcx, ref_expr);
821832

822833
fn get_did(ccx: &CrateContext, did: ast::DefId)
823834
-> ast::DefId {
824835
if did.krate != ast::LOCAL_CRATE {
836+
// Case 2 or 3. Which one we're in is determined by
837+
// whether the DefId produced by `maybe_instantiate_inline`
838+
// is in the LOCAL_CRATE or not.
825839
inline::maybe_instantiate_inline(ccx, did)
826840
} else {
841+
// Case 1.
827842
did
828843
}
829844
}
@@ -832,13 +847,17 @@ fn trans_def<'a>(bcx: &'a Block<'a>,
832847
-> ValueRef {
833848
// For external constants, we don't inline.
834849
if did.krate == ast::LOCAL_CRATE {
850+
// Case 1 or 2. (The inlining in case 2 produces a new
851+
// DefId in LOCAL_CRATE.)
852+
835853
// The LLVM global has the type of its initializer,
836854
// which may not be equal to the enum's type for
837855
// non-C-like enums.
838856
let val = base::get_item_val(bcx.ccx(), did.node);
839857
let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
840858
PointerCast(bcx, val, pty)
841859
} else {
860+
// Case 3.
842861
match bcx.ccx().extern_const_values().borrow().find(&did) {
843862
None => {} // Continue.
844863
Some(llval) => {

src/librustc/middle/trans/foreign.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,18 @@ pub fn register_static(ccx: &CrateContext,
159159
}
160160
};
161161
unsafe {
162+
// Declare a symbol `foo` with the desired linkage.
162163
let g1 = ident.get().with_c_str(|buf| {
163164
llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf)
164165
});
165166
llvm::SetLinkage(g1, linkage);
166167

168+
// Declare an internal global `extern_with_linkage_foo` which
169+
// is initialized with the address of `foo`. If `foo` is
170+
// discarded during linking (for example, if `foo` has weak
171+
// linkage and there are no definitions), then
172+
// `extern_with_linkage_foo` will instead be initialized to
173+
// zero.
167174
let mut real_name = "_rust_extern_with_linkage_".to_string();
168175
real_name.push_str(ident.get());
169176
let g2 = real_name.with_c_str(|buf| {
@@ -175,6 +182,7 @@ pub fn register_static(ccx: &CrateContext,
175182
}
176183
}
177184
None => unsafe {
185+
// Generate an external declaration.
178186
ident.get().with_c_str(|buf| {
179187
llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf)
180188
})
@@ -490,6 +498,10 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
490498
register_foreign_item_fn(ccx, abi, ty,
491499
lname.get().as_slice(),
492500
Some(foreign_item.span));
501+
// Unlike for other items, we shouldn't call
502+
// `base::update_linkage` here. Foreign items have
503+
// special linkage requirements, which are handled
504+
// inside `foreign::register_*`.
493505
}
494506
}
495507
}

0 commit comments

Comments
 (0)