Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: linker placement attribute proposed implementation #13661

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 62 additions & 47 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1851,62 +1851,77 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {

// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
let (v, inlineable) = consts::const_expr(ccx, expr, is_local);
let (v, inlineable) = if attr::contains_name(i.attrs.as_slice(),
"unsafe_override_address") {
let (addrconst, _) = consts::const_expr(ccx, expr, is_local);
let llptrty = type_of(ccx, ty).ptr_to().to_ref();
let ptr = unsafe { llvm::LLVMConstIntToPtr(addrconst, llptrty) };

(ptr, true)
} else {
consts::const_expr(ccx, expr, is_local)
};
ccx.const_values.borrow_mut().insert(id, v);
let mut inlineable = inlineable;

unsafe {
let llty = llvm::LLVMTypeOf(v);
let g = sym.with_c_str(|buf| {
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
});
if attr::contains_name(i.attrs.as_slice(), "unsafe_override_address") {
ccx.item_symbols.borrow_mut().insert(i.id, sym);
foreign = true;
v
} else {
unsafe {
let llty = llvm::LLVMTypeOf(v);
let g = sym.with_c_str(|buf| {
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
});

if !ccx.reachable.contains(&id) {
lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
}

if !ccx.reachable.contains(&id) {
lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
}
// Apply the `unnamed_addr` attribute if
// requested
if attr::contains_name(i.attrs.as_slice(),
"address_insignificant") {
if ccx.reachable.contains(&id) {
ccx.sess().span_bug(i.span,
"insignificant static is reachable");
}
lib::llvm::SetUnnamedAddr(g, true);

// This is a curious case where we must make
// all of these statics inlineable. If a
// global is tagged as
// address_insignificant, then LLVM won't
// coalesce globals unless they have an
// internal linkage type. This means that
// external crates cannot use this global.
// This is a problem for things like inner
// statics in generic functions, because the
// function will be inlined into another
// crate and then attempt to link to the
// static in the original crate, only to
// find that it's not there. On the other
// side of inlininig, the crates knows to
// not declare this static as
// available_externally (because it isn't)
inlineable = true;
}

// Apply the `unnamed_addr` attribute if
// requested
if attr::contains_name(i.attrs.as_slice(),
"address_insignificant") {
if ccx.reachable.contains(&id) {
ccx.sess().span_bug(i.span,
"insignificant static is reachable");
if attr::contains_name(i.attrs.as_slice(),
"thread_local") {
lib::llvm::set_thread_local(g, true);
}
lib::llvm::SetUnnamedAddr(g, true);

// This is a curious case where we must make
// all of these statics inlineable. If a
// global is tagged as
// address_insignificant, then LLVM won't
// coalesce globals unless they have an
// internal linkage type. This means that
// external crates cannot use this global.
// This is a problem for things like inner
// statics in generic functions, because the
// function will be inlined into another
// crate and then attempt to link to the
// static in the original crate, only to
// find that it's not there. On the other
// side of inlininig, the crates knows to
// not declare this static as
// available_externally (because it isn't)
inlineable = true;
}

if attr::contains_name(i.attrs.as_slice(),
"thread_local") {
lib::llvm::set_thread_local(g, true);
}
if !inlineable {
debug!("{} not inlined", sym);
ccx.non_inlineable_statics.borrow_mut()
.insert(id);
}

if !inlineable {
debug!("{} not inlined", sym);
ccx.non_inlineable_statics.borrow_mut()
.insert(id);
ccx.item_symbols.borrow_mut().insert(i.id, sym);
g
}

ccx.item_symbols.borrow_mut().insert(i.id, sym);
g
}
}

Expand Down
22 changes: 16 additions & 6 deletions src/librustc/middle/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ use std::c_str::ToCStr;
use std::slice;
use std::vec::Vec;
use libc::c_uint;
use syntax::{ast, ast_util};
use syntax::{ast, ast_util, ast_map, attr};


pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
-> ValueRef {
Expand Down Expand Up @@ -683,13 +684,22 @@ pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
unsafe {
let _icx = push_ctxt("trans_const");
let g = base::get_item_val(ccx, id);
let item = ccx.tcx.map.get(id);
let isglobal = match item {
ast_map::NodeItem(i) =>
if attr::contains_name(i.attrs.as_slice(),
"unsafe_override_address") {false} else {true},
_ => true,
};
// At this point, get_item_val has already translated the
// constant's initializer to determine its LLVM type.
let v = ccx.const_values.borrow().get_copy(&id);
llvm::LLVMSetInitializer(g, v);
if m != ast::MutMutable {
llvm::LLVMSetGlobalConstant(g, True);
if isglobal {
let v = ccx.const_values.borrow().get_copy(&id);
llvm::LLVMSetInitializer(g, v);
if m != ast::MutMutable {
llvm::LLVMSetGlobalConstant(g, True);
}
debuginfo::create_global_var_metadata(ccx, id, g);
}
debuginfo::create_global_var_metadata(ccx, id, g);
}
}
18 changes: 15 additions & 3 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,15 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
let _indenter = indenter();

match it.node {
ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
ast::ItemStatic(_, _, e) => {
// override type to uint if it's unsafe_override_address, to make things
// like static t: T = 123 work.
if attr::contains_name(it.attrs.as_slice(), "unsafe_override_address") {
check_const(ccx, it.span, e, it.id, Some(ty::mk_u32()));
} else {
check_const(ccx, it.span, e, it.id, None);
}
}
ast::ItemEnum(ref enum_definition, _) => {
check_enum_variants(ccx,
it.span,
Expand Down Expand Up @@ -3407,11 +3415,15 @@ pub fn check_block_with_expected(fcx: &FnCtxt,
pub fn check_const(ccx: &CrateCtxt,
sp: Span,
e: &ast::Expr,
id: ast::NodeId) {
id: ast::NodeId,
override_ty: Option<ty::t>) {
let inh = blank_inherited_fields(ccx);
let rty = ty::node_id_to_type(ccx.tcx, id);
let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
let declty = match override_ty {
Some(t) => t,
None => fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty,
};
check_const_with_ty(&fcx, sp, e, declty);
}

Expand Down