提交 5af3c12c 编写于 作者: E Eduard Burtescu

trans: Move static item handling to consts.

上级 c3f856e7
......@@ -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 @@ fn create_entry_fn(ccx: &CrateContext,
}
}
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::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::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::Local(..) | Def::Upvar(..) => {
DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
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));
}
}
}
_ => {
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 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 @@ pub fn trans_lvalue(&mut self,
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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册