From b337c21322dfb011ca5586474184db4d4904fd14 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 9 Jul 2018 15:58:25 +0200 Subject: [PATCH 1/8] Provide a way of accessing the ThinLTO module import map in rustc. --- src/librustc_codegen_llvm/back/lto.rs | 69 ++++++++++++++++++++++++++- src/librustc_llvm/ffi.rs | 8 ++++ src/rustllvm/PassWrapper.cpp | 56 ++++++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index a33f8b569d0a8..28b9d2e7afa25 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -20,12 +20,13 @@ use rustc::hir::def_id::LOCAL_CRATE; use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; use rustc::util::common::time_ext; +use rustc_data_structures::fx::FxHashMap; use time_graph::Timeline; use {ModuleCodegen, ModuleLlvm, ModuleKind, ModuleSource}; use libc; -use std::ffi::CString; +use std::ffi::{CString, CStr}; use std::ptr; use std::slice; use std::sync::Arc; @@ -776,3 +777,69 @@ impl ThinModule { Ok(module) } } + + +#[derive(Debug)] +pub struct ThinLTOImports { + // key = llvm name of importing module, value = list of modules it imports from + imports: FxHashMap>, +} + +impl ThinLTOImports { + + /// Load the ThinLTO import map from ThinLTOData. + unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports { + let raw_data: *const llvm::ThinLTOModuleImports = + llvm::LLVMRustGetThinLTOModuleImports(data); + + assert!(!raw_data.is_null()); + + let mut imports = FxHashMap(); + let mut module_ptr = raw_data; + let mut module_index = 0; + + loop { + let mut entry_ptr: *const llvm::ThinLTOModuleName = *module_ptr; + + if entry_ptr.is_null() { + break; + } + + let importing_module_name = CStr::from_ptr(*entry_ptr) + .to_str() + .expect("Non-utf8 LLVM module name encountered") + .to_owned(); + + entry_ptr = entry_ptr.offset(1); + + let mut imported_modules = vec![]; + + loop { + let imported_module_name = *entry_ptr; + + if imported_module_name.is_null() { + break + } + + let imported_module_name = CStr::from_ptr(imported_module_name) + .to_str() + .expect("Non-utf8 LLVM module name encountered") + .to_owned(); + + imported_modules.push(imported_module_name); + entry_ptr = entry_ptr.offset(1); + } + + imports.insert(importing_module_name, imported_modules); + + module_ptr = module_ptr.offset(1); + module_index += 1; + } + + assert_eq!(module_index, imports.len()); + + ThinLTOImports { + imports + } + } +} diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 0497de940ca15..b3a3893bfc3e7 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -350,6 +350,11 @@ pub enum ThinLTOData {} /// LLVMRustThinLTOBuffer pub enum ThinLTOBuffer {} +/// LLVMRustThinLTOModuleName +pub type ThinLTOModuleName = *const c_char; +/// LLVMRustThinLTOModuleImports +pub type ThinLTOModuleImports = *const ThinLTOModuleName; + /// LLVMRustThinLTOModule #[repr(C)] pub struct ThinLTOModule { @@ -1778,6 +1783,9 @@ extern "C" { Data: *const ThinLTOData, Module: ModuleRef, ) -> bool; + pub fn LLVMRustGetThinLTOModuleImports( + Data: *const ThinLTOData, + ) -> *const ThinLTOModuleImports; pub fn LLVMRustFreeThinLTOData(Data: *mut ThinLTOData); pub fn LLVMRustParseBitcodeForThinLTO( Context: ContextRef, diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a00ff3b345d11..30f585efedc12 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -798,6 +798,11 @@ LLVMRustPGOAvailable() { #endif } +// We encode the ThinLTO module import map as a nested null-terminated list to +// get it into Rust. +typedef const char* LLVMRustThinLTOModuleName; +typedef LLVMRustThinLTOModuleName* LLVMRustThinLTOModuleImports; + #if LLVM_VERSION_GE(4, 0) // Here you'll find an implementation of ThinLTO as used by the Rust compiler @@ -1099,6 +1104,52 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { return true; } +/// Converts the LLVMRustThinLTOData::ImportLists map into a nested list. The +/// first level is a null-terminated array with an entry for each module. Each +/// entry is a pointer that points to a null-termined array of module names. The +/// first entry is always the name of the *importing* module, the following +/// entries are the names of the modules it imports from. Each module name is +/// a regular C string. +extern "C" LLVMRustThinLTOModuleImports* +LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *Data) { + // Allocate number of module +1. This is a null-terminated array. + LLVMRustThinLTOModuleImports* thinLTOModuleImports = + new LLVMRustThinLTOModuleImports[Data->ImportLists.size() + 1]; + size_t module_index = 0; + + for (const auto & module : Data->ImportLists) { + StringRef module_id = module.getKey(); + const auto& imports = module.getValue(); + + // Allocate number of imported module + 2, one extra for the name of the + // importing module and another one for null-termination. + LLVMRustThinLTOModuleImports imports_array = + new LLVMRustThinLTOModuleName[imports.size() + 2]; + + // The first value is always the name of the *importing* module. + imports_array[0] = strndup(module_id.data(), module_id.size()); + + size_t imports_array_index = 1; + for (const auto imported_module_id : imports.keys()) { + // The following values are the names of the imported modules. + imports_array[imports_array_index] = strndup(imported_module_id.data(), + imported_module_id.size()); + imports_array_index += 1; + } + + assert(imports_array_index == imports.size() + 1); + imports_array[imports_array_index] = nullptr; + + thinLTOModuleImports[module_index] = imports_array; + module_index += 1; + } + + assert(module_index == Data->ImportLists.size()); + thinLTOModuleImports[module_index] = nullptr; + + return thinLTOModuleImports; +} + // This struct and various functions are sort of a hack right now, but the // problem is that we've got in-memory LLVM modules after we generate and // optimize all codegen-units for one compilation in rustc. To be compatible @@ -1280,6 +1331,11 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { report_fatal_error("ThinLTO not available"); } +extern "C" LLVMRustThinLTOModuleImports +LLVMRustGetLLVMRustThinLTOModuleImports(const LLVMRustThinLTOData *Data) { + report_fatal_error("ThinLTO not available"); +} + extern "C" void LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) { report_fatal_error("ThinLTO not available"); From 5868bd53fec99124161f85de44203b4ad63ed48d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 9 Jul 2018 17:00:24 +0200 Subject: [PATCH 2/8] Persist ThinLTO import data in incr. comp. session directory. --- src/librustc_codegen_llvm/back/lto.rs | 83 ++++++++++++++++++++++++- src/librustc_codegen_llvm/base.rs | 24 ++++++- src/librustc_codegen_llvm/lib.rs | 2 +- src/librustc_incremental/lib.rs | 1 + src/librustc_incremental/persist/mod.rs | 1 + 5 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 28b9d2e7afa25..ef03e76f94682 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -27,10 +27,16 @@ use {ModuleCodegen, ModuleLlvm, ModuleKind, ModuleSource}; use libc; use std::ffi::{CString, CStr}; +use std::fs::File; +use std::io; +use std::mem; +use std::path::Path; use std::ptr; use std::slice; use std::sync::Arc; +pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-imports.bin"; + pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { match crate_type { config::CrateTypeExecutable | @@ -194,7 +200,7 @@ pub(crate) fn run(cgcx: &CodegenContext, } Lto::Thin | Lto::ThinLocal => { - thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline) + thin_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline) } Lto::No => unreachable!(), } @@ -347,7 +353,8 @@ impl Drop for Linker { /// calculating the *index* for ThinLTO. This index will then be shared amongst /// all of the `LtoModuleCodegen` units returned below and destroyed once /// they all go out of scope. -fn thin_lto(diag_handler: &Handler, +fn thin_lto(cgcx: &CodegenContext, + diag_handler: &Handler, modules: Vec, serialized_modules: Vec<(SerializedModule, CString)>, symbol_white_list: &[*const libc::c_char], @@ -425,6 +432,18 @@ fn thin_lto(diag_handler: &Handler, let msg = format!("failed to prepare thin LTO context"); return Err(write::llvm_err(&diag_handler, msg)) } + + // Save the ThinLTO import information for incremental compilation. + if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir { + let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME); + let imports = ThinLTOImports::from_thin_lto_data(data); + if let Err(err) = imports.save_to_file(&path) { + let msg = format!("Error while writing ThinLTO import data: {}", + err); + return Err(write::llvm_err(&diag_handler, msg)); + } + } + let data = ThinData(data); info!("thin LTO data created"); timeline.record("data"); @@ -787,6 +806,12 @@ pub struct ThinLTOImports { impl ThinLTOImports { + pub fn new_empty() -> ThinLTOImports { + ThinLTOImports { + imports: FxHashMap(), + } + } + /// Load the ThinLTO import map from ThinLTOData. unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports { let raw_data: *const llvm::ThinLTOModuleImports = @@ -842,4 +867,58 @@ impl ThinLTOImports { imports } } + + pub fn save_to_file(&self, path: &Path) -> io::Result<()> { + use std::io::Write; + + let file = File::create(path)?; + let mut writer = io::BufWriter::new(file); + + for (importing_module_name, imported_modules) in &self.imports { + writeln!(writer, "{}", importing_module_name)?; + + for imported_module in imported_modules { + writeln!(writer, " {}", imported_module)?; + } + + writeln!(writer)?; + } + + Ok(()) + } + + pub fn load_from_file(path: &Path) -> io::Result { + use std::io::BufRead; + + let mut imports = FxHashMap(); + let mut current_module = None; + let mut current_imports = vec![]; + + let file = File::open(path)?; + + for line in io::BufReader::new(file).lines() { + let line = line?; + + if line.is_empty() { + let importing_module = current_module + .take() + .expect("Importing module not set"); + + imports.insert(importing_module, + mem::replace(&mut current_imports, vec![])); + } else if line.starts_with(" ") { + // This is an imported module + assert_ne!(current_module, None); + current_imports.push(line.trim().to_string()); + } else { + // This is the beginning of a new module + assert_eq!(current_module, None); + current_module = Some(line.trim().to_string()); + } + } + + Ok(ThinLTOImports { + imports + }) + } } diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index ea26e271c9bb3..9a625720f4d09 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -29,7 +29,7 @@ use super::ModuleCodegen; use super::ModuleKind; use abi; -use back::link; +use back::{link, lto}; use back::write::{self, OngoingCodegen, create_target_machine}; use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; @@ -1370,6 +1370,27 @@ mod temp_stable_hash_impls { } } +#[allow(unused)] +fn load_thin_lto_imports(sess: &Session) -> lto::ThinLTOImports { + let path = rustc_incremental::in_incr_comp_dir_sess( + sess, + lto::THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME + ); + + if !path.exists() { + return lto::ThinLTOImports::new_empty(); + } + + match lto::ThinLTOImports::load_from_file(&path) { + Ok(imports) => imports, + Err(e) => { + let msg = format!("Error while trying to load ThinLTO import data \ + for incremental compilation: {}", e); + sess.fatal(&msg) + } + } +} + pub fn define_custom_section(cx: &CodegenCx, def_id: DefId) { use rustc::mir::interpret::GlobalId; @@ -1408,3 +1429,4 @@ pub fn define_custom_section(cx: &CodegenCx, def_id: DefId) { ); } } + diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 8aa7902021f24..e575c7ad68491 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -90,7 +90,7 @@ mod back { mod command; pub mod linker; pub mod link; - mod lto; + pub mod lto; pub mod symbol_export; pub mod write; mod rpath; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 3839c133a6eb2..cc560ed4580d6 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -42,6 +42,7 @@ pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir; pub use persist::save_dep_graph; pub use persist::save_work_product_index; pub use persist::in_incr_comp_dir; +pub use persist::in_incr_comp_dir_sess; pub use persist::prepare_session_directory; pub use persist::finalize_session_directory; pub use persist::delete_workproduct_files; diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index e1f00db56d5cb..17d36ba3fa7f4 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -23,6 +23,7 @@ mod file_format; pub use self::fs::finalize_session_directory; pub use self::fs::garbage_collect_session_directories; pub use self::fs::in_incr_comp_dir; +pub use self::fs::in_incr_comp_dir_sess; pub use self::fs::prepare_session_directory; pub use self::load::dep_graph_tcx_init; pub use self::load::load_dep_graph; From e8c7cdda7a91b41f8b0906433de609fdbd25fbe2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 10 Jul 2018 19:16:22 +0200 Subject: [PATCH 3/8] Clean up CodegenUnit name generation. --- src/librustc/mir/mono.rs | 79 ++++++++++++++++++- src/librustc/session/mod.rs | 9 +++ .../assert_module_sources.rs | 53 +++++++++++-- src/librustc_mir/monomorphize/partitioning.rs | 68 ++++++---------- .../issue-39828/auxiliary/generic.rs | 2 +- 5 files changed, 154 insertions(+), 57 deletions(-) diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 79566fbbc11a4..5ca0dda754557 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -8,15 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum}; use syntax::ast::NodeId; -use syntax::symbol::InternedString; +use syntax::symbol::{Symbol, InternedString}; use ty::{Instance, TyCtxt}; use util::nodemap::FxHashMap; use rustc_data_structures::base_n; use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult, StableHasher}; use ich::{Fingerprint, StableHashingContext, NodeIdHashingMode}; +use std::fmt; use std::hash::Hash; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] @@ -173,6 +174,80 @@ impl<'tcx> CodegenUnit<'tcx> { self.size_estimate = Some(size_estimate + delta); } } + + /// CGU names should fulfill the following requirements: + /// - They should be able to act as a file name on any kind of file system + /// - They should not collide with other CGU names, even for different versions + /// of the same crate. + /// + /// Consequently, we don't use special characters except for '.' and '-' and we + /// prefix each name with the crate-name and crate-disambiguator. + /// + /// This function will build CGU names of the form: + /// + /// ``` + /// .(-)*[.] + /// ``` + /// + /// The '.' before `` makes sure that names with a special + /// suffix can never collide with a name built out of regular Rust + /// identifiers (e.g. module paths). + pub fn build_cgu_name(tcx: TyCtxt, + cnum: CrateNum, + components: I, + special_suffix: Option) + -> InternedString + where I: IntoIterator, + C: fmt::Display, + S: fmt::Display, + { + let cgu_name = CodegenUnit::build_cgu_name_no_mangle(tcx, + cnum, + components, + special_suffix); + + if tcx.sess.opts.debugging_opts.human_readable_cgu_names { + cgu_name + } else { + let cgu_name = &cgu_name.as_str()[..]; + Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str() + } + } + + /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the + /// resulting name. + pub fn build_cgu_name_no_mangle(tcx: TyCtxt, + cnum: CrateNum, + components: I, + special_suffix: Option) + -> InternedString + where I: IntoIterator, + C: fmt::Display, + S: fmt::Display, + { + use std::fmt::Write; + + let mut cgu_name = String::with_capacity(64); + + // Start out with the crate name and disambiguator + write!(cgu_name, + "{}.{}", + tcx.crate_name(cnum), + tcx.crate_disambiguator(cnum)).unwrap(); + + // Add the components + for component in components { + write!(cgu_name, "-{}", component).unwrap(); + } + + if let Some(special_suffix) = special_suffix { + // We add a dot in here so it cannot clash with anything in a regular + // Rust identifier + write!(cgu_name, ".{}", special_suffix).unwrap(); + } + + Symbol::intern(&cgu_name[..]).as_interned_str() + } } impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index ad1df0a1348c5..c28b49756f096 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -26,6 +26,7 @@ use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use util::common::ProfileQueriesMsg; +use rustc_data_structures::base_n; use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock}; use syntax::ast::NodeId; @@ -1185,6 +1186,14 @@ impl CrateDisambiguator { } } +impl fmt::Display for CrateDisambiguator { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let (a, b) = self.0.as_value(); + let as_u128 = a as u128 | ((b as u128) << 64); + f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE)) + } +} + impl From for CrateDisambiguator { fn from(fingerprint: Fingerprint) -> CrateDisambiguator { CrateDisambiguator(fingerprint) diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index df8e0f056afc9..f6e9ee7b22560 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -27,11 +27,11 @@ //! the HIR doesn't change as a result of the annotations, which might //! perturb the reuse results. +use rustc::hir::def_id::LOCAL_CRATE; use rustc::dep_graph::{DepNode, DepConstructor}; use rustc::mir::mono::CodegenUnit; use rustc::ty::TyCtxt; use syntax::ast; -use syntax_pos::symbol::Symbol; use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED}; const MODULE: &'static str = "module"; @@ -72,12 +72,37 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { return; } - let mname = self.field(attr, MODULE); - let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str()); - let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_interned_str(); + let user_path = self.field(attr, MODULE).as_str().to_string(); + let crate_name = self.tcx.crate_name(LOCAL_CRATE).as_str().to_string(); + + if !user_path.starts_with(&crate_name) { + let msg = format!("Found malformed codegen unit name `{}`. \ + Codegen units names must always start with the name of the \ + crate (`{}` in this case).", user_path, crate_name); + self.tcx.sess.span_fatal(attr.span, &msg); + } + + // Split of the "special suffix" if there is one. + let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind(".") { + (&user_path[..index], Some(&user_path[index + 1 ..])) + } else { + (&user_path[..], None) + }; + + let mut cgu_path_components = user_path.split("-").collect::>(); + + // Remove the crate name + assert_eq!(cgu_path_components.remove(0), crate_name); + + let cgu_name = CodegenUnit::build_cgu_name(self.tcx, + LOCAL_CRATE, + cgu_path_components, + cgu_special_suffix); + + debug!("mapping '{}' to cgu name '{}'", self.field(attr, MODULE), cgu_name); let dep_node = DepNode::new(self.tcx, - DepConstructor::CompileCodegenUnit(mangled_cgu_name)); + DepConstructor::CompileCodegenUnit(cgu_name)); if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) { match (disposition, loaded_from_cache) { @@ -85,13 +110,13 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { self.tcx.sess.span_err( attr.span, &format!("expected module named `{}` to be Reused but is Codegened", - mname)); + user_path)); } (Disposition::Codegened, true) => { self.tcx.sess.span_err( attr.span, &format!("expected module named `{}` to be Codegened but is Reused", - mname)); + user_path)); } (Disposition::Reused, true) | (Disposition::Codegened, false) => { @@ -99,7 +124,19 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { } } } else { - self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname)); + let available_cgus = self.tcx + .collect_and_partition_mono_items(LOCAL_CRATE) + .1 + .iter() + .map(|cgu| format!("{}", cgu.name())) + .collect::>() + .join(", "); + + self.tcx.sess.span_err(attr.span, + &format!("no module named `{}` (mangled: {}).\nAvailable modules: {}", + user_path, + cgu_name, + available_cgus)); } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 5f15870d6fbc3..73b430bc04112 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -104,7 +104,7 @@ use monomorphize::collector::InliningMap; use rustc::dep_graph::WorkProductId; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::DefPathData; use rustc::mir::mono::{Linkage, Visibility}; use rustc::middle::exported_symbols::SymbolExportLevel; @@ -114,7 +114,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use std::collections::hash_map::Entry; use std::cmp; use syntax::ast::NodeId; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::InternedString; use rustc::mir::mono::MonoItem; use monomorphize::item::{MonoItemExt, InstantiationMode}; @@ -204,16 +204,9 @@ impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> { // Anything we can't find a proper codegen unit for goes into this. fn fallback_cgu_name(tcx: TyCtxt) -> InternedString { - const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; - - if tcx.sess.opts.debugging_opts.human_readable_cgu_names { - Symbol::intern(FALLBACK_CODEGEN_UNIT).as_interned_str() - } else { - Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_interned_str() - } + CodegenUnit::build_cgu_name(tcx, LOCAL_CRATE, &["fallback"], Some("cgu")) } - pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mono_items: I, strategy: PartitioningStrategy, @@ -224,8 +217,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_mono_items(tcx, - mono_items); + let mut initial_partitioning = place_root_mono_items(tcx, mono_items); initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx)); @@ -234,7 +226,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // If the partitioning should produce a fixed count of codegen units, merge // until that count is reached. if let PartitioningStrategy::FixedUnitCount(count) = strategy { - merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str()); + merge_codegen_units(tcx, &mut initial_partitioning, count); debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } @@ -328,7 +320,7 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let codegen_unit = codegen_units.entry(codegen_unit_name.clone()) - .or_insert_with(make_codegen_unit); + .or_insert_with(make_codegen_unit); let mut can_be_internalized = true; let default_visibility = |id: DefId, is_generic: bool| { @@ -491,9 +483,9 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, - crate_name: &str) { +fn merge_codegen_units<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, + initial_partitioning: &mut PreInliningPartitioning<'tcx>, + target_cgu_count: usize) { assert!(target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; @@ -522,7 +514,7 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< } for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.set_name(numbered_codegen_unit_name(crate_name, index)); + cgu.set_name(numbered_codegen_unit_name(tcx, index)); } } @@ -727,42 +719,26 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, volatile: bool) -> InternedString { - // Unfortunately we cannot just use the `ty::item_path` infrastructure here - // because we need paths to modules and the DefIds of those are not - // available anymore for external items. - let mut cgu_name = String::with_capacity(64); - let def_path = tcx.def_path(def_id); - cgu_name.push_str(&tcx.crate_name(def_path.krate).as_str()); - - for part in tcx.def_path(def_id) - .data - .iter() - .take_while(|part| { - match part.data { - DefPathData::Module(..) => true, - _ => false, - } - }) { - cgu_name.push_str("-"); - cgu_name.push_str(&part.data.as_interned_str().as_str()); - } - if volatile { - cgu_name.push_str(".volatile"); - } + let components = def_path.data.iter().take_while(|part| { + match part.data { + DefPathData::Module(..) => true, + _ => false, + } + }).map(|part| part.data.as_interned_str()); - let cgu_name = if tcx.sess.opts.debugging_opts.human_readable_cgu_names { - cgu_name + let volatile_suffix = if volatile { + Some("volatile") } else { - CodegenUnit::mangle_name(&cgu_name) + None }; - Symbol::intern(&cgu_name[..]).as_interned_str() + CodegenUnit::build_cgu_name(tcx, def_path.krate, components, volatile_suffix) } -fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { - Symbol::intern(&format!("{}{}", crate_name, index)).as_interned_str() +fn numbered_codegen_unit_name(tcx: TyCtxt, index: usize) -> InternedString { + CodegenUnit::build_cgu_name_no_mangle(tcx, LOCAL_CRATE, &["cgu"], Some(index)) } fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/test/incremental/issue-39828/auxiliary/generic.rs b/src/test/incremental/issue-39828/auxiliary/generic.rs index a562eab1768f3..5491827af8a35 100644 --- a/src/test/incremental/issue-39828/auxiliary/generic.rs +++ b/src/test/incremental/issue-39828/auxiliary/generic.rs @@ -11,7 +11,7 @@ // revisions:rpass1 rpass2 // compile-flags: -Z query-dep-graph -#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")] +#![rustc_partition_reused(module="generic-fallback.cgu", cfg="rpass2")] #![feature(rustc_attrs)] #![crate_type="rlib"] From 7cd1fdcaf3ee0743c6d064be623021bdf259ea60 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 10 Jul 2018 19:43:58 +0200 Subject: [PATCH 4/8] Clean up LLVM module naming (just use CodegenUnit names). --- src/librustc_codegen_llvm/back/link.rs | 7 --- src/librustc_codegen_llvm/back/lto.rs | 11 ++-- src/librustc_codegen_llvm/back/write.rs | 3 +- src/librustc_codegen_llvm/base.rs | 78 ++++++++++--------------- src/librustc_codegen_llvm/context.rs | 5 +- src/librustc_codegen_llvm/lib.rs | 4 +- 6 files changed, 39 insertions(+), 69 deletions(-) diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index a7f0910a6fccc..9e45da4cb6859 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -45,13 +45,6 @@ use std::process::{Output, Stdio}; use std::str; use syntax::attr; -/// The LLVM module name containing crate-metadata. This includes a `.` on -/// purpose, so it cannot clash with the name of a user-defined module. -pub const METADATA_MODULE_NAME: &'static str = "crate.metadata"; - -// same as for metadata above, but for allocator shim -pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator"; - pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target, invalid_output_for_target, build_link_meta, out_filename, check_file_is_writeable}; diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index ef03e76f94682..a68f22b2651f9 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -238,7 +238,7 @@ fn fat_lto(cgcx: &CodegenContext, .expect("must be codegen'ing at least one module"); let module = modules.remove(costliest_module); let llmod = module.llvm().expect("can't lto pre-codegened modules").llmod; - info!("using {:?} as a base module", module.llmod_id); + info!("using {:?} as a base module", module.name); // For all other modules we codegened we'll need to link them into our own // bitcode. All modules were codegened in their own LLVM context, however, @@ -248,7 +248,7 @@ fn fat_lto(cgcx: &CodegenContext, for module in modules { let llvm = module.llvm().expect("can't lto pre-codegened modules"); let buffer = ModuleBuffer::new(llvm.llmod); - let llmod_id = CString::new(&module.llmod_id[..]).unwrap(); + let llmod_id = CString::new(&module.name[..]).unwrap(); serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); } @@ -376,9 +376,9 @@ fn thin_lto(cgcx: &CodegenContext, // the most expensive portion of this small bit of global // analysis! for (i, module) in modules.iter().enumerate() { - info!("local module: {} - {}", i, module.llmod_id); + info!("local module: {} - {}", i, module.name); let llvm = module.llvm().expect("can't lto precodegened module"); - let name = CString::new(module.llmod_id.clone()).unwrap(); + let name = CString::new(module.name.clone()).unwrap(); let buffer = ThinBuffer::new(llvm.llmod); thin_modules.push(llvm::ThinLTOModule { identifier: name.as_ptr(), @@ -387,7 +387,7 @@ fn thin_lto(cgcx: &CodegenContext, }); thin_buffers.push(buffer); module_names.push(name); - timeline.record(&module.llmod_id); + timeline.record(&module.name); } // FIXME: All upstream crates are deserialized internally in the @@ -676,7 +676,6 @@ impl ThinModule { llcx, tm, }), - llmod_id: self.name().to_string(), name: self.name().to_string(), kind: ModuleKind::Regular, }; diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 467782518f673..99daf4b0ed62d 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -696,7 +696,7 @@ unsafe fn codegen(cgcx: &CodegenContext, if config.emit_bc_compressed { let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); - let data = bytecode::encode(&module.llmod_id, data); + let data = bytecode::encode(&module.name, data); if let Err(e) = fs::write(&dst, data) { diag_handler.err(&format!("failed to write bytecode: {}", e)); } @@ -1308,7 +1308,6 @@ fn execute_work_item(cgcx: &CodegenContext, assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed); Ok(WorkItemResult::Compiled(CompiledModule { - llmod_id: module.llmod_id.clone(), name: module_name, kind: ModuleKind::Regular, pre_existing: true, diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 9a625720f4d09..603ee78585ea6 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -739,15 +739,18 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let link_meta = link::build_link_meta(crate_hash); // Codegen the metadata. - let llmod_id = "metadata"; + let metadata_cgu_name = CodegenUnit::build_cgu_name(tcx, + LOCAL_CRATE, + &["crate"], + Some("metadata")).as_str() + .to_string(); let (metadata_llcx, metadata_llmod, metadata) = time(tcx.sess, "write metadata", || { - write_metadata(tcx, llmod_id, &link_meta) + write_metadata(tcx, &metadata_cgu_name, &link_meta) }); let metadata_module = ModuleCodegen { - name: link::METADATA_MODULE_NAME.to_string(), - llmod_id: llmod_id.to_string(), + name: metadata_cgu_name, source: ModuleSource::Codegened(ModuleLlvm { llcx: metadata_llcx, llmod: metadata_llmod, @@ -810,26 +813,30 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Codegen an allocator shim, if any let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() { - unsafe { - let llmod_id = "allocator"; - let (llcx, llmod) = - context::create_context_and_module(tcx.sess, llmod_id); - let modules = ModuleLlvm { - llmod, - llcx, - tm: create_target_machine(tcx.sess, false), - }; - time(tcx.sess, "write allocator module", || { + let llmod_id = CodegenUnit::build_cgu_name(tcx, + LOCAL_CRATE, + &["crate"], + Some("allocator")).as_str() + .to_string(); + let (llcx, llmod) = unsafe { + context::create_context_and_module(tcx.sess, &llmod_id) + }; + let modules = ModuleLlvm { + llmod, + llcx, + tm: create_target_machine(tcx.sess, false), + }; + time(tcx.sess, "write allocator module", || { + unsafe { allocator::codegen(tcx, &modules, kind) - }); + } + }); - Some(ModuleCodegen { - name: link::ALLOCATOR_MODULE_NAME.to_string(), - llmod_id: llmod_id.to_string(), - source: ModuleSource::Codegened(modules), - kind: ModuleKind::Allocator, - }) - } + Some(ModuleCodegen { + name: llmod_id, + source: ModuleSource::Codegened(modules), + kind: ModuleKind::Allocator, + }) } else { None }; @@ -872,21 +879,10 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // succeed it means that none of the dependencies has changed // and we can safely re-use. if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) { - // Append ".rs" to LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // 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", cgu.name()); - let module = ModuleCodegen { name: cgu.name().to_string(), source: ModuleSource::Preexisting(buf), kind: ModuleKind::Regular, - llmod_id, }; tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); write::submit_codegened_module_to_llvm(tcx, module, 0); @@ -1195,21 +1191,8 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let cgu_name = cgu.name().to_string(); - // Append ".rs" to LLVM module identifier. - // - // LLVM code generator emits a ".file filename" directive - // for ELF backends. Value of the "filename" is set as the - // LLVM module identifier. Due to a LLVM MC bug[1], LLVM - // 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", - cgu.name(), - tcx.crate_disambiguator(LOCAL_CRATE) - .to_fingerprint().to_hex()); - // Instantiate monomorphizations without filling out definitions yet... - let cx = CodegenCx::new(tcx, cgu, &llmod_id); + let cx = CodegenCx::new(tcx, cgu); let module = { let mono_items = cx.codegen_unit .items_in_deterministic_order(cx.tcx); @@ -1267,7 +1250,6 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: cgu_name, source: ModuleSource::Codegened(llvm_module), kind: ModuleKind::Regular, - llmod_id, } }; diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index b774d7c5def21..80187f939b452 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -214,8 +214,7 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont impl<'a, 'tcx> CodegenCx<'a, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - codegen_unit: Arc>, - llmod_id: &str) + codegen_unit: Arc>) -> CodegenCx<'a, 'tcx> { // An interesting part of Windows which MSVC forces our hand on (and // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` @@ -268,7 +267,7 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { unsafe { let (llcx, llmod) = create_context_and_module(&tcx.sess, - &llmod_id[..]); + &codegen_unit.name().as_str()); let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo { let dctx = debuginfo::CrateDebugContext::new(llmod); diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index e575c7ad68491..af3a512c37620 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -258,8 +258,8 @@ struct ModuleCodegen { /// unique amongst **all** crates. Therefore, it should contain /// something unique to this crate (e.g., a module path) as well /// as the crate name and disambiguator. + /// We currently generate these names via CodegenUnit::build_cgu_name(). name: String, - llmod_id: String, source: ModuleSource, kind: ModuleKind, } @@ -306,7 +306,6 @@ impl ModuleCodegen { }; CompiledModule { - llmod_id: self.llmod_id, name: self.name.clone(), kind: self.kind, pre_existing, @@ -320,7 +319,6 @@ impl ModuleCodegen { #[derive(Debug)] struct CompiledModule { name: String, - llmod_id: String, kind: ModuleKind, pre_existing: bool, object: Option, From 25ea9f544a1e6e6d1c1beb277985ebf6aef7f8fa Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Jul 2018 10:44:13 +0200 Subject: [PATCH 5/8] Adapt codegen-unit tests to new CGU naming scheme. --- .../drop_in_place_intrinsic.rs | 6 ++-- .../item-collection/generic-drop-glue.rs | 12 +++---- .../instantiation-through-vtable.rs | 4 +-- .../item-collection/non-generic-drop-glue.rs | 4 +-- .../item-collection/transitive-drop-glue.rs | 18 +++++----- .../item-collection/tuple-drop-glue.rs | 8 ++--- .../codegen-units/item-collection/unsizing.rs | 8 ++--- src/tools/compiletest/src/runtest.rs | 33 ++++++++++++++++--- 8 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs index 49e4b8d43c19c..cec88f1c6a245 100644 --- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -14,7 +14,7 @@ #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic-cgu.0[Internal] struct StructWithDtor(u32); impl Drop for StructWithDtor { @@ -26,7 +26,7 @@ impl Drop for StructWithDtor { #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic-cgu.0[Internal] let x = [StructWithDtor(0), StructWithDtor(1)]; drop_slice_in_place(&x); @@ -40,7 +40,7 @@ fn drop_slice_in_place(x: &[StructWithDtor]) { // This is the interesting thing in this test case: Normally we would // not have drop-glue for the unsized [StructWithDtor]. This has to be // generated though when the drop_in_place() intrinsic is used. - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic-cgu.0[Internal] ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]); } } diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs index aad32d1eb7c06..5afa519bc5902 100644 --- a/src/test/codegen-units/item-collection/generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs @@ -47,7 +47,7 @@ enum EnumNoDrop { struct NonGenericNoDrop(i32); struct NonGenericWithDrop(i32); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue-cgu.0[Internal] impl Drop for NonGenericWithDrop { //~ MONO_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] @@ -57,11 +57,11 @@ impl Drop for NonGenericWithDrop { //~ MONO_ITEM fn generic_drop_glue::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] let _ = StructWithDrop { x: 0i8, y: 'a' }.x; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; @@ -70,17 +70,17 @@ fn start(_: isize, _: *const *const u8) -> isize { // This is supposed to generate drop-glue because it contains a field that // needs to be dropped. - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; - //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue0[Internal] + //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index 5c6201da252be..d09d343a8458e 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -34,13 +34,13 @@ impl Trait for Struct { fn start(_: isize, _: *const *const u8) -> isize { let s1 = Struct { _a: 0u32 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable-cgu.0[Internal] //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable-cgu.0[Internal] //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs index 6ca24aa5b4b89..a939dd56cda5b 100644 --- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs @@ -15,7 +15,7 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue-cgu.0[Internal] struct StructWithDrop { x: i32 } @@ -29,7 +29,7 @@ struct StructNoDrop { x: i32 } -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue-cgu.0[Internal] enum EnumWithDrop { A(i32) } diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs index d20213c109bdb..7bbc9b6d0fbc9 100644 --- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs +++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs @@ -15,11 +15,11 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] struct Root(Intermediate); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] struct Intermediate(Leaf); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] struct Leaf; impl Drop for Leaf { @@ -40,15 +40,15 @@ impl Drop for LeafGen { fn start(_: isize, _: *const *const u8) -> isize { let _ = Root(Intermediate(Leaf)); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0u32))); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0i16))); diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs index 9e4cc6ea6f08e..865570ccfa55a 100644 --- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs +++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs @@ -15,7 +15,7 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue0[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue-cgu.0[Internal] struct Dropped; impl Drop for Dropped { @@ -26,11 +26,11 @@ impl Drop for Dropped { //~ MONO_ITEM fn tuple_drop_glue::start[0] #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue-cgu.0[Internal] let x = (0u32, Dropped); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue-cgu.0[Internal] let x = (0i16, (Dropped, true)); 0 diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index adc0eb6c70915..5e9a3258c7adf 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -59,13 +59,13 @@ impl, U: ?Sized> CoerceUnsized> for Wrapper fn start(_: isize, _: *const *const u8) -> isize { // simple case let bool_sized = &true; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn unsizing::{{impl}}[0]::foo[0] let _bool_unsized = bool_sized as &Trait; let char_sized = &'a'; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn unsizing::{{impl}}[1]::foo[0] let _char_unsized = char_sized as &Trait; @@ -75,13 +75,13 @@ fn start(_: isize, _: *const *const u8) -> isize { _b: 2, _c: 3.0f64 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn unsizing::{{impl}}[2]::foo[0] let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing0[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 59ddc16715d3b..e5fb472afd635 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2209,12 +2209,12 @@ impl<'test> TestCx<'test> { .stdout .lines() .filter(|line| line.starts_with(PREFIX)) - .map(str_to_mono_item) + .map(|line| str_to_mono_item(line, true)) .collect(); let expected: Vec = errors::load_errors(&self.testpaths.file, None) .iter() - .map(|e| str_to_mono_item(&e.msg[..])) + .map(|e| str_to_mono_item(&e.msg[..], false)) .collect(); let mut missing = Vec::new(); @@ -2299,14 +2299,14 @@ impl<'test> TestCx<'test> { } // [MONO_ITEM] name [@@ (cgu)+] - fn str_to_mono_item(s: &str) -> MonoItem { + fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem { let s = if s.starts_with(PREFIX) { (&s[PREFIX.len()..]).trim() } else { s.trim() }; - let full_string = format!("{}{}", PREFIX, s.trim().to_owned()); + let full_string = format!("{}{}", PREFIX, s); let parts: Vec<&str> = s .split(CGU_MARKER) @@ -2323,7 +2323,13 @@ impl<'test> TestCx<'test> { .split(' ') .map(str::trim) .filter(|s| !s.is_empty()) - .map(str::to_owned) + .map(|s| { + if cgu_has_crate_disambiguator { + remove_crate_disambiguator_from_cgu(s) + } else { + s.to_string() + } + }) .collect() } else { HashSet::new() @@ -2348,6 +2354,23 @@ impl<'test> TestCx<'test> { string } + + fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String { + // The first '.' is the start of the crate disambiguator + let disambiguator_start = cgu.find('.') + .expect("Could not find start of crate disambiguator in CGU spec"); + + // The first non-alphanumeric character is the end of the disambiguator + let disambiguator_end = cgu[disambiguator_start + 1 ..] + .find(|c| !char::is_alphanumeric(c)) + .expect("Could not find end of crate disambiguator in CGU spec") + + disambiguator_start + 1; + + let mut result = cgu[0 .. disambiguator_start].to_string(); + result.push_str(&cgu[disambiguator_end ..]); + + result + } } fn init_incremental_test(&self) { From 78226236c7e14eeb8ec282da565293d66366a272 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Jul 2018 14:59:50 +0200 Subject: [PATCH 6/8] Fix some run-make tests after object file naming has changed. --- src/test/run-make-fulldeps/cross-lang-lto/Makefile | 8 ++++---- .../extra-filename-with-temp-outputs/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/run-make-fulldeps/cross-lang-lto/Makefile b/src/test/run-make-fulldeps/cross-lang-lto/Makefile index efe1b7072ffb8..dbd0116e5e378 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto/Makefile @@ -17,22 +17,22 @@ all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib staticlib: lib.rs $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib.a $(call EXTRACT_OBJS, liblib.a) - $(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib.lib0.rcgu.o + for file in $(TMPDIR)/liblib.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done staticlib-fat-lto: lib.rs $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-fat-lto.a -Clto=fat $(call EXTRACT_OBJS, liblib-fat-lto.a) - $(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib-fat-lto.lib0.rcgu.o + for file in $(TMPDIR)/liblib-fat-lto.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done staticlib-thin-lto: lib.rs $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-thin-lto.a -Clto=thin $(call EXTRACT_OBJS, liblib-thin-lto.a) - $(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib-thin-lto.lib0.rcgu.o + for file in $(TMPDIR)/liblib-thin-lto.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done rlib: lib.rs $(BUILD_LIB) --crate-type=rlib -o $(TMPDIR)/liblib.rlib $(call EXTRACT_OBJS, liblib.rlib) - $(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib.lib0.rcgu.o + for file in $(TMPDIR)/liblib.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done cdylib: lib.rs $(BUILD_LIB) --crate-type=cdylib --emit=obj -o $(TMPDIR)/cdylib.o diff --git a/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile b/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile index 6de4f97df0c16..e46390a9d0cd7 100644 --- a/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile +++ b/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile @@ -2,5 +2,5 @@ all: $(RUSTC) -C extra-filename=bar foo.rs -C save-temps - rm $(TMPDIR)/foobar.foo0.rcgu.o + rm $(TMPDIR)/foobar.foo*0.rcgu.o rm $(TMPDIR)/$(call BIN,foobar) From 81daa487daea9162d602c63e0e2200207cb84348 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 13 Jul 2018 10:15:29 +0200 Subject: [PATCH 7/8] Change LLVMRustGetThinLTOModuleImports() so it also works with LLVM 4. --- src/rustllvm/PassWrapper.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 30f585efedc12..6e10af9762dbf 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -1117,7 +1117,7 @@ LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *Data) { new LLVMRustThinLTOModuleImports[Data->ImportLists.size() + 1]; size_t module_index = 0; - for (const auto & module : Data->ImportLists) { + for (const auto& module : Data->ImportLists) { StringRef module_id = module.getKey(); const auto& imports = module.getValue(); @@ -1130,7 +1130,8 @@ LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *Data) { imports_array[0] = strndup(module_id.data(), module_id.size()); size_t imports_array_index = 1; - for (const auto imported_module_id : imports.keys()) { + for (const auto& imported_module : imports) { + StringRef imported_module_id = imported_module.getKey(); // The following values are the names of the imported modules. imports_array[imports_array_index] = strndup(imported_module_id.data(), imported_module_id.size()); From 4e28b6cbd3fd65eff38ae30a9d2b00404da1e0e1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 10 Jul 2018 10:39:06 +0200 Subject: [PATCH 8/8] Use ThinLTO import information when doing incremental compilation. --- src/librustc/dep_graph/graph.rs | 115 ++++++++---- src/librustc/session/config.rs | 2 +- src/librustc/session/mod.rs | 5 - src/librustc/ty/query/config.rs | 6 - src/librustc/ty/query/mod.rs | 3 +- src/librustc_codegen_llvm/back/lto.rs | 4 + src/librustc_codegen_llvm/base.rs | 167 ++++++++++++------ src/librustc_mir/monomorphize/partitioning.rs | 6 +- src/tools/compiletest/src/runtest.rs | 3 + 9 files changed, 212 insertions(+), 99 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 2390d7eccce76..04f71bd1e0664 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -204,13 +204,31 @@ impl DepGraph { where C: DepGraphSafe + StableHashingContextProvider<'gcx>, R: HashStable>, { - self.with_task_impl(key, cx, arg, false, task, + self.with_task_impl(key, cx, arg, false, true, task, |key| OpenTask::Regular(Lock::new(RegularOpenTask { node: key, reads: SmallVec::new(), read_set: FxHashSet(), })), - |data, key, task| data.borrow_mut().complete_task(key, task)) + |data, key, task| data.borrow_mut().complete_task(key, task, false)) + } + + pub fn with_forced_task<'gcx, C, A, R>(&self, + key: DepNode, + cx: C, + arg: A, + task: fn(C, A) -> R) + -> (R, DepNodeIndex) + where C: DepGraphSafe + StableHashingContextProvider<'gcx>, + R: HashStable>, + { + self.with_task_impl(key, cx, arg, false, false, task, + |key| OpenTask::Regular(Lock::new(RegularOpenTask { + node: key, + reads: SmallVec::new(), + read_set: FxHashSet(), + })), + |data, key, task| data.borrow_mut().complete_task(key, task, true)) } /// Creates a new dep-graph input with value `input` @@ -226,7 +244,7 @@ impl DepGraph { arg } - self.with_task_impl(key, cx, input, true, identity_fn, + self.with_task_impl(key, cx, input, true, true, identity_fn, |_| OpenTask::Ignore, |data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new())) } @@ -237,6 +255,7 @@ impl DepGraph { cx: C, arg: A, no_tcx: bool, + do_fingerprinting: bool, task: fn(C, A) -> R, create_task: fn(DepNode) -> OpenTask, finish_task_and_alloc_depnode: fn(&Lock, @@ -282,41 +301,58 @@ impl DepGraph { let dep_node_index = finish_task_and_alloc_depnode(&data.current, key, open_task); - let mut stable_hasher = StableHasher::new(); - result.hash_stable(&mut hcx, &mut stable_hasher); + if do_fingerprinting { + let mut stable_hasher = StableHasher::new(); + result.hash_stable(&mut hcx, &mut stable_hasher); - let current_fingerprint = stable_hasher.finish(); + let current_fingerprint = stable_hasher.finish(); - // Store the current fingerprint - { - let mut fingerprints = self.fingerprints.borrow_mut(); + // Store the current fingerprint + { + let mut fingerprints = self.fingerprints.borrow_mut(); + + if dep_node_index.index() >= fingerprints.len() { + fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO); + } - if dep_node_index.index() >= fingerprints.len() { - fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO); + debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO, + "DepGraph::with_task() - Duplicate fingerprint \ + insertion for {:?}", key); + fingerprints[dep_node_index] = current_fingerprint; } - debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO, - "DepGraph::with_task() - Duplicate fingerprint \ - insertion for {:?}", key); - fingerprints[dep_node_index] = current_fingerprint; - } + // Determine the color of the new DepNode. + if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - // Determine the color of the new DepNode. - if let Some(prev_index) = data.previous.node_to_index_opt(&key) { - let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); + let color = if current_fingerprint == prev_fingerprint { + DepNodeColor::Green(dep_node_index) + } else { + DepNodeColor::Red + }; - let color = if current_fingerprint == prev_fingerprint { - DepNodeColor::Green(dep_node_index) - } else { - DepNodeColor::Red - }; + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_index).is_none(), + "DepGraph::with_task() - Duplicate DepNodeColor \ + insertion for {:?}", key); + + colors.insert(prev_index, color); + } + } else { + // Always store a ZERO fingerprint + { + let mut fingerprints = self.fingerprints.borrow_mut(); - let mut colors = data.colors.borrow_mut(); - debug_assert!(colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor \ - insertion for {:?}", key); + if dep_node_index.index() >= fingerprints.len() { + fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO); + } + + fingerprints[dep_node_index] = Fingerprint::ZERO; + } - colors.insert(prev_index, color); + if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + data.colors.borrow_mut().insert(prev_index, DepNodeColor::Red); + } } (result, dep_node_index) @@ -378,7 +414,7 @@ impl DepGraph { } /// Execute something within an "eval-always" task which is a task - // that runs whenever anything changes. + /// that runs whenever anything changes. pub fn with_eval_always_task<'gcx, C, A, R>(&self, key: DepNode, cx: C, @@ -388,7 +424,7 @@ impl DepGraph { where C: DepGraphSafe + StableHashingContextProvider<'gcx>, R: HashStable>, { - self.with_task_impl(key, cx, arg, false, task, + self.with_task_impl(key, cx, arg, false, true, task, |key| OpenTask::EvalAlways { node: key }, |data, key, task| data.borrow_mut().complete_eval_always_task(key, task)) } @@ -939,7 +975,11 @@ impl CurrentDepGraph { } } - fn complete_task(&mut self, key: DepNode, task: OpenTask) -> DepNodeIndex { + fn complete_task(&mut self, + key: DepNode, + task: OpenTask, + allow_existing_dep_node: bool) + -> DepNodeIndex { if let OpenTask::Regular(task) = task { let RegularOpenTask { node, @@ -970,7 +1010,16 @@ impl CurrentDepGraph { } } - self.alloc_node(node, reads) + if allow_existing_dep_node { + if let Some(&dep_node_index) = self.node_to_node_index.get(&node) { + self.edges[dep_node_index] = reads; + dep_node_index + } else { + self.alloc_node(node, reads) + } + } else { + self.alloc_node(node, reads) + } } else { bug!("complete_task() - Expected regular task to be popped") } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 55752141e30eb..cbc8b4fe68381 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1973,7 +1973,7 @@ pub fn build_session_options_and_crate_config( (&None, &None) => None, }.map(|m| PathBuf::from(m)); - if cg.lto != Lto::No && incremental.is_some() { + if cg.lto == Lto::Fat && incremental.is_some() { early_error( error_format, "can't perform LTO when compiling incrementally", diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index c28b49756f096..327127bf144ea 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -583,11 +583,6 @@ impl Session { return config::Lto::No; } - // Right now ThinLTO isn't compatible with incremental compilation. - if self.opts.incremental.is_some() { - return config::Lto::No; - } - // Now we're in "defaults" territory. By default we enable ThinLTO for // optimized compiles (anything greater than O0). match self.opts.optimize { diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index bd6217e28c755..751d0a08f7d2c 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -702,12 +702,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::codegen_unit<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::compile_codegen_unit<'tcx> { - fn describe(_tcx: TyCtxt, _: InternedString) -> String { - format!("compile_codegen_unit") - } -} - impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("output_filenames") diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 3581dd87f6f8d..8fb0c5bbcae70 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -27,7 +27,7 @@ use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; use mir::interpret::ConstEvalResult; -use mir::mono::{CodegenUnit, Stats}; +use mir::mono::CodegenUnit; use mir; use mir::interpret::{GlobalId, Allocation}; use session::{CompileResult, CrateDisambiguator}; @@ -436,7 +436,6 @@ define_queries! { <'tcx> -> (Arc, Arc>>>), [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, - [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, [] fn output_filenames: output_filenames_node(CrateNum) -> Arc, diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index a68f22b2651f9..1aabd4facbe79 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -811,6 +811,10 @@ impl ThinLTOImports { } } + pub fn modules_imported_by(&self, llvm_module_name: &str) -> &[String] { + self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) + } + /// Load the ThinLTO import map from ThinLTOData. unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports { let raw_data: *const llvm::ThinLTOModuleImports = diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 603ee78585ea6..30b04e9ba988c 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -43,7 +43,6 @@ use rustc::middle::cstore::{EncodedMetadata}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; use rustc::ty::query::Providers; -use rustc::dep_graph::{DepNode, DepConstructor}; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; use rustc::middle::exported_symbols; use rustc::util::common::{time, print_time_passes_entry}; @@ -858,51 +857,50 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut total_codegen_time = Duration::new(0, 0); let mut all_stats = Stats::default(); + let reusable_cgus = determine_cgu_reuse(tcx, &codegen_units); + for cgu in codegen_units.into_iter() { ongoing_codegen.wait_for_signal_to_codegen_item(); ongoing_codegen.check_for_errors(tcx.sess); - // First, if incremental compilation is enabled, we try to re-use the - // codegen unit from the cache. + debug!("starting codegen for CGU: {}", cgu.name()); + + let reused = if reusable_cgus.contains(cgu.name()) { + debug!("CGU `{}` can be re-used", cgu.name()); + + let work_product_id = &cgu.work_product_id(); + let work_product = tcx.dep_graph + .previous_work_product(work_product_id) + .expect("Could not find work-product for reuseable CGU"); + + let module = ModuleCodegen { + name: cgu.name().to_string(), + source: ModuleSource::Preexisting(work_product), + kind: ModuleKind::Regular, + }; + write::submit_codegened_module_to_llvm(tcx, module, 0); + true + } else { + debug!("CGU `{}` can NOT be re-used", cgu.name()); + + let _timing_guard = time_graph.as_ref().map(|time_graph| { + time_graph.start(write::CODEGEN_WORKER_TIMELINE, + write::CODEGEN_WORK_PACKAGE_KIND, + &format!("codegen {}", cgu.name())) + }); + let start_time = Instant::now(); + let stats = compile_codegen_unit(tcx, *cgu.name()); + all_stats.extend(stats); + total_codegen_time += start_time.elapsed(); + false + }; + if tcx.dep_graph.is_fully_enabled() { - let cgu_id = cgu.work_product_id(); - - // Check whether there is a previous work-product we can - // re-use. Not only must the file exist, and the inputs not - // be dirty, but the hash of the symbols we will generate must - // be the same. - if let Some(buf) = tcx.dep_graph.previous_work_product(&cgu_id) { - let dep_node = &DepNode::new(tcx, - DepConstructor::CompileCodegenUnit(cgu.name().clone())); - - // We try to mark the DepNode::CompileCodegenUnit green. If we - // succeed it means that none of the dependencies has changed - // and we can safely re-use. - if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) { - let module = ModuleCodegen { - name: cgu.name().to_string(), - source: ModuleSource::Preexisting(buf), - kind: ModuleKind::Regular, - }; - tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); - write::submit_codegened_module_to_llvm(tcx, module, 0); - // Continue to next cgu, this one is done. - continue - } - } else { - // This can happen if files were deleted from the cache - // directory for some reason. We just re-compile then. - } + let dep_node_index = + tcx.dep_graph.dep_node_index_of(&cgu.compilation_dep_node(tcx)); + tcx.dep_graph.mark_loaded_from_cache(dep_node_index, reused); } - let _timing_guard = time_graph.as_ref().map(|time_graph| { - time_graph.start(write::CODEGEN_WORKER_TIMELINE, - write::CODEGEN_WORK_PACKAGE_KIND, - &format!("codegen {}", cgu.name())) - }); - let start_time = Instant::now(); - all_stats.extend(tcx.compile_codegen_unit(*cgu.name())); - total_codegen_time += start_time.elapsed(); ongoing_codegen.check_for_errors(tcx.sess); } @@ -948,6 +946,67 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ongoing_codegen } +fn determine_cgu_reuse<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + codegen_units: &[Arc>]) + -> FxHashSet { + if !tcx.dep_graph.is_fully_enabled() { + return FxHashSet() + } + + let mut green_cgus = FxHashSet(); + + for cgu in codegen_units { + let work_product_id = &cgu.work_product_id(); + + if tcx.dep_graph.previous_work_product(work_product_id).is_none() { + // We don't have anything cached for this CGU. This can happen + // if the CGU did not exist in the previous session. We are done + // for this CGU, skip to the next. + continue + }; + + // Try to mark the CGU as green + let dep_node = cgu.compilation_dep_node(tcx); + + assert!(!tcx.dep_graph.dep_node_exists(&dep_node), + "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", + cgu.name()); + + if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() { + green_cgus.insert(cgu.name().to_string()); + } else { + // We definitely cannot re-use this CGU + } + } + + let thin_lto_imports = load_thin_lto_imports(tcx.sess); + let mut reusable_cgus = FxHashSet(); + + // Now we know all CGUs that have not changed themselves. Next we need to + // check if anything they imported via ThinLTO has changed. + for cgu_name in &green_cgus { + let imported_cgus = thin_lto_imports.modules_imported_by(cgu_name); + + let all_imports_green = imported_cgus.iter().all(|imported_cgu| { + green_cgus.contains(&imported_cgu[..]) + }); + + if all_imports_green { + reusable_cgus.insert(cgu_name.clone()); + } + } + + codegen_units + .iter() + .filter_map(|cgu| { + if reusable_cgus.contains(&cgu.name().as_str()[..]) { + Some(cgu.name().clone()) + } else { + None + } + }).collect::>() +} + fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { time(tcx.sess, "assert dep graph", @@ -1167,11 +1226,15 @@ fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool { } fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu: InternedString) -> Stats { - let cgu = tcx.codegen_unit(cgu); - + cgu_name: InternedString) + -> Stats { let start_time = Instant::now(); - let (stats, module) = module_codegen(tcx, cgu); + + let dep_node = tcx.codegen_unit(cgu_name).compilation_dep_node(tcx); + let ((stats, module), _) = tcx.dep_graph.with_forced_task(dep_node, + tcx, + cgu_name, + module_codegen); let time_to_codegen = start_time.elapsed(); // We assume that the cost to run LLVM on a CGU is proportional to @@ -1180,22 +1243,22 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time_to_codegen.subsec_nanos() as u64; write::submit_codegened_module_to_llvm(tcx, - module, - cost); + module, + cost); return stats; fn module_codegen<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - cgu: Arc>) + cgu_name: InternedString) -> (Stats, ModuleCodegen) { - let cgu_name = cgu.name().to_string(); + let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... let cx = CodegenCx::new(tcx, cgu); let module = { let mono_items = cx.codegen_unit - .items_in_deterministic_order(cx.tcx); + .items_in_deterministic_order(cx.tcx); for &(mono_item, (linkage, visibility)) in &mono_items { mono_item.predefine(&cx, linkage, visibility); } @@ -1247,7 +1310,7 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; ModuleCodegen { - name: cgu_name, + name: cgu_name.to_string(), source: ModuleSource::Codegened(llvm_module), kind: ModuleKind::Regular, } @@ -1270,7 +1333,6 @@ pub fn provide(providers: &mut Providers) { .cloned() .expect(&format!("failed to find cgu with name {:?}", name)) }; - providers.compile_codegen_unit = compile_codegen_unit; provide_extern(providers); } @@ -1352,8 +1414,11 @@ mod temp_stable_hash_impls { } } -#[allow(unused)] fn load_thin_lto_imports(sess: &Session) -> lto::ThinLTOImports { + if sess.opts.incremental.is_none() { + return lto::ThinLTOImports::new_empty(); + } + let path = rustc_incremental::in_incr_comp_dir_sess( sess, lto::THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 73b430bc04112..f804cdc14e5f1 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -103,7 +103,7 @@ //! inlining, even when they are not marked #[inline]. use monomorphize::collector::InliningMap; -use rustc::dep_graph::WorkProductId; +use rustc::dep_graph::{WorkProductId, DepNode, DepConstructor}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::DefPathData; use rustc::mir::mono::{Linkage, Visibility}; @@ -194,6 +194,10 @@ pub trait CodegenUnitExt<'tcx> { items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); items } + + fn compilation_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode { + DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone())) + } } impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e5fb472afd635..1f63ae241b66c 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1658,6 +1658,9 @@ impl<'test> TestCx<'test> { rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]); rustc.args(&["-Z", "incremental-verify-ich"]); rustc.args(&["-Z", "incremental-queries"]); + + // Force thinlto off for now.. + rustc.args(&["-Zthinlto=no"]); } if self.config.mode == CodegenUnits {