use llvm;
use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef};
-use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig};
+use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct};
use middle::cstore::LinkMeta;
use rustc::hir::def::ExportMap;
use rustc::hir::def_id::DefId;
use monomorphize::Instance;
use partitioning::CodegenUnit;
-use collector::TransItemState;
use trans_item::TransItem;
use type_::{Type, TypeNames};
use rustc::ty::subst::{Substs, VecPerParamSpace};
use rustc::ty::{self, Ty, TyCtxt};
use session::config::NoDebugInfo;
use session::Session;
+use session::config;
+use symbol_map::SymbolMap;
use util::sha2::Sha256;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
use std::str;
use syntax::ast;
use syntax::parse::token::InternedString;
+use abi::FnType;
pub struct Stats {
pub n_glues_created: Cell<usize>,
pub n_null_glues: Cell<usize>,
pub n_real_glues: Cell<usize>,
+ pub n_fallback_instantiations: Cell<usize>,
pub n_fns: Cell<usize>,
pub n_monos: Cell<usize>,
pub n_inlines: Cell<usize>,
mir_map: &'a MirMap<'tcx>,
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
- available_monomorphizations: RefCell<FnvHashSet<String>>,
- available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
use_dll_storage_attrs: bool,
- translation_items: RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>>,
+ translation_items: RefCell<FnvHashSet<TransItem<'tcx>>>,
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
}
pub struct LocalCrateContext<'tcx> {
llmod: ModuleRef,
llcx: ContextRef,
+ previous_work_product: Option<WorkProduct>,
tn: TypeNames, // FIXME: This seems to be largely unused.
codegen_unit: CodegenUnit<'tcx>,
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
- drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>,
+ drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, (ValueRef, FnType)>>,
/// Track mapping of external ids to local items imported for inlining
external: RefCell<DefIdMap<Option<ast::NodeId>>>,
/// Backwards version of the `external` map (inlined items to where they
/// Depth of the current type-of computation - used to bail out
type_of_depth: Cell<usize>,
+
+ symbol_map: Rc<SymbolMap<'tcx>>,
}
// Implement DepTrackingMapConfig for `trait_cache`
}
impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> {
-
pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>,
- codegen_units: Vec<CodegenUnit<'tcx>>)
+ codegen_units: Vec<CodegenUnit<'tcx>>,
+ previous_work_products: Vec<Option<WorkProduct>>,
+ symbol_map: Rc<SymbolMap<'tcx>>)
-> CrateContextList<'a, 'tcx> {
CrateContextList {
shared: shared_ccx,
- local_ccxs: codegen_units.into_iter().map(|codegen_unit| {
- LocalCrateContext::new(shared_ccx, codegen_unit)
+ local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, wp)| {
+ LocalCrateContext::new(shared_ccx, cgu, wp, symbol_map.clone())
}).collect()
}
}
- pub fn iter<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
+ /// Iterate over all crate contexts, whether or not they need
+ /// translation. That is, whether or not a `.o` file is available
+ /// for re-use from a previous incr. comp.).
+ pub fn iter_all<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
CrateContextIterator {
shared: self.shared,
index: 0,
- local_ccxs: &self.local_ccxs[..]
+ local_ccxs: &self.local_ccxs[..],
+ filter_to_previous_work_product_unavail: false,
}
}
- pub fn get_ccx<'b>(&'b self, index: usize) -> CrateContext<'b, 'tcx> {
- CrateContext {
+ /// Iterator over all CCX that need translation (cannot reuse results from
+ /// previous incr. comp.).
+ pub fn iter_need_trans<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
+ CrateContextIterator {
shared: self.shared,
- index: index,
+ index: 0,
local_ccxs: &self.local_ccxs[..],
+ filter_to_previous_work_product_unavail: true,
}
}
shared: &'a SharedCrateContext<'a, 'tcx>,
local_ccxs: &'a [LocalCrateContext<'tcx>],
index: usize,
+
+ /// if true, only return results where `previous_work_product` is none
+ filter_to_previous_work_product_unavail: bool,
}
impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
type Item = CrateContext<'a, 'tcx>;
fn next(&mut self) -> Option<CrateContext<'a, 'tcx>> {
- if self.index >= self.local_ccxs.len() {
- return None;
- }
+ loop {
+ if self.index >= self.local_ccxs.len() {
+ return None;
+ }
- let index = self.index;
- self.index += 1;
+ let index = self.index;
+ self.index += 1;
- Some(CrateContext {
- shared: self.shared,
- index: index,
- local_ccxs: self.local_ccxs,
- })
+ let ccx = CrateContext {
+ shared: self.shared,
+ index: index,
+ local_ccxs: self.local_ccxs,
+ };
+
+ if
+ self.filter_to_previous_work_product_unavail &&
+ ccx.previous_work_product().is_some()
+ {
+ continue;
+ }
+
+ return Some(ccx);
+ }
}
}
}
}
+pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode {
+ let reloc_model_arg = match sess.opts.cg.relocation_model {
+ Some(ref s) => &s[..],
+ None => &sess.target.target.options.relocation_model[..],
+ };
+
+ match reloc_model_arg {
+ "pic" => llvm::RelocPIC,
+ "static" => llvm::RelocStatic,
+ "default" => llvm::RelocDefault,
+ "dynamic-no-pic" => llvm::RelocDynamicNoPic,
+ _ => {
+ sess.err(&format!("{:?} is not a valid relocation mode",
+ sess.opts
+ .cg
+ .relocation_model));
+ sess.abort_if_errors();
+ bug!();
+ }
+ }
+}
+
+fn is_any_library(sess: &Session) -> bool {
+ sess.crate_types.borrow().iter().any(|ty| {
+ *ty != config::CrateTypeExecutable
+ })
+}
+
+pub fn is_pie_binary(sess: &Session) -> bool {
+ !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocPIC
+}
+
unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
let llcx = llvm::LLVMContextCreate();
let mod_name = CString::new(mod_name).unwrap();
let llvm_target = sess.target.target.llvm_target.as_bytes();
let llvm_target = CString::new(llvm_target).unwrap();
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
+
+ if is_pie_binary(sess) {
+ llvm::LLVMRustSetModulePIELevel(llmod);
+ }
+
(llcx, llmod)
}
n_glues_created: Cell::new(0),
n_null_glues: Cell::new(0),
n_real_glues: Cell::new(0),
+ n_fallback_instantiations: Cell::new(0),
n_fns: Cell::new(0),
n_monos: Cell::new(0),
n_inlines: Cell::new(0),
},
check_overflow: check_overflow,
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
- available_monomorphizations: RefCell::new(FnvHashSet()),
- available_drop_glues: RefCell::new(FnvHashMap()),
use_dll_storage_attrs: use_dll_storage_attrs,
- translation_items: RefCell::new(FnvHashMap()),
+ translation_items: RefCell::new(FnvHashSet()),
trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
}
}
}
}
- pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
+ pub fn translation_items(&self) -> &RefCell<FnvHashSet<TransItem<'tcx>>> {
&self.translation_items
}
impl<'tcx> LocalCrateContext<'tcx> {
fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
- codegen_unit: CodegenUnit<'tcx>)
+ codegen_unit: CodegenUnit<'tcx>,
+ previous_work_product: Option<WorkProduct>,
+ symbol_map: Rc<SymbolMap<'tcx>>)
-> LocalCrateContext<'tcx> {
unsafe {
// Append ".rs" to LLVM module identifier.
// crashes if the module identifier is same as other symbols
// such as a function name in the module.
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
- let llmod_id = format!("{}.rs", codegen_unit.name);
+ let llmod_id = format!("{}.rs", codegen_unit.name());
let (llcx, llmod) = create_context_and_module(&shared.tcx.sess,
&llmod_id[..]);
let dbg_cx = if shared.tcx.sess.opts.debuginfo != NoDebugInfo {
- Some(debuginfo::CrateDebugContext::new(llmod))
+ let dctx = debuginfo::CrateDebugContext::new(llmod);
+ debuginfo::metadata::compile_unit_metadata(shared, &dctx, shared.tcx.sess);
+ Some(dctx)
} else {
None
};
let local_ccx = LocalCrateContext {
llmod: llmod,
llcx: llcx,
+ previous_work_product: previous_work_product,
codegen_unit: codegen_unit,
tn: TypeNames::new(),
needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()),
intrinsics: RefCell::new(FnvHashMap()),
n_llvm_insns: Cell::new(0),
type_of_depth: Cell::new(0),
+ symbol_map: symbol_map,
};
let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
self.local().llcx
}
+ pub fn previous_work_product(&self) -> Option<&WorkProduct> {
+ self.local().previous_work_product.as_ref()
+ }
+
pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> {
&self.local().codegen_unit
}
&self.local().fn_pointer_shims
}
- pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>> {
+ pub fn drop_glues<'a>(&'a self)
+ -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, (ValueRef, FnType)>> {
&self.local().drop_glues
}
&self.shared.stats
}
- pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> {
- &self.shared.available_monomorphizations
- }
-
- pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> {
- &self.shared.available_drop_glues
- }
-
pub fn int_type(&self) -> Type {
self.local().int_type
}
self.shared.get_mir(def_id)
}
- pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
- &self.shared.translation_items
+ pub fn symbol_map(&self) -> &SymbolMap<'tcx> {
+ &*self.local().symbol_map
}
- pub fn record_translation_item_as_generated(&self, cgi: TransItem<'tcx>) {
- if self.sess().opts.debugging_opts.print_trans_items.is_none() {
- return;
- }
-
- let mut codegen_items = self.translation_items().borrow_mut();
-
- if codegen_items.contains_key(&cgi) {
- codegen_items.insert(cgi, TransItemState::PredictedAndGenerated);
- } else {
- codegen_items.insert(cgi, TransItemState::NotPredictedButGenerated);
- }
+ pub fn translation_items(&self) -> &RefCell<FnvHashSet<TransItem<'tcx>>> {
+ &self.shared.translation_items
}
/// Given the def-id of some item that has no type parameters, make
ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p);
ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p);
- // Some intrinsics were introduced in later versions of LLVM, but they have
- // fallbacks in libc or libm and such.
- macro_rules! compatible_ifn {
- ($name:expr, noop($cname:ident ($($arg:expr),*) -> void), $llvm_version:expr) => (
- if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
- // The `if key == $name` is already in ifn!
- ifn!($name, fn($($arg),*) -> void);
- } else if key == $name {
- let f = declare::declare_cfn(ccx, stringify!($cname),
- Type::func(&[$($arg),*], &void));
- llvm::SetLinkage(f, llvm::InternalLinkage);
-
- let bld = ccx.builder();
- let llbb = unsafe {
- llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), f,
- "entry-block\0".as_ptr() as *const _)
- };
-
- bld.position_at_end(llbb);
- bld.ret_void();
-
- ccx.intrinsics().borrow_mut().insert($name, f.clone());
- return Some(f);
- }
- );
- ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr, $llvm_version:expr) => (
- if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
- // The `if key == $name` is already in ifn!
- ifn!($name, fn($($arg),*) -> $ret);
- } else if key == $name {
- let f = declare::declare_cfn(ccx, stringify!($cname),
- Type::func(&[$($arg),*], &$ret));
- ccx.intrinsics().borrow_mut().insert($name, f.clone());
- return Some(f);
- }
- )
- }
-
- compatible_ifn!("llvm.assume", noop(llvmcompat_assume(i1) -> void), 6);
+ ifn!("llvm.assume", fn(i1) -> void);
if ccx.sess().opts.debuginfo != NoDebugInfo {
ifn!("llvm.dbg.declare", fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);