Skip to content

Commit edc5cdc

Browse files
committed
make symbols internal when possible
Add a post-processing pass to `trans` that converts symbols from external to internal when possible. Translation with multiple compilation units initially makes most symbols external, since it is not clear when translating a definition whether that symbol will need to be accessed from another compilation unit. This final pass internalizes symbols that are not reachable from other crates and not referenced from other compilation units, so that LLVM can perform more aggressive optimizations on those symbols.
1 parent e09bef8 commit edc5cdc

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ use arena::TypedArena;
8585
use libc::{c_uint, uint64_t};
8686
use std::c_str::ToCStr;
8787
use std::cell::{Cell, RefCell};
88+
use std::collections::HashSet;
8889
use std::rc::Rc;
8990
use std::{i8, i16, i32, i64};
9091
use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
@@ -2891,6 +2892,84 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
28912892
return metadata;
28922893
}
28932894

2895+
/// Find any symbols that are defined in one compilation unit, but not declared
2896+
/// in any other compilation unit. Give these symbols internal linkage.
2897+
fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
2898+
use std::c_str::CString;
2899+
2900+
unsafe {
2901+
let mut declared = HashSet::new();
2902+
2903+
let iter_globals = |llmod| {
2904+
ValueIter {
2905+
cur: llvm::LLVMGetFirstGlobal(llmod),
2906+
step: llvm::LLVMGetNextGlobal,
2907+
}
2908+
};
2909+
2910+
let iter_functions = |llmod| {
2911+
ValueIter {
2912+
cur: llvm::LLVMGetFirstFunction(llmod),
2913+
step: llvm::LLVMGetNextFunction,
2914+
}
2915+
};
2916+
2917+
// Collect all external declarations in all compilation units.
2918+
for ccx in cx.iter() {
2919+
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
2920+
let linkage = llvm::LLVMGetLinkage(val);
2921+
// We only care about external declarations (not definitions)
2922+
// and available_externally definitions.
2923+
if !(linkage == llvm::ExternalLinkage as c_uint &&
2924+
llvm::LLVMIsDeclaration(val) != 0) &&
2925+
!(linkage == llvm::AvailableExternallyLinkage as c_uint) {
2926+
continue
2927+
}
2928+
2929+
let name = CString::new(llvm::LLVMGetValueName(val), false);
2930+
declared.insert(name);
2931+
}
2932+
}
2933+
2934+
// Examine each external definition. If the definition is not used in
2935+
// any other compilation unit, and is not reachable from other crates,
2936+
// then give it internal linkage.
2937+
for ccx in cx.iter() {
2938+
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
2939+
// We only care about external definitions.
2940+
if !(llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint &&
2941+
llvm::LLVMIsDeclaration(val) == 0) {
2942+
continue
2943+
}
2944+
2945+
let name = CString::new(llvm::LLVMGetValueName(val), false);
2946+
if !declared.contains(&name) &&
2947+
!reachable.contains_equiv(&name.as_str().unwrap()) {
2948+
llvm::SetLinkage(val, llvm::InternalLinkage);
2949+
}
2950+
}
2951+
}
2952+
}
2953+
2954+
2955+
struct ValueIter {
2956+
cur: ValueRef,
2957+
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
2958+
}
2959+
2960+
impl Iterator<ValueRef> for ValueIter {
2961+
fn next(&mut self) -> Option<ValueRef> {
2962+
let old = self.cur;
2963+
if !old.is_null() {
2964+
self.cur = unsafe { (self.step)(old) };
2965+
Some(old)
2966+
} else {
2967+
None
2968+
}
2969+
}
2970+
}
2971+
}
2972+
28942973
pub fn trans_crate(krate: ast::Crate,
28952974
analysis: CrateAnalysis) -> (ty::ctxt, CrateTranslation) {
28962975
let CrateAnalysis { ty_cx: tcx, exp_map2, reachable, name, .. } = analysis;
@@ -3009,6 +3088,10 @@ pub fn trans_crate(krate: ast::Crate,
30093088
// referenced from rt/rust_try.ll
30103089
reachable.push("rust_eh_personality_catch".to_string());
30113090

3091+
if codegen_units > 1 {
3092+
internalize_symbols(&shared_ccx, &reachable.iter().map(|x| x.clone()).collect());
3093+
}
3094+
30123095
let metadata_module = ModuleTranslation {
30133096
llcx: shared_ccx.metadata_llcx(),
30143097
llmod: shared_ccx.metadata_llmod(),

0 commit comments

Comments
 (0)