trans: Move static item handling to consts.
This commit is contained in:
parent
c3f856e7e2
commit
5af3c12cfc
6 changed files with 123 additions and 150 deletions
|
|
@ -10,8 +10,8 @@
|
|||
//! Translate the completed AST to the LLVM IR.
|
||||
//!
|
||||
//! Some functions here, such as trans_block and trans_expr, return a value --
|
||||
//! the result of the translation to LLVM -- while others, such as trans_fn,
|
||||
//! trans_impl, and trans_item, are called only for the side effect of adding a
|
||||
//! the result of the translation to LLVM -- while others, such as trans_fn
|
||||
//! and trans_item, are called only for the side effect of adding a
|
||||
//! particular definition to the LLVM IR output we're producing.
|
||||
//!
|
||||
//! Hopefully useful general knowledge about trans:
|
||||
|
|
@ -228,36 +228,6 @@ pub fn kind_for_closure(ccx: &CrateContext, closure_id: DefId) -> ty::ClosureKin
|
|||
*ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
did: DefId,
|
||||
t: Ty<'tcx>)
|
||||
-> ValueRef {
|
||||
let name = ccx.sess().cstore.item_symbol(did);
|
||||
let ty = type_of(ccx, t);
|
||||
if let Some(n) = ccx.externs().borrow_mut().get(&name) {
|
||||
return *n;
|
||||
}
|
||||
// FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
|
||||
// FIXME(nagisa): investigate whether it can be changed into define_global
|
||||
let c = declare::declare_global(ccx, &name[..], ty);
|
||||
// Thread-local statics in some other crate need to *always* be linked
|
||||
// against in a thread-local fashion, so we need to be sure to apply the
|
||||
// thread-local attribute locally if it was present remotely. If we
|
||||
// don't do this then linker errors can be generated where the linker
|
||||
// complains that one object files has a thread local version of the
|
||||
// symbol and another one doesn't.
|
||||
for attr in ccx.tcx().get_attrs(did).iter() {
|
||||
if attr.check_name("thread_local") {
|
||||
llvm::set_thread_local(c, true);
|
||||
}
|
||||
}
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(c, llvm::DLLImportStorageClass);
|
||||
}
|
||||
ccx.externs().borrow_mut().insert(name.to_string(), c);
|
||||
return c;
|
||||
}
|
||||
|
||||
fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId {
|
||||
match bcx.tcx().lang_items.require(it) {
|
||||
Ok(id) => id,
|
||||
|
|
@ -2714,11 +2684,11 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) {
|
|||
}
|
||||
}
|
||||
|
||||
fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
id: ast::NodeId,
|
||||
ty: Ty<'tcx>,
|
||||
attrs: &[ast::Attribute])
|
||||
-> String {
|
||||
pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
id: ast::NodeId,
|
||||
ty: Ty<'tcx>,
|
||||
attrs: &[ast::Attribute])
|
||||
-> String {
|
||||
match ccx.external_srcs().borrow().get(&id) {
|
||||
Some(&did) => {
|
||||
let sym = ccx.sess().cstore.item_symbol(did);
|
||||
|
|
@ -2768,25 +2738,6 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
let sym = || exported_name(ccx, id, ty, &i.attrs);
|
||||
|
||||
let v = match i.node {
|
||||
hir::ItemStatic(..) => {
|
||||
// If this static came from an external crate, then
|
||||
// we need to get the symbol from metadata instead of
|
||||
// using the current crate's name/version
|
||||
// information in the hash of the symbol
|
||||
let sym = sym();
|
||||
debug!("making {}", sym);
|
||||
|
||||
// Create the global before evaluating the initializer;
|
||||
// this is necessary to allow recursive statics.
|
||||
let llty = type_of(ccx, ty);
|
||||
let g = declare::define_global(ccx, &sym[..], llty).unwrap_or_else(|| {
|
||||
ccx.sess()
|
||||
.span_fatal(i.span, &format!("symbol `{}` is already defined", sym))
|
||||
});
|
||||
|
||||
ccx.item_symbols().borrow_mut().insert(i.id, sym);
|
||||
g
|
||||
}
|
||||
|
||||
hir::ItemFn(_, _, _, abi, _, _) => {
|
||||
let sym = sym();
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
|||
|
||||
// Create the closure.
|
||||
for (i, freevar) in freevars.iter().enumerate() {
|
||||
let datum = expr::trans_local_var(bcx, freevar.def);
|
||||
let datum = expr::trans_var(bcx, freevar.def);
|
||||
let upvar_slot_dest = adt::trans_field_ptr(
|
||||
bcx, &repr, adt::MaybeSizedValue::sized(dest_addr), Disr(0), i);
|
||||
let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
|
||||
|
|
|
|||
|
|
@ -1341,14 +1341,3 @@ pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
_ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_static_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
did: DefId,
|
||||
ty: Ty<'tcx>)
|
||||
-> ValueRef {
|
||||
if let Some(node_id) = ccx.tcx().map.as_local_node_id(did) {
|
||||
base::get_item_val(ccx, node_id)
|
||||
} else {
|
||||
base::get_extern_const(ccx, did, ty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,16 +18,19 @@ use middle::cstore::LOCAL_CRATE;
|
|||
use middle::const_eval::{self, ConstEvalErr};
|
||||
use middle::def::Def;
|
||||
use middle::def_id::DefId;
|
||||
use rustc::front::map as hir_map;
|
||||
use trans::{adt, closure, debuginfo, expr, inline, machine};
|
||||
use trans::base::{self, push_ctxt};
|
||||
use trans::base::{self, exported_name, push_ctxt};
|
||||
use trans::callee::Callee;
|
||||
use trans::collector::{self, TransItem};
|
||||
use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
|
||||
use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
|
||||
use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint};
|
||||
use trans::common::{type_is_fat_ptr, Field, C_vector, C_array, C_null, ExprId, MethodCallKey};
|
||||
use trans::datum::{Datum, Lvalue};
|
||||
use trans::declare;
|
||||
use trans::monomorphize;
|
||||
use trans::foreign;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use trans::value::Value;
|
||||
|
|
@ -46,7 +49,7 @@ use std::ffi::{CStr, CString};
|
|||
use std::borrow::Cow;
|
||||
use libc::c_uint;
|
||||
use syntax::ast::{self, LitKind};
|
||||
use syntax::attr;
|
||||
use syntax::attr::{self, AttrMetaMethods};
|
||||
use syntax::parse::token;
|
||||
use syntax::ptr::P;
|
||||
|
||||
|
|
@ -806,7 +809,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
|
||||
if let Some(Def::Static(def_id, _)) = opt_def {
|
||||
common::get_static_val(cx, def_id, ety)
|
||||
get_static(cx, def_id).val
|
||||
} else {
|
||||
// If this isn't the address of a static, then keep going through
|
||||
// normal constant evaluation.
|
||||
|
|
@ -1013,6 +1016,65 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
|
||||
-> Datum<'tcx, Lvalue> {
|
||||
let ty = ccx.tcx().lookup_item_type(def_id).ty;
|
||||
|
||||
let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) {
|
||||
match ccx.tcx().map.get(id) {
|
||||
hir_map::NodeItem(&hir::Item {
|
||||
ref attrs, span, node: hir::ItemStatic(..), ..
|
||||
}) => {
|
||||
// If this static came from an external crate, then
|
||||
// we need to get the symbol from metadata instead of
|
||||
// using the current crate's name/version
|
||||
// information in the hash of the symbol
|
||||
let sym = exported_name(ccx, id, ty, attrs);
|
||||
debug!("making {}", sym);
|
||||
|
||||
// Create the global before evaluating the initializer;
|
||||
// this is necessary to allow recursive statics.
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| {
|
||||
ccx.sess().span_fatal(span,
|
||||
&format!("symbol `{}` is already defined", sym))
|
||||
});
|
||||
|
||||
ccx.item_symbols().borrow_mut().insert(id, sym);
|
||||
g
|
||||
}
|
||||
|
||||
hir_map::NodeForeignItem(ni @ &hir::ForeignItem {
|
||||
node: hir::ForeignItemStatic(..), ..
|
||||
}) => foreign::register_static(ccx, ni),
|
||||
|
||||
item => unreachable!("get_static: expected static, found {:?}", item)
|
||||
}
|
||||
} else {
|
||||
// FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
|
||||
// FIXME(nagisa): investigate whether it can be changed into define_global
|
||||
let name = ccx.sess().cstore.item_symbol(def_id);
|
||||
let g = declare::declare_global(ccx, &name, type_of::type_of(ccx, ty));
|
||||
// Thread-local statics in some other crate need to *always* be linked
|
||||
// against in a thread-local fashion, so we need to be sure to apply the
|
||||
// thread-local attribute locally if it was present remotely. If we
|
||||
// don't do this then linker errors can be generated where the linker
|
||||
// complains that one object files has a thread local version of the
|
||||
// symbol and another one doesn't.
|
||||
for attr in ccx.tcx().get_attrs(def_id).iter() {
|
||||
if attr.check_name("thread_local") {
|
||||
llvm::set_thread_local(g, true);
|
||||
}
|
||||
}
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(g, llvm::DLLImportStorageClass);
|
||||
}
|
||||
g
|
||||
};
|
||||
|
||||
Datum::new(g, ty, Lvalue::new("static"))
|
||||
}
|
||||
|
||||
pub fn trans_static(ccx: &CrateContext,
|
||||
m: hir::Mutability,
|
||||
expr: &hir::Expr,
|
||||
|
|
@ -1026,7 +1088,8 @@ pub fn trans_static(ccx: &CrateContext,
|
|||
|
||||
unsafe {
|
||||
let _icx = push_ctxt("trans_static");
|
||||
let g = base::get_item_val(ccx, id);
|
||||
let def_id = ccx.tcx().map.local_def_id(id);
|
||||
let datum = get_static(ccx, def_id);
|
||||
|
||||
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
|
||||
let (v, _) = try!(const_expr(
|
||||
|
|
@ -1039,40 +1102,39 @@ pub fn trans_static(ccx: &CrateContext,
|
|||
|
||||
// boolean SSA values are i1, but they have to be stored in i8 slots,
|
||||
// otherwise some LLVM optimization passes don't work as expected
|
||||
let mut val_llty = llvm::LLVMTypeOf(v);
|
||||
let v = if val_llty == Type::i1(ccx).to_ref() {
|
||||
val_llty = Type::i8(ccx).to_ref();
|
||||
llvm::LLVMConstZExt(v, val_llty)
|
||||
let mut val_llty = val_ty(v);
|
||||
let v = if val_llty == Type::i1(ccx) {
|
||||
val_llty = Type::i8(ccx);
|
||||
llvm::LLVMConstZExt(v, val_llty.to_ref())
|
||||
} else {
|
||||
v
|
||||
};
|
||||
|
||||
let ty = ccx.tcx().node_id_to_type(id);
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
let g = if val_llty == llty.to_ref() {
|
||||
g
|
||||
let llty = type_of::type_of(ccx, datum.ty);
|
||||
let g = if val_llty == llty {
|
||||
datum.val
|
||||
} else {
|
||||
// If we created the global with the wrong type,
|
||||
// correct the type.
|
||||
let empty_string = CString::new("").unwrap();
|
||||
let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
|
||||
let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(datum.val));
|
||||
let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
|
||||
llvm::LLVMSetValueName(g, empty_string.as_ptr());
|
||||
llvm::LLVMSetValueName(datum.val, empty_string.as_ptr());
|
||||
let new_g = llvm::LLVMGetOrInsertGlobal(
|
||||
ccx.llmod(), name_string.as_ptr(), val_llty);
|
||||
ccx.llmod(), name_string.as_ptr(), val_llty.to_ref());
|
||||
// To avoid breaking any invariants, we leave around the old
|
||||
// global for the moment; we'll replace all references to it
|
||||
// with the new global later. (See base::trans_crate.)
|
||||
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
|
||||
ccx.statics_to_rauw().borrow_mut().push((datum.val, new_g));
|
||||
new_g
|
||||
};
|
||||
llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
|
||||
llvm::LLVMSetAlignment(g, type_of::align_of(ccx, datum.ty));
|
||||
llvm::LLVMSetInitializer(g, v);
|
||||
|
||||
// As an optimization, all shared statics which do not have interior
|
||||
// mutability are placed into read-only memory.
|
||||
if m != hir::MutMutable {
|
||||
let tcontents = ty.type_contents(ccx.tcx());
|
||||
let tcontents = datum.ty.type_contents(ccx.tcx());
|
||||
if !tcontents.interior_unsafe() {
|
||||
llvm::LLVMSetGlobalConstant(g, llvm::True);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
//! expression and ensures that the result has a cleanup associated with it,
|
||||
//! creating a temporary stack slot if necessary.
|
||||
//!
|
||||
//! - `trans_local_var -> Datum`: looks up a local variable or upvar.
|
||||
//! - `trans_var -> Datum`: looks up a local variable, upvar or static.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
|
|
@ -652,7 +652,8 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
trans(bcx, &e)
|
||||
}
|
||||
hir::ExprPath(..) => {
|
||||
trans_def(bcx, expr, bcx.def(expr.id))
|
||||
let var = trans_var(bcx, bcx.def(expr.id));
|
||||
DatumBlock::new(bcx, var.to_expr_datum())
|
||||
}
|
||||
hir::ExprField(ref base, name) => {
|
||||
trans_rec_field(bcx, &base, name.node)
|
||||
|
|
@ -882,27 +883,40 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
DatumBlock::new(bcx, elt_datum)
|
||||
}
|
||||
|
||||
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
ref_expr: &hir::Expr,
|
||||
def: Def)
|
||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||
//! Translates a reference to a path.
|
||||
/// Translates a reference to a variable.
|
||||
pub fn trans_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: Def)
|
||||
-> Datum<'tcx, Lvalue> {
|
||||
|
||||
let _icx = push_ctxt("trans_def_lvalue");
|
||||
match def {
|
||||
Def::Static(did, _) => {
|
||||
let const_ty = expr_ty(bcx, ref_expr);
|
||||
let val = get_static_val(bcx.ccx(), did, const_ty);
|
||||
let lval = Lvalue::new("expr::trans_def");
|
||||
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
|
||||
Def::Static(did, _) => consts::get_static(bcx.ccx(), did),
|
||||
Def::Upvar(_, nid, _, _) => {
|
||||
// Can't move upvars, so this is never a ZeroMemLastUse.
|
||||
let local_ty = node_id_type(bcx, nid);
|
||||
let lval = Lvalue::new_with_hint("expr::trans_var (upvar)",
|
||||
bcx, nid, HintKind::ZeroAndMaintain);
|
||||
match bcx.fcx.llupvars.borrow().get(&nid) {
|
||||
Some(&val) => Datum::new(val, local_ty, lval),
|
||||
None => {
|
||||
bcx.sess().bug(&format!(
|
||||
"trans_var: no llval for upvar {} found",
|
||||
nid));
|
||||
}
|
||||
}
|
||||
}
|
||||
Def::Local(..) | Def::Upvar(..) => {
|
||||
DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
|
||||
}
|
||||
_ => {
|
||||
bcx.sess().span_bug(ref_expr.span,
|
||||
&format!("{:?} should not reach expr::trans_def", def))
|
||||
Def::Local(_, nid) => {
|
||||
let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
|
||||
Some(&v) => v,
|
||||
None => {
|
||||
bcx.sess().bug(&format!(
|
||||
"trans_var: no datum for local/arg {} found",
|
||||
nid));
|
||||
}
|
||||
};
|
||||
debug!("take_local(nid={}, v={:?}, ty={})",
|
||||
nid, Value(datum.val), datum.ty);
|
||||
datum
|
||||
}
|
||||
_ => unreachable!("{:?} should not reach expr::trans_var", def)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1247,48 +1261,6 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
/// Translates a reference to a local variable or argument. This always results in an lvalue datum.
|
||||
pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
def: Def)
|
||||
-> Datum<'tcx, Lvalue> {
|
||||
let _icx = push_ctxt("trans_local_var");
|
||||
|
||||
match def {
|
||||
Def::Upvar(_, nid, _, _) => {
|
||||
// Can't move upvars, so this is never a ZeroMemLastUse.
|
||||
let local_ty = node_id_type(bcx, nid);
|
||||
let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)",
|
||||
bcx, nid, HintKind::ZeroAndMaintain);
|
||||
match bcx.fcx.llupvars.borrow().get(&nid) {
|
||||
Some(&val) => Datum::new(val, local_ty, lval),
|
||||
None => {
|
||||
bcx.sess().bug(&format!(
|
||||
"trans_local_var: no llval for upvar {} found",
|
||||
nid));
|
||||
}
|
||||
}
|
||||
}
|
||||
Def::Local(_, nid) => {
|
||||
let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
|
||||
Some(&v) => v,
|
||||
None => {
|
||||
bcx.sess().bug(&format!(
|
||||
"trans_local_var: no datum for local/arg {} found",
|
||||
nid));
|
||||
}
|
||||
};
|
||||
debug!("take_local(nid={}, v={:?}, ty={})",
|
||||
nid, Value(datum.val), datum.ty);
|
||||
datum
|
||||
}
|
||||
_ => {
|
||||
bcx.sess().unimpl(&format!(
|
||||
"unsupported def type in trans_local_var: {:?}",
|
||||
def));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
fields: &[hir::Field],
|
||||
base: Option<&hir::Expr>,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use rustc::mir::tcx::LvalueTy;
|
|||
use trans::adt;
|
||||
use trans::base;
|
||||
use trans::common::{self, BlockAndBuilder};
|
||||
use trans::consts;
|
||||
use trans::machine;
|
||||
use trans::type_of;
|
||||
use trans::mir::drop;
|
||||
|
|
@ -89,9 +90,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
mir::Lvalue::Arg(index) => self.args[index as usize],
|
||||
mir::Lvalue::Static(def_id) => {
|
||||
let const_ty = self.mir.lvalue_ty(tcx, lvalue);
|
||||
LvalueRef::new_sized(
|
||||
common::get_static_val(ccx, def_id, const_ty.to_ty(tcx)),
|
||||
const_ty)
|
||||
LvalueRef::new_sized(consts::get_static(ccx, def_id).val, const_ty)
|
||||
},
|
||||
mir::Lvalue::ReturnPointer => {
|
||||
let fn_return_ty = bcx.monomorphize(&self.mir.return_ty);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue