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.
This commit is contained in:
parent
cca4804251
commit
58d4b8edd3
14 changed files with 388 additions and 101 deletions
|
|
@ -41,4 +41,6 @@ pub use assert_dep_graph::assert_dep_graph;
|
|||
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 hash;
|
|||
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;
|
||||
|
|
|
|||
61
src/librustc_incremental/persist/work_product.rs
Normal file
61
src/librustc_incremental/persist/work_product.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// 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 syntax_pos::MultiSpan;
|
|||
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 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
|
|||
// 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 optimize_and_codegen(cgcx: &CodegenContext,
|
|||
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::ty::adjustment::CustomCoerceUnsized;
|
|||
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::cell::{Cell, RefCell};
|
|||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize debuginfo
|
||||
if ccx.sess().opts.debuginfo != NoDebugInfo {
|
||||
debuginfo::finalize(&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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
|
|||
|
||||
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 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);
|
||||
}
|
||||
|
||||
let index = self.index;
|
||||
self.index += 1;
|
||||
|
||||
Some(CrateContext {
|
||||
shared: self.shared,
|
||||
index: index,
|
||||
local_ccxs: self.local_ccxs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -510,6 +541,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
|||
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 @@ impl<'tcx> LocalCrateContext<'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 @@ impl<'tcx> LocalCrateContext<'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 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
|||
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 @@ mod value;
|
|||
#[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 glue::DropGlueKind;
|
|||
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 @@ impl<'tcx> Hash for TransItem<'tcx> {
|
|||
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 @@ impl<'a, 'tcx> TransItem<'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 @@ impl<'a, 'tcx> TransItem<'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 @@ impl<'a, 'tcx> TransItem<'tcx> {
|
|||
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 @@ impl<'a, 'tcx> TransItem<'tcx> {
|
|||
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_metadata;
|
|||
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::session::build_session;
|
|||
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 @@ impl<'a> CompilerCalls<'a> for JitCalls {
|
|||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue