提交 58d4b8ed 编写于 作者: N Niko Matsakis

Modify trans to skip generating `.o` files

This checks the `previous_work_products` data from the dep-graph and
tries to simply copy a `.o` file if possible.  We also add new
work-products into the dep-graph, and create edges to/from the dep-node
for a work-product.
上级 cca48042
......@@ -41,4 +41,6 @@
pub use calculate_svh::SvhCalculate;
pub use persist::load_dep_graph;
pub use persist::save_dep_graph;
pub use persist::save_trans_partition;
pub use persist::save_work_products;
pub use persist::in_incr_comp_dir;
......@@ -19,7 +19,10 @@
mod load;
mod save;
mod util;
mod work_product;
pub use self::load::load_dep_graph;
pub use self::save::save_dep_graph;
pub use self::save::save_work_products;
pub use self::work_product::save_trans_partition;
pub use self::util::in_incr_comp_dir;
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This module contains files for saving intermediate work-products.
use persist::util::*;
use rustc::dep_graph::{WorkProduct, WorkProductId};
use rustc::session::Session;
use std::fs;
use std::path::Path;
use std::sync::Arc;
pub fn save_trans_partition(sess: &Session,
partition_name: &str,
partition_hash: u64,
path_to_obj_file: &Path) {
debug!("save_trans_partition({:?},{},{})",
partition_name,
partition_hash,
path_to_obj_file.display());
if sess.opts.incremental.is_none() {
return;
}
let id = Arc::new(WorkProductId::PartitionObjectFile(partition_name.to_string()));
let file_name = format!("cgu-{}", partition_name);
let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap();
// try to delete the file if it already exists
//
// FIXME(#34955) we can be smarter here -- if we are re-using, no need to do anything
if path_in_incr_dir.exists() {
let _ = fs::remove_file(&path_in_incr_dir);
}
match
fs::hard_link(path_to_obj_file, &path_in_incr_dir)
.or_else(|_| fs::copy(path_to_obj_file, &path_in_incr_dir).map(|_| ()))
{
Ok(_) => {
let work_product = WorkProduct {
input_hash: partition_hash,
file_name: file_name,
};
sess.dep_graph.insert_work_product(&id, work_product);
}
Err(err) => {
sess.warn(&format!("error copying object file `{}` \
to incremental directory as `{}`: {}",
path_to_obj_file.display(),
path_in_incr_dir.display(),
err));
}
}
}
......@@ -10,13 +10,14 @@
use back::lto;
use back::link::{get_linker, remove};
use rustc_incremental::save_trans_partition;
use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
use session::Session;
use session::config::{self, OutputType};
use llvm;
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
use llvm::SMDiagnosticRef;
use {CrateTranslation, ModuleTranslation};
use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
use util::common::time;
use util::common::path2cstr;
use errors::{self, Handler, Level, DiagnosticBuilder};
......@@ -26,6 +27,7 @@
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::str;
use std::sync::{Arc, Mutex};
......@@ -422,10 +424,11 @@ struct HandlerFreeVars<'a> {
// Unsafe due to LLVM calls.
unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
mtrans: ModuleTranslation,
mllvm: ModuleLlvm,
config: ModuleConfig,
output_names: OutputFilenames) {
let llmod = mtrans.llmod;
let llcx = mtrans.llcx;
let llmod = mllvm.llmod;
let llcx = mllvm.llcx;
let tm = config.tm;
// llcx doesn't outlive this function, so we can put this on the stack.
......@@ -628,8 +631,14 @@ unsafe fn with_codegen<F>(tm: TargetMachineRef,
pub fn cleanup_llvm(trans: &CrateTranslation) {
for module in trans.modules.iter() {
unsafe {
llvm::LLVMDisposeModule(module.llmod);
llvm::LLVMContextDispose(module.llcx);
match module.source {
ModuleSource::Translated(llvm) => {
llvm::LLVMDisposeModule(llvm.llmod);
llvm::LLVMContextDispose(llvm.llcx);
}
ModuleSource::Preexisting(_) => {
}
}
}
}
}
......@@ -743,6 +752,13 @@ pub fn run_passes(sess: &Session,
run_work_multithreaded(sess, work_items, num_workers);
}
// If in incr. comp. mode, preserve the `.o` files for potential re-use
for mtrans in trans.modules.iter() {
let path_to_obj = crate_output.temp_path(OutputType::Object, Some(&mtrans.name));
debug!("wrote module {:?} to {:?}", mtrans.name, path_to_obj);
save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &path_to_obj);
}
// All codegen is finished.
unsafe {
llvm::LLVMRustDisposeTargetMachine(tm);
......@@ -913,13 +929,46 @@ fn build_work_item(sess: &Session,
}
}
fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<()> {
let p = p.as_ref();
let q = q.as_ref();
if q.exists() {
try!(fs::remove_file(&q));
}
fs::hard_link(p, q)
.or_else(|_| fs::copy(p, q).map(|_| ()))
}
fn execute_work_item(cgcx: &CodegenContext,
work_item: WorkItem) {
unsafe {
optimize_and_codegen(cgcx,
work_item.mtrans,
work_item.config,
work_item.output_names);
match work_item.mtrans.source {
ModuleSource::Translated(mllvm) => {
debug!("llvm-optimizing {:?}", work_item.mtrans.name);
optimize_and_codegen(cgcx,
work_item.mtrans,
mllvm,
work_item.config,
work_item.output_names);
}
ModuleSource::Preexisting(ref buf) => {
let obj_out = work_item.output_names.temp_path(OutputType::Object,
Some(&work_item.mtrans.name));
debug!("copying pre-existing module `{}` from {} to {}",
work_item.mtrans.name,
buf.display(),
obj_out.display());
match link_or_copy(buf, &obj_out) {
Ok(()) => { }
Err(err) => {
cgcx.handler.err(&format!("unable to copy {} to {}: {}",
buf.display(),
obj_out.display(),
err));
}
}
}
}
}
}
......
......@@ -26,6 +26,8 @@
#![allow(non_camel_case_types)]
use super::CrateTranslation;
use super::ModuleLlvm;
use super::ModuleSource;
use super::ModuleTranslation;
use back::link;
......@@ -43,6 +45,7 @@
use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::util::common::time;
use rustc_incremental::in_incr_comp_dir;
use rustc::mir::mir_map::MirMap;
use rustc_data_structures::graph::OUTGOING;
use session::config::{self, NoDebugInfo, FullDebugInfo};
......@@ -99,6 +102,7 @@
use std::collections::HashMap;
use std::ptr;
use std::rc::Rc;
use std::path::PathBuf;
use std::str;
use std::{i8, i16, i32, i64};
use syntax_pos::{Span, DUMMY_SP};
......@@ -2133,7 +2137,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
let instance = Instance::mono(ccx.shared(), main_def_id);
if !ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance)) {
if !ccx.codegen_unit().contains_item(&TransItem::Fn(instance)) {
// We want to create the wrapper in the same codegen unit as Rust's main
// function.
return;
......@@ -2270,7 +2274,7 @@ fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>,
// Collect all symbols that need to stay externally visible because they
// are referenced via a declaration in some other codegen unit.
for ccx in ccxs.iter() {
for ccx in ccxs.iter_need_trans() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
let linkage = llvm::LLVMGetLinkage(val);
// We only care about external declarations (not definitions)
......@@ -2315,7 +2319,7 @@ fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>,
// Examine each external definition. If the definition is not used in
// any other compilation unit, and is not reachable from other crates,
// then give it internal linkage.
for ccx in ccxs.iter() {
for ccx in ccxs.iter_need_trans() {
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
let linkage = llvm::LLVMGetLinkage(val);
......@@ -2362,7 +2366,7 @@ fn create_imps(cx: &CrateContextList) {
"\x01__imp_"
};
unsafe {
for ccx in cx.iter() {
for ccx in cx.iter_need_trans() {
let exported: Vec<_> = iter_globals(ccx.llmod())
.filter(|&val| {
llvm::LLVMGetLinkage(val) ==
......@@ -2514,8 +2518,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let metadata_module = ModuleTranslation {
name: "metadata".to_string(),
llcx: shared_ccx.metadata_llcx(),
llmod: shared_ccx.metadata_llmod(),
symbol_name_hash: 0, // we always rebuild metadata, at least for now
source: ModuleSource::Translated(ModuleLlvm {
llcx: shared_ccx.metadata_llcx(),
llmod: shared_ccx.metadata_llmod(),
}),
};
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
......@@ -2525,14 +2532,29 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let symbol_map = Rc::new(symbol_map);
let previous_work_products = trans_reuse_previous_work_products(tcx,
&codegen_units,
&symbol_map);
let crate_context_list = CrateContextList::new(&shared_ccx,
codegen_units,
previous_work_products,
symbol_map.clone());
let modules = crate_context_list.iter()
.map(|ccx| ModuleTranslation {
name: String::from(&ccx.codegen_unit().name[..]),
llcx: ccx.llcx(),
llmod: ccx.llmod()
let modules: Vec<_> = crate_context_list.iter_all()
.map(|ccx| {
let source = match ccx.previous_work_product() {
Some(buf) => ModuleSource::Preexisting(buf.clone()),
None => ModuleSource::Translated(ModuleLlvm {
llcx: ccx.llcx(),
llmod: ccx.llmod(),
}),
};
ModuleTranslation {
name: String::from(ccx.codegen_unit().name()),
symbol_name_hash: ccx.codegen_unit().compute_symbol_name_hash(tcx, &symbol_map),
source: source,
}
})
.collect();
......@@ -2551,41 +2573,44 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
// Instantiate translation items without filling out definitions yet...
for ccx in crate_context_list.iter() {
let trans_items = ccx.codegen_unit()
.items_in_deterministic_order(tcx, &symbol_map);
for ccx in crate_context_list.iter_need_trans() {
let cgu = ccx.codegen_unit();
let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map);
for (trans_item, linkage) in trans_items {
trans_item.predefine(&ccx, linkage);
}
tcx.dep_graph.with_task(cgu.work_product_dep_node(), || {
for (trans_item, linkage) in trans_items {
trans_item.predefine(&ccx, linkage);
}
});
}
// ... and now that we have everything pre-defined, fill out those definitions.
for ccx in crate_context_list.iter() {
let trans_items = ccx.codegen_unit()
.items_in_deterministic_order(tcx, &symbol_map);
for (trans_item, _) in trans_items {
trans_item.define(&ccx);
}
for ccx in crate_context_list.iter_need_trans() {
let cgu = ccx.codegen_unit();
let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map);
tcx.dep_graph.with_task(cgu.work_product_dep_node(), || {
for (trans_item, _) in trans_items {
trans_item.define(&ccx);
}
// If this codegen unit contains the main function, also create the
// wrapper here
maybe_create_entry_wrapper(&ccx);
// If this codegen unit contains the main function, also create the
// wrapper here
maybe_create_entry_wrapper(&ccx);
// Run replace-all-uses-with for statics that need it
for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
unsafe {
let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
llvm::LLVMDeleteGlobal(old_g);
// Run replace-all-uses-with for statics that need it
for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
unsafe {
let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
llvm::LLVMDeleteGlobal(old_g);
}
}
}
// Finalize debuginfo
if ccx.sess().opts.debuginfo != NoDebugInfo {
debuginfo::finalize(&ccx);
}
// Finalize debuginfo
if ccx.sess().opts.debuginfo != NoDebugInfo {
debuginfo::finalize(&ccx);
}
});
}
symbol_names_test::report_symbol_names(&shared_ccx);
......@@ -2679,6 +2704,38 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
/// For each CGU, identify if we can reuse an existing object file (or
/// maybe other context).
fn trans_reuse_previous_work_products(tcx: TyCtxt,
codegen_units: &[CodegenUnit],
symbol_map: &SymbolMap)
-> Vec<Option<PathBuf>> {
debug!("trans_reuse_previous_work_products()");
codegen_units
.iter()
.map(|cgu| {
let id = cgu.work_product_id();
let hash = cgu.compute_symbol_name_hash(tcx, symbol_map);
debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash);
if let Some(work_product) = tcx.dep_graph.previous_work_product(&id) {
if work_product.input_hash == hash {
debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
return Some(in_incr_comp_dir(tcx.sess, &work_product.file_name).unwrap());
} else {
debug!("trans_reuse_previous_work_products: \
not reusing {:?} because hash changed to {:?}",
work_product, hash);
}
}
None
})
.collect()
}
fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
-> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
let time_passes = scx.sess().time_passes();
......@@ -2739,10 +2796,10 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
let mut item_to_cgus = HashMap::new();
for cgu in &codegen_units {
for (&trans_item, &linkage) in &cgu.items {
for (&trans_item, &linkage) in cgu.items() {
item_to_cgus.entry(trans_item)
.or_insert(Vec::new())
.push((cgu.name.clone(), linkage));
.push((cgu.name().clone(), linkage));
}
}
......
......@@ -1029,7 +1029,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
assert!(!ccx.external_srcs().borrow().contains_key(&id));
let defined_in_current_codegen_unit = ccx.codegen_unit()
.items
.items()
.contains_key(&TransItem::Static(id));
if defined_in_current_codegen_unit {
if declare::get_declared_value(ccx, sym).is_none() {
......
......@@ -40,6 +40,7 @@
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
use std::path::PathBuf;
use std::marker::PhantomData;
use std::ptr;
use std::rc::Rc;
......@@ -95,6 +96,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
pub struct LocalCrateContext<'tcx> {
llmod: ModuleRef,
llcx: ContextRef,
previous_work_product: Option<PathBuf>,
tn: TypeNames, // FIXME: This seems to be largely unused.
codegen_unit: CodegenUnit<'tcx>,
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
......@@ -198,24 +200,39 @@ pub struct CrateContextList<'a, 'tcx: 'a> {
}
impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> {
pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>,
codegen_units: Vec<CodegenUnit<'tcx>>,
previous_work_products: Vec<Option<PathBuf>>,
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, symbol_map.clone())
local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, path)| {
LocalCrateContext::new(shared_ccx, cgu, path, 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,
}
}
/// 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: 0,
local_ccxs: &self.local_ccxs[..],
filter_to_previous_work_product_unavail: true,
}
}
......@@ -239,24 +256,38 @@ pub struct CrateContextIterator<'a, 'tcx: 'a> {
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);
}
}
}
......@@ -510,6 +541,7 @@ pub fn metadata_symbol_name(&self) -> String {
impl<'tcx> LocalCrateContext<'tcx> {
fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
codegen_unit: CodegenUnit<'tcx>,
previous_work_product: Option<PathBuf>,
symbol_map: Rc<SymbolMap<'tcx>>)
-> LocalCrateContext<'tcx> {
unsafe {
......@@ -521,7 +553,7 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
// 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[..]);
......@@ -535,6 +567,7 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
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()),
......@@ -694,6 +727,10 @@ pub fn llcx(&self) -> ContextRef {
self.local().llcx
}
pub fn previous_work_product(&self) -> Option<&PathBuf> {
self.local().previous_work_product.as_ref()
}
pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> {
&self.local().codegen_unit
}
......
......@@ -239,7 +239,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
Falling back to on-demand instantiation.",
g,
TransItem::DropGlue(g).to_raw_string(),
ccx.codegen_unit().name);
ccx.codegen_unit().name());
ccx.stats().n_fallback_instantiations.set(ccx.stats()
.n_fallback_instantiations
......
......@@ -37,6 +37,8 @@
#![feature(unicode)]
#![feature(question_mark)]
use std::path::PathBuf;
extern crate arena;
extern crate flate;
extern crate getopts;
......@@ -133,6 +135,18 @@ pub mod back {
#[derive(Clone)]
pub struct ModuleTranslation {
pub name: String,
pub symbol_name_hash: u64,
pub source: ModuleSource,
}
#[derive(Clone)]
pub enum ModuleSource {
Preexisting(PathBuf),
Translated(ModuleLlvm),
}
#[derive(Copy, Clone)]
pub struct ModuleLlvm {
pub llcx: llvm::ContextRef,
pub llmod: llvm::ModuleRef,
}
......
......@@ -52,7 +52,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("leaving monomorphic fn {:?}", instance);
return (val, mono_ty);
} else {
assert!(!ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance)));
assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
}
debug!("monomorphic_fn({:?})", instance);
......
......@@ -119,12 +119,15 @@
use collector::InliningMap;
use llvm;
use monomorphize;
use rustc::dep_graph::{DepNode, WorkProductId};
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathData;
use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
use rustc::ty::TyCtxt;
use rustc::ty::item_path::characteristic_def_id_of_type;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher, SipHasher};
use std::sync::Arc;
use symbol_map::SymbolMap;
use syntax::ast::NodeId;
use syntax::parse::token::{self, InternedString};
......@@ -140,11 +143,54 @@ pub enum PartitioningStrategy {
}
pub struct CodegenUnit<'tcx> {
pub name: InternedString,
pub items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>,
name: InternedString,
items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>,
}
impl<'tcx> CodegenUnit<'tcx> {
pub fn new(name: InternedString,
items: FnvHashMap<TransItem<'tcx>, llvm::Linkage>)
-> Self {
CodegenUnit {
name: name,
items: items,
}
}
pub fn empty(name: InternedString) -> Self {
Self::new(name, FnvHashMap())
}
pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool {
self.items.contains_key(item)
}
pub fn name(&self) -> &str {
&self.name
}
pub fn items(&self) -> &FnvHashMap<TransItem<'tcx>, llvm::Linkage> {
&self.items
}
pub fn work_product_id(&self) -> Arc<WorkProductId> {
Arc::new(WorkProductId::PartitionObjectFile(self.name().to_string()))
}
pub fn work_product_dep_node(&self) -> DepNode<DefId> {
DepNode::WorkProduct(self.work_product_id())
}
pub fn compute_symbol_name_hash(&self, tcx: TyCtxt, symbol_map: &SymbolMap) -> u64 {
let mut state = SipHasher::new();
let all_items = self.items_in_deterministic_order(tcx, symbol_map);
for (item, _) in all_items {
let symbol_name = symbol_map.get(item).unwrap();
symbol_name.hash(&mut state);
}
state.finish()
}
pub fn items_in_deterministic_order(&self,
tcx: TyCtxt,
symbol_map: &SymbolMap)
......@@ -277,10 +323,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
let make_codegen_unit = || {
CodegenUnit {
name: codegen_unit_name.clone(),
items: FnvHashMap(),
}
CodegenUnit::empty(codegen_unit_name.clone())
};
let mut codegen_unit = codegen_units.entry(codegen_unit_name.clone())
......@@ -319,10 +362,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if codegen_units.is_empty() {
let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT);
codegen_units.entry(codegen_unit_name.clone())
.or_insert_with(|| CodegenUnit {
name: codegen_unit_name.clone(),
items: FnvHashMap(),
});
.or_insert_with(|| CodegenUnit::new(codegen_unit_name.clone(),
FnvHashMap()));
}
PreInliningPartitioning {
......@@ -362,10 +403,8 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
// we reach the target count
while codegen_units.len() < target_cgu_count {
let index = codegen_units.len();
codegen_units.push(CodegenUnit {
name: numbered_codegen_unit_name(crate_name, index),
items: FnvHashMap()
});
codegen_units.push(
CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index)));
}
}
......@@ -381,10 +420,8 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
follow_inlining(*root, inlining_map, &mut reachable);
}
let mut new_codegen_unit = CodegenUnit {
name: codegen_unit.name.clone(),
items: FnvHashMap(),
};
let mut new_codegen_unit =
CodegenUnit::empty(codegen_unit.name.clone());
// Add all translation items that are not already there
for trans_item in reachable {
......@@ -560,10 +597,9 @@ fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
items.insert(trans_item, linkage);
}
CodegenUnit {
name: numbered_codegen_unit_name(&tcx.crate_name[..], 0),
items: items
}
CodegenUnit::new(
numbered_codegen_unit_name(&tcx.crate_name[..], 0),
items)
}
fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
......
......@@ -23,12 +23,12 @@
use llvm;
use monomorphize::{self, Instance};
use inline;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst;
use rustc::dep_graph::DepNode;
use rustc_const_eval::fatal_const_eval_err;
use std::hash::{Hash, Hasher};
use syntax::ast::{self, NodeId};
......@@ -68,16 +68,27 @@ fn hash<H: Hasher>(&self, s: &mut H) {
impl<'a, 'tcx> TransItem<'tcx> {
pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
ccx.codegen_unit().name);
ccx.codegen_unit().name());
// (*) This code executes in the context of a dep-node for the
// entire CGU. In some cases, we introduce dep-nodes for
// particular items that we are translating (these nodes will
// have read edges coming into the CGU node). These smaller
// nodes are not needed for correctness -- we always
// invalidate an entire CGU at a time -- but they enable
// finer-grained testing, since you can write tests that check
// that the incoming edges to a particular fn are from a
// particular set.
self.register_reads(ccx);
match *self {
TransItem::Static(node_id) => {
let def_id = ccx.tcx().map.local_def_id(node_id);
let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*)
let item = ccx.tcx().map.expect_item(node_id);
if let hir::ItemStatic(_, m, ref expr) = item.node {
match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
......@@ -93,6 +104,13 @@ pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
}
}
TransItem::Fn(instance) => {
let _task;
if instance.def.is_local() {
_task = ccx.tcx().dep_graph.in_task(
DepNode::TransCrateItem(instance.def)); // (*)
}
base::trans_instance(&ccx, instance);
}
TransItem::DropGlue(dg) => {
......@@ -103,7 +121,7 @@ pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
debug!("END IMPLEMENTING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
ccx.codegen_unit().name);
ccx.codegen_unit().name());
}
/// If necessary, creates a subtask for trans'ing a particular item and registers reads on
......@@ -152,7 +170,7 @@ pub fn predefine(&self,
debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
ccx.codegen_unit().name);
ccx.codegen_unit().name());
let symbol_name = ccx.symbol_map()
.get_or_compute(ccx.shared(), *self);
......@@ -174,7 +192,7 @@ pub fn predefine(&self,
debug!("END PREDEFINING '{} ({})' in cgu {}",
self.to_string(ccx.tcx()),
self.to_raw_string(),
ccx.codegen_unit().name);
ccx.codegen_unit().name());
}
fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
......
......@@ -20,6 +20,7 @@
extern crate rustc_resolve;
extern crate rustc_errors;
extern crate rustc_errors as errors;
extern crate rustc_trans;
#[macro_use] extern crate syntax;
use std::ffi::{CStr, CString};
......@@ -37,6 +38,7 @@
use rustc_driver::{driver, abort_on_err};
use rustc_resolve::MakeGlobMap;
use rustc_metadata::cstore::CStore;
use rustc_trans::ModuleSource;
use libc::c_void;
use rustc_errors::registry::Registry;
......@@ -261,7 +263,10 @@ fn compile_program(input: &str, sysroot: PathBuf)
.filter_map(|(_, p)| p).collect();
assert_eq!(trans.modules.len(), 1);
let llmod = trans.modules[0].llmod;
let llmod = match trans.modules[0].source {
ModuleSource::Preexisting(_) => unimplemented!(),
ModuleSource::Translated(llvm) => llvm.llmod,
};
// Workaround because raw pointers do not impl Send
let modp = llmod as usize;
......
......@@ -13,11 +13,13 @@
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_llvm;
extern crate rustc_trans;
#[macro_use] extern crate syntax;
extern crate getopts;
use rustc_driver::{CompilerCalls, Compilation};
use rustc_driver::driver::CompileController;
use rustc_trans::ModuleSource;
use rustc::session::Session;
use syntax::codemap::FileLoader;
use std::io;
......@@ -51,7 +53,10 @@ fn build_controller(&mut self,
state.session.abort_if_errors();
let trans = state.trans.unwrap();
assert_eq!(trans.modules.len(), 1);
let rs_llmod = trans.modules[0].llmod;
let rs_llmod = match trans.modules[0].source {
ModuleSource::Preexisting(_) => unimplemented!(),
ModuleSource::Translated(llvm) => llvm.llmod,
};
unsafe { rustc_llvm::LLVMDumpModule(rs_llmod) };
});
cc
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册