Always add all modules to the global ThinLTO module analysis when compiling incrementally.
This commit is contained in:
parent
64a738d8ce
commit
abd5cc3364
|
@ -1198,6 +1198,15 @@ dependencies = [
|
||||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memmap"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -2029,6 +2038,7 @@ name = "rustc_codegen_llvm"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc_llvm 0.0.0",
|
"rustc_llvm 0.0.0",
|
||||||
|
@ -3151,6 +3161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||||
"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
|
"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
|
||||||
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
|
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
|
||||||
|
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
|
||||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||||
"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11"
|
"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11"
|
||||||
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
||||||
|
|
|
@ -883,7 +883,6 @@ pub enum WorkProductFileKind {
|
||||||
Object,
|
Object,
|
||||||
Bytecode,
|
Bytecode,
|
||||||
BytecodeCompressed,
|
BytecodeCompressed,
|
||||||
PreThinLtoBytecode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CurrentDepGraph {
|
pub(super) struct CurrentDepGraph {
|
||||||
|
|
|
@ -11,17 +11,18 @@
|
||||||
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
|
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
|
||||||
use back::symbol_export;
|
use back::symbol_export;
|
||||||
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
|
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
|
||||||
use back::write::{self, DiagnosticHandlers};
|
use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename};
|
||||||
use errors::{FatalError, Handler};
|
use errors::{FatalError, Handler};
|
||||||
use llvm::archive_ro::ArchiveRO;
|
use llvm::archive_ro::ArchiveRO;
|
||||||
use llvm::{True, False};
|
use llvm::{True, False};
|
||||||
use llvm;
|
use llvm;
|
||||||
use memmap;
|
use memmap;
|
||||||
|
use rustc::dep_graph::WorkProduct;
|
||||||
use rustc::hir::def_id::LOCAL_CRATE;
|
use rustc::hir::def_id::LOCAL_CRATE;
|
||||||
use rustc::middle::exported_symbols::SymbolExportLevel;
|
use rustc::middle::exported_symbols::SymbolExportLevel;
|
||||||
use rustc::session::config::{self, Lto};
|
use rustc::session::config::{self, Lto};
|
||||||
use rustc::util::common::time_ext;
|
use rustc::util::common::time_ext;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use time_graph::Timeline;
|
use time_graph::Timeline;
|
||||||
use {ModuleCodegen, ModuleLlvm, ModuleKind};
|
use {ModuleCodegen, ModuleLlvm, ModuleKind};
|
||||||
|
|
||||||
|
@ -29,15 +30,10 @@ use libc;
|
||||||
|
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
|
||||||
use std::mem;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::Arc;
|
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 {
|
pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
|
||||||
match crate_type {
|
match crate_type {
|
||||||
config::CrateType::Executable |
|
config::CrateType::Executable |
|
||||||
|
@ -105,11 +101,16 @@ impl LtoModuleCodegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs LTO, which in the case of full LTO means merging all modules into
|
||||||
|
/// a single one and returning it for further optimizing. For ThinLTO, it will
|
||||||
|
/// do the global analysis necessary and return two lists, one of the modules
|
||||||
|
/// the need optimization and another for modules that can simply be copied over
|
||||||
|
/// from the incr. comp. cache.
|
||||||
pub(crate) fn run(cgcx: &CodegenContext,
|
pub(crate) fn run(cgcx: &CodegenContext,
|
||||||
modules: Vec<ModuleCodegen>,
|
modules: Vec<ModuleCodegen>,
|
||||||
import_only_modules: Vec<(SerializedModule, CString)>,
|
cached_modules: Vec<(SerializedModule, WorkProduct)>,
|
||||||
timeline: &mut Timeline)
|
timeline: &mut Timeline)
|
||||||
-> Result<Vec<LtoModuleCodegen>, FatalError>
|
-> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
|
||||||
{
|
{
|
||||||
let diag_handler = cgcx.create_diag_handler();
|
let diag_handler = cgcx.create_diag_handler();
|
||||||
let export_threshold = match cgcx.lto {
|
let export_threshold = match cgcx.lto {
|
||||||
|
@ -202,13 +203,14 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
||||||
match cgcx.lto {
|
match cgcx.lto {
|
||||||
Lto::Yes | // `-C lto` == fat LTO by default
|
Lto::Yes | // `-C lto` == fat LTO by default
|
||||||
Lto::Fat => {
|
Lto::Fat => {
|
||||||
assert!(import_only_modules.is_empty());
|
assert!(cached_modules.is_empty());
|
||||||
fat_lto(cgcx,
|
let opt_jobs = fat_lto(cgcx,
|
||||||
&diag_handler,
|
&diag_handler,
|
||||||
modules,
|
modules,
|
||||||
upstream_modules,
|
upstream_modules,
|
||||||
&symbol_white_list,
|
&symbol_white_list,
|
||||||
timeline)
|
timeline);
|
||||||
|
opt_jobs.map(|opt_jobs| (opt_jobs, vec![]))
|
||||||
}
|
}
|
||||||
Lto::Thin |
|
Lto::Thin |
|
||||||
Lto::ThinLocal => {
|
Lto::ThinLocal => {
|
||||||
|
@ -220,7 +222,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
||||||
&diag_handler,
|
&diag_handler,
|
||||||
modules,
|
modules,
|
||||||
upstream_modules,
|
upstream_modules,
|
||||||
import_only_modules,
|
cached_modules,
|
||||||
&symbol_white_list,
|
&symbol_white_list,
|
||||||
timeline)
|
timeline)
|
||||||
}
|
}
|
||||||
|
@ -388,14 +390,19 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
diag_handler: &Handler,
|
diag_handler: &Handler,
|
||||||
modules: Vec<ModuleCodegen>,
|
modules: Vec<ModuleCodegen>,
|
||||||
serialized_modules: Vec<(SerializedModule, CString)>,
|
serialized_modules: Vec<(SerializedModule, CString)>,
|
||||||
import_only_modules: Vec<(SerializedModule, CString)>,
|
cached_modules: Vec<(SerializedModule, WorkProduct)>,
|
||||||
symbol_white_list: &[*const libc::c_char],
|
symbol_white_list: &[*const libc::c_char],
|
||||||
timeline: &mut Timeline)
|
timeline: &mut Timeline)
|
||||||
-> Result<Vec<LtoModuleCodegen>, FatalError>
|
-> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
info!("going for that thin, thin LTO");
|
info!("going for that thin, thin LTO");
|
||||||
|
|
||||||
|
let green_modules: FxHashMap<_, _> = cached_modules
|
||||||
|
.iter()
|
||||||
|
.map(|&(_, ref wp)| (wp.cgu_name.clone(), wp.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut thin_buffers = Vec::new();
|
let mut thin_buffers = Vec::new();
|
||||||
let mut module_names = Vec::new();
|
let mut module_names = Vec::new();
|
||||||
let mut thin_modules = Vec::new();
|
let mut thin_modules = Vec::new();
|
||||||
|
@ -411,6 +418,28 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
info!("local module: {} - {}", i, module.name);
|
info!("local module: {} - {}", i, module.name);
|
||||||
let name = CString::new(module.name.clone()).unwrap();
|
let name = CString::new(module.name.clone()).unwrap();
|
||||||
let buffer = ThinBuffer::new(module.module_llvm.llmod());
|
let buffer = ThinBuffer::new(module.module_llvm.llmod());
|
||||||
|
|
||||||
|
// We emit the module after having serialized it into a ThinBuffer
|
||||||
|
// because only then it will contain the ThinLTO module summary.
|
||||||
|
if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
|
||||||
|
if cgcx.config(module.kind).emit_pre_thin_lto_bc {
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
let path = incr_comp_session_dir
|
||||||
|
.join(pre_lto_bitcode_filename(&module.name));
|
||||||
|
let mut file = File::create(&path).unwrap_or_else(|e| {
|
||||||
|
panic!("Failed to create pre-lto-bitcode file `{}`: {}",
|
||||||
|
path.display(),
|
||||||
|
e);
|
||||||
|
});
|
||||||
|
file.write_all(buffer.data()).unwrap_or_else(|e| {
|
||||||
|
panic!("Error writing pre-lto-bitcode file `{}`: {}",
|
||||||
|
path.display(),
|
||||||
|
e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thin_modules.push(llvm::ThinLTOModule {
|
thin_modules.push(llvm::ThinLTOModule {
|
||||||
identifier: name.as_ptr(),
|
identifier: name.as_ptr(),
|
||||||
data: buffer.data().as_ptr(),
|
data: buffer.data().as_ptr(),
|
||||||
|
@ -438,8 +467,13 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
// looking at upstream modules entirely sometimes (the contents,
|
// looking at upstream modules entirely sometimes (the contents,
|
||||||
// we must always unconditionally look at the index).
|
// we must always unconditionally look at the index).
|
||||||
let mut serialized = Vec::new();
|
let mut serialized = Vec::new();
|
||||||
for (module, name) in serialized_modules {
|
|
||||||
info!("foreign module {:?}", name);
|
let cached_modules = cached_modules.into_iter().map(|(sm, wp)| {
|
||||||
|
(sm, CString::new(wp.cgu_name).unwrap())
|
||||||
|
});
|
||||||
|
|
||||||
|
for (module, name) in serialized_modules.into_iter().chain(cached_modules) {
|
||||||
|
info!("upstream or cached module {:?}", name);
|
||||||
thin_modules.push(llvm::ThinLTOModule {
|
thin_modules.push(llvm::ThinLTOModule {
|
||||||
identifier: name.as_ptr(),
|
identifier: name.as_ptr(),
|
||||||
data: module.data().as_ptr(),
|
data: module.data().as_ptr(),
|
||||||
|
@ -449,21 +483,8 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
module_names.push(name);
|
module_names.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the modules collected up to this point we actually want to
|
// Sanity check
|
||||||
// optimize. The `import_only_modules` below need to be in the list of
|
assert_eq!(thin_modules.len(), module_names.len());
|
||||||
// available modules but we don't need to run optimizations for them
|
|
||||||
// since we already have their optimized version cached.
|
|
||||||
let modules_to_optimize = module_names.len();
|
|
||||||
for (module, name) in import_only_modules {
|
|
||||||
info!("foreign module {:?}", name);
|
|
||||||
thin_modules.push(llvm::ThinLTOModule {
|
|
||||||
identifier: name.as_ptr(),
|
|
||||||
data: module.data().as_ptr(),
|
|
||||||
len: module.data().len(),
|
|
||||||
});
|
|
||||||
serialized.push(module);
|
|
||||||
module_names.push(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delegate to the C++ bindings to create some data here. Once this is a
|
// Delegate to the C++ bindings to create some data here. Once this is a
|
||||||
// tried-and-true interface we may wish to try to upstream some of this
|
// tried-and-true interface we may wish to try to upstream some of this
|
||||||
|
@ -478,30 +499,7 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
|
write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Save the ThinLTO import information for incremental compilation.
|
let import_map = ThinLTOImports::from_thin_lto_data(data);
|
||||||
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);
|
|
||||||
|
|
||||||
// The import information from the current compilation session. It
|
|
||||||
// does not contain info about modules that have been loaded from
|
|
||||||
// the cache instead of having been recompiled...
|
|
||||||
let current_imports = ThinLTOImports::from_thin_lto_data(data);
|
|
||||||
|
|
||||||
// ... so we load this additional information from the previous
|
|
||||||
// cache file if necessary.
|
|
||||||
let imports = if path.exists() {
|
|
||||||
let prev_imports = ThinLTOImports::load_from_file(&path).unwrap();
|
|
||||||
prev_imports.update(current_imports, &module_names)
|
|
||||||
} else {
|
|
||||||
current_imports
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
let data = ThinData(data);
|
||||||
info!("thin LTO data created");
|
info!("thin LTO data created");
|
||||||
|
@ -517,12 +515,36 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
serialized_modules: serialized,
|
serialized_modules: serialized,
|
||||||
module_names,
|
module_names,
|
||||||
});
|
});
|
||||||
Ok((0..modules_to_optimize).map(|i| {
|
|
||||||
LtoModuleCodegen::Thin(ThinModule {
|
let mut copy_jobs = vec![];
|
||||||
|
let mut opt_jobs = vec![];
|
||||||
|
|
||||||
|
for (module_index, module_name) in shared.module_names.iter().enumerate() {
|
||||||
|
let module_name = module_name_to_str(module_name);
|
||||||
|
|
||||||
|
if green_modules.contains_key(module_name) {
|
||||||
|
let mut imports_all_green = true;
|
||||||
|
for imported_module in import_map.modules_imported_by(module_name) {
|
||||||
|
if !green_modules.contains_key(imported_module) {
|
||||||
|
imports_all_green = false;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if imports_all_green {
|
||||||
|
let work_product = green_modules[module_name].clone();
|
||||||
|
copy_jobs.push(work_product);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
|
||||||
shared: shared.clone(),
|
shared: shared.clone(),
|
||||||
idx: i,
|
idx: module_index,
|
||||||
})
|
}));
|
||||||
}).collect())
|
}
|
||||||
|
|
||||||
|
Ok((opt_jobs, copy_jobs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,44 +872,12 @@ pub struct ThinLTOImports {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThinLTOImports {
|
impl ThinLTOImports {
|
||||||
pub fn new() -> ThinLTOImports {
|
|
||||||
ThinLTOImports {
|
|
||||||
imports: FxHashMap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn modules_imported_by(&self, llvm_module_name: &str) -> &[String] {
|
pub fn modules_imported_by(&self, llvm_module_name: &str) -> &[String] {
|
||||||
self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
|
self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(mut self, new: ThinLTOImports, module_names: &[CString]) -> ThinLTOImports {
|
|
||||||
let module_names: FxHashSet<_> = module_names.iter().map(|name| {
|
|
||||||
name.clone().into_string().unwrap()
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
// Remove all modules that don't exist anymore.
|
|
||||||
self.imports.retain(|k, _| module_names.contains(k));
|
|
||||||
|
|
||||||
// Overwrite old values
|
|
||||||
for (importing_module, imported_modules) in new.imports {
|
|
||||||
self.imports.insert(importing_module, imported_modules);
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load the ThinLTO import map from ThinLTOData.
|
/// Load the ThinLTO import map from ThinLTOData.
|
||||||
unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports {
|
unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports {
|
||||||
fn module_name_to_str(c_str: &CStr) -> &str {
|
|
||||||
match c_str.to_str() {
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(e) => {
|
|
||||||
bug!("Encountered non-utf8 LLVM module name `{}`: {}",
|
|
||||||
c_str.to_string_lossy(),
|
|
||||||
e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void,
|
unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void,
|
||||||
importing_module_name: *const libc::c_char,
|
importing_module_name: *const libc::c_char,
|
||||||
imported_module_name: *const libc::c_char) {
|
imported_module_name: *const libc::c_char) {
|
||||||
|
@ -896,6 +886,7 @@ impl ThinLTOImports {
|
||||||
let importing_module_name = module_name_to_str(&importing_module_name);
|
let importing_module_name = module_name_to_str(&importing_module_name);
|
||||||
let imported_module_name = CStr::from_ptr(imported_module_name);
|
let imported_module_name = CStr::from_ptr(imported_module_name);
|
||||||
let imported_module_name = module_name_to_str(&imported_module_name);
|
let imported_module_name = module_name_to_str(&imported_module_name);
|
||||||
|
|
||||||
if !map.imports.contains_key(importing_module_name) {
|
if !map.imports.contains_key(importing_module_name) {
|
||||||
map.imports.insert(importing_module_name.to_owned(), vec![]);
|
map.imports.insert(importing_module_name.to_owned(), vec![]);
|
||||||
}
|
}
|
||||||
|
@ -913,47 +904,15 @@ impl ThinLTOImports {
|
||||||
&mut map as *mut _ as *mut libc::c_void);
|
&mut map as *mut _ as *mut libc::c_void);
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
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<ThinLTOImports> {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn module_name_to_str(c_str: &CStr) -> &str {
|
||||||
|
match c_str.to_str() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
bug!("Encountered non-utf8 LLVM module name `{}`: {}",
|
||||||
|
c_str.to_string_lossy(),
|
||||||
|
e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ use rustc::util::nodemap::FxHashMap;
|
||||||
use time_graph::{self, TimeGraph, Timeline};
|
use time_graph::{self, TimeGraph, Timeline};
|
||||||
use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
|
use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
|
||||||
use llvm_util;
|
use llvm_util;
|
||||||
use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, ModuleLlvm,
|
use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, // ModuleLlvm,
|
||||||
CachedModuleCodegen};
|
CachedModuleCodegen};
|
||||||
use CrateInfo;
|
use CrateInfo;
|
||||||
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
|
@ -228,8 +228,8 @@ pub struct ModuleConfig {
|
||||||
pgo_use: String,
|
pgo_use: String,
|
||||||
|
|
||||||
// Flags indicating which outputs to produce.
|
// Flags indicating which outputs to produce.
|
||||||
|
pub emit_pre_thin_lto_bc: bool,
|
||||||
emit_no_opt_bc: bool,
|
emit_no_opt_bc: bool,
|
||||||
emit_pre_thin_lto_bc: bool,
|
|
||||||
emit_bc: bool,
|
emit_bc: bool,
|
||||||
emit_bc_compressed: bool,
|
emit_bc_compressed: bool,
|
||||||
emit_lto_bc: bool,
|
emit_lto_bc: bool,
|
||||||
|
@ -625,20 +625,13 @@ unsafe fn optimize(cgcx: &CodegenContext,
|
||||||
// Deallocate managers that we're now done with
|
// Deallocate managers that we're now done with
|
||||||
llvm::LLVMDisposePassManager(fpm);
|
llvm::LLVMDisposePassManager(fpm);
|
||||||
llvm::LLVMDisposePassManager(mpm);
|
llvm::LLVMDisposePassManager(mpm);
|
||||||
|
|
||||||
if config.emit_pre_thin_lto_bc {
|
|
||||||
let out = cgcx.output_filenames.temp_path_ext(PRE_THIN_LTO_BC_EXT,
|
|
||||||
module_name);
|
|
||||||
let out = path2cstr(&out);
|
|
||||||
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_lto_work(cgcx: &CodegenContext,
|
fn generate_lto_work(cgcx: &CodegenContext,
|
||||||
modules: Vec<ModuleCodegen>,
|
modules: Vec<ModuleCodegen>,
|
||||||
import_only_modules: Vec<(SerializedModule, CString)>)
|
import_only_modules: Vec<(SerializedModule, WorkProduct)>)
|
||||||
-> Vec<(WorkItem, u64)>
|
-> Vec<(WorkItem, u64)>
|
||||||
{
|
{
|
||||||
let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
|
let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
|
||||||
|
@ -646,13 +639,22 @@ fn generate_lto_work(cgcx: &CodegenContext,
|
||||||
CODEGEN_WORK_PACKAGE_KIND,
|
CODEGEN_WORK_PACKAGE_KIND,
|
||||||
"generate lto")
|
"generate lto")
|
||||||
}).unwrap_or(Timeline::noop());
|
}).unwrap_or(Timeline::noop());
|
||||||
let lto_modules = lto::run(cgcx, modules, import_only_modules, &mut timeline)
|
let (lto_modules, copy_jobs) = lto::run(cgcx, modules, import_only_modules, &mut timeline)
|
||||||
.unwrap_or_else(|e| e.raise());
|
.unwrap_or_else(|e| e.raise());
|
||||||
|
|
||||||
lto_modules.into_iter().map(|module| {
|
let lto_modules = lto_modules.into_iter().map(|module| {
|
||||||
let cost = module.cost();
|
let cost = module.cost();
|
||||||
(WorkItem::LTO(module), cost)
|
(WorkItem::LTO(module), cost)
|
||||||
}).collect()
|
});
|
||||||
|
|
||||||
|
let copy_jobs = copy_jobs.into_iter().map(|wp| {
|
||||||
|
(WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
|
||||||
|
name: wp.cgu_name.clone(),
|
||||||
|
source: wp,
|
||||||
|
}), 0)
|
||||||
|
});
|
||||||
|
|
||||||
|
lto_modules.chain(copy_jobs).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn codegen(cgcx: &CodegenContext,
|
unsafe fn codegen(cgcx: &CodegenContext,
|
||||||
|
@ -1083,7 +1085,6 @@ pub fn start_async_codegen(tcx: TyCtxt,
|
||||||
fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
compiled_modules: &CompiledModules,
|
compiled_modules: &CompiledModules,
|
||||||
output_filenames: &OutputFilenames,
|
|
||||||
) -> FxHashMap<WorkProductId, WorkProduct> {
|
) -> FxHashMap<WorkProductId, WorkProduct> {
|
||||||
let mut work_products = FxHashMap::default();
|
let mut work_products = FxHashMap::default();
|
||||||
|
|
||||||
|
@ -1104,13 +1105,6 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
||||||
files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
|
files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pre_thin_lto_bytecode_path =
|
|
||||||
output_filenames.temp_path_ext(PRE_THIN_LTO_BC_EXT, Some(&module.name));
|
|
||||||
|
|
||||||
if pre_thin_lto_bytecode_path.exists() {
|
|
||||||
files.push((WorkProductFileKind::PreThinLtoBytecode, pre_thin_lto_bytecode_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((id, product)) =
|
if let Some((id, product)) =
|
||||||
copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
|
copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
|
||||||
work_products.insert(id, product);
|
work_products.insert(id, product);
|
||||||
|
@ -1285,9 +1279,6 @@ enum WorkItem {
|
||||||
/// Copy the post-LTO artifacts from the incremental cache to the output
|
/// Copy the post-LTO artifacts from the incremental cache to the output
|
||||||
/// directory.
|
/// directory.
|
||||||
CopyPostLtoArtifacts(CachedModuleCodegen),
|
CopyPostLtoArtifacts(CachedModuleCodegen),
|
||||||
/// Load the pre-LTO version of a module from the incremental cache, so it
|
|
||||||
/// can be run through LTO again.
|
|
||||||
LoadPreLtoModule(CachedModuleCodegen),
|
|
||||||
/// Perform (Thin)LTO on the given module.
|
/// Perform (Thin)LTO on the given module.
|
||||||
LTO(lto::LtoModuleCodegen),
|
LTO(lto::LtoModuleCodegen),
|
||||||
}
|
}
|
||||||
|
@ -1297,7 +1288,6 @@ impl WorkItem {
|
||||||
match *self {
|
match *self {
|
||||||
WorkItem::Optimize(ref m) => m.kind,
|
WorkItem::Optimize(ref m) => m.kind,
|
||||||
WorkItem::CopyPostLtoArtifacts(_) |
|
WorkItem::CopyPostLtoArtifacts(_) |
|
||||||
WorkItem::LoadPreLtoModule(_) |
|
|
||||||
WorkItem::LTO(_) => ModuleKind::Regular,
|
WorkItem::LTO(_) => ModuleKind::Regular,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1305,7 +1295,6 @@ impl WorkItem {
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
WorkItem::Optimize(ref m) => format!("optimize: {}", m.name),
|
WorkItem::Optimize(ref m) => format!("optimize: {}", m.name),
|
||||||
WorkItem::LoadPreLtoModule(ref m) => format!("load pre-lto module: {}", m.name),
|
|
||||||
WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name),
|
WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name),
|
||||||
WorkItem::LTO(ref m) => format!("lto: {}", m.name()),
|
WorkItem::LTO(ref m) => format!("lto: {}", m.name()),
|
||||||
}
|
}
|
||||||
|
@ -1326,9 +1315,6 @@ fn execute_work_item(cgcx: &CodegenContext,
|
||||||
work_item @ WorkItem::Optimize(_) => {
|
work_item @ WorkItem::Optimize(_) => {
|
||||||
execute_optimize_work_item(cgcx, work_item, timeline)
|
execute_optimize_work_item(cgcx, work_item, timeline)
|
||||||
}
|
}
|
||||||
work_item @ WorkItem::LoadPreLtoModule(_) => {
|
|
||||||
execute_load_pre_lto_mod_work_item(cgcx, work_item, timeline)
|
|
||||||
}
|
|
||||||
work_item @ WorkItem::CopyPostLtoArtifacts(_) => {
|
work_item @ WorkItem::CopyPostLtoArtifacts(_) => {
|
||||||
execute_copy_from_cache_work_item(cgcx, work_item, timeline)
|
execute_copy_from_cache_work_item(cgcx, work_item, timeline)
|
||||||
}
|
}
|
||||||
|
@ -1454,9 +1440,6 @@ fn execute_copy_from_cache_work_item(cgcx: &CodegenContext,
|
||||||
bytecode_compressed = Some(path.clone());
|
bytecode_compressed = Some(path.clone());
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
WorkProductFileKind::PreThinLtoBytecode => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let source_file = in_incr_comp_dir(&incr_comp_session_dir,
|
let source_file = in_incr_comp_dir(&incr_comp_session_dir,
|
||||||
&saved_file);
|
&saved_file);
|
||||||
|
@ -1509,69 +1492,6 @@ fn execute_lto_work_item(cgcx: &CodegenContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_load_pre_lto_mod_work_item(cgcx: &CodegenContext,
|
|
||||||
work_item: WorkItem,
|
|
||||||
_: &mut Timeline)
|
|
||||||
-> Result<WorkItemResult, FatalError>
|
|
||||||
{
|
|
||||||
let module = if let WorkItem::LoadPreLtoModule(module) = work_item {
|
|
||||||
module
|
|
||||||
} else {
|
|
||||||
bug!("execute_load_pre_lto_mod_work_item() called with wrong WorkItem kind.")
|
|
||||||
};
|
|
||||||
|
|
||||||
let work_product = module.source.clone();
|
|
||||||
let incr_comp_session_dir = cgcx.incr_comp_session_dir
|
|
||||||
.as_ref()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let filename = pre_lto_bitcode_filename(&work_product);
|
|
||||||
let bc_path = in_incr_comp_dir(&incr_comp_session_dir, &filename);
|
|
||||||
|
|
||||||
let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
|
|
||||||
panic!("failed to open bitcode file `{}`: {}",
|
|
||||||
bc_path.display(),
|
|
||||||
e);
|
|
||||||
});
|
|
||||||
|
|
||||||
let module_llvm = unsafe {
|
|
||||||
let data = ::memmap::Mmap::map(&file).unwrap_or_else(|e| {
|
|
||||||
panic!("failed to create mmap for bitcode file `{}`: {}",
|
|
||||||
bc_path.display(),
|
|
||||||
e);
|
|
||||||
});
|
|
||||||
|
|
||||||
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
|
|
||||||
let mod_name_c = SmallCStr::new(&module.name);
|
|
||||||
let llmod_raw = match llvm::LLVMRustParseBitcodeForThinLTO(
|
|
||||||
llcx,
|
|
||||||
data.as_ptr(),
|
|
||||||
data.len(),
|
|
||||||
mod_name_c.as_ptr(),
|
|
||||||
) {
|
|
||||||
Some(m) => m as *const _,
|
|
||||||
None => {
|
|
||||||
panic!("failed to parse bitcode for thin LTO module `{}`",
|
|
||||||
module.name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let tm = (cgcx.tm_factory)().unwrap();
|
|
||||||
|
|
||||||
ModuleLlvm {
|
|
||||||
llmod_raw,
|
|
||||||
llcx,
|
|
||||||
tm,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(WorkItemResult::NeedsLTO(ModuleCodegen {
|
|
||||||
name: module.name.to_string(),
|
|
||||||
module_llvm,
|
|
||||||
kind: ModuleKind::Regular,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Message {
|
enum Message {
|
||||||
Token(io::Result<Acquired>),
|
Token(io::Result<Acquired>),
|
||||||
NeedsLTO {
|
NeedsLTO {
|
||||||
|
@ -1588,7 +1508,7 @@ enum Message {
|
||||||
},
|
},
|
||||||
AddImportOnlyModule {
|
AddImportOnlyModule {
|
||||||
module_data: SerializedModule,
|
module_data: SerializedModule,
|
||||||
module_name: CString,
|
work_product: WorkProduct,
|
||||||
},
|
},
|
||||||
CodegenComplete,
|
CodegenComplete,
|
||||||
CodegenItem,
|
CodegenItem,
|
||||||
|
@ -1893,6 +1813,7 @@ fn start_executing_work(tcx: TyCtxt,
|
||||||
work_items.len() > 0 ||
|
work_items.len() > 0 ||
|
||||||
running > 0 ||
|
running > 0 ||
|
||||||
needs_lto.len() > 0 ||
|
needs_lto.len() > 0 ||
|
||||||
|
lto_import_only_modules.len() > 0 ||
|
||||||
main_thread_worker_state != MainThreadWorkerState::Idle {
|
main_thread_worker_state != MainThreadWorkerState::Idle {
|
||||||
|
|
||||||
// While there are still CGUs to be codegened, the coordinator has
|
// While there are still CGUs to be codegened, the coordinator has
|
||||||
|
@ -1932,7 +1853,7 @@ fn start_executing_work(tcx: TyCtxt,
|
||||||
running == 0 &&
|
running == 0 &&
|
||||||
main_thread_worker_state == MainThreadWorkerState::Idle {
|
main_thread_worker_state == MainThreadWorkerState::Idle {
|
||||||
assert!(!started_lto);
|
assert!(!started_lto);
|
||||||
assert!(needs_lto.len() > 0);
|
assert!(needs_lto.len() + lto_import_only_modules.len() > 0);
|
||||||
started_lto = true;
|
started_lto = true;
|
||||||
let modules = mem::replace(&mut needs_lto, Vec::new());
|
let modules = mem::replace(&mut needs_lto, Vec::new());
|
||||||
let import_only_modules =
|
let import_only_modules =
|
||||||
|
@ -2104,10 +2025,13 @@ fn start_executing_work(tcx: TyCtxt,
|
||||||
free_worker_ids.push(worker_id);
|
free_worker_ids.push(worker_id);
|
||||||
needs_lto.push(result);
|
needs_lto.push(result);
|
||||||
}
|
}
|
||||||
Message::AddImportOnlyModule { module_data, module_name } => {
|
Message::AddImportOnlyModule { module_data, work_product } => {
|
||||||
assert!(!started_lto);
|
assert!(!started_lto);
|
||||||
assert!(!codegen_done);
|
assert!(!codegen_done);
|
||||||
lto_import_only_modules.push((module_data, module_name));
|
assert_eq!(main_thread_worker_state,
|
||||||
|
MainThreadWorkerState::Codegenning);
|
||||||
|
lto_import_only_modules.push((module_data, work_product));
|
||||||
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
||||||
}
|
}
|
||||||
Message::Done { result: Err(()), worker_id: _ } => {
|
Message::Done { result: Err(()), worker_id: _ } => {
|
||||||
shared_emitter.fatal("aborting due to worker thread failure");
|
shared_emitter.fatal("aborting due to worker thread failure");
|
||||||
|
@ -2483,8 +2407,7 @@ impl OngoingCodegen {
|
||||||
|
|
||||||
let work_products =
|
let work_products =
|
||||||
copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
|
copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
|
||||||
&compiled_modules,
|
&compiled_modules);
|
||||||
&self.output_filenames);
|
|
||||||
produce_final_output_artifacts(sess,
|
produce_final_output_artifacts(sess,
|
||||||
&compiled_modules,
|
&compiled_modules,
|
||||||
&self.output_filenames);
|
&self.output_filenames);
|
||||||
|
@ -2565,19 +2488,7 @@ pub(crate) fn submit_post_lto_module_to_llvm(tcx: TyCtxt,
|
||||||
|
|
||||||
pub(crate) fn submit_pre_lto_module_to_llvm(tcx: TyCtxt,
|
pub(crate) fn submit_pre_lto_module_to_llvm(tcx: TyCtxt,
|
||||||
module: CachedModuleCodegen) {
|
module: CachedModuleCodegen) {
|
||||||
let llvm_work_item = WorkItem::LoadPreLtoModule(module);
|
let filename = pre_lto_bitcode_filename(&module.name);
|
||||||
|
|
||||||
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone {
|
|
||||||
llvm_work_item,
|
|
||||||
// We don't know the size of the module, but just loading will have smaller
|
|
||||||
// cost than optimizing.
|
|
||||||
cost: 10,
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn submit_import_only_module_to_llvm(tcx: TyCtxt,
|
|
||||||
module: CachedModuleCodegen) {
|
|
||||||
let filename = pre_lto_bitcode_filename(&module.source);
|
|
||||||
let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
|
let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
|
||||||
let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
|
let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
|
||||||
panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e)
|
panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e)
|
||||||
|
@ -2592,21 +2503,12 @@ pub(crate) fn submit_import_only_module_to_llvm(tcx: TyCtxt,
|
||||||
// Schedule the module to be loaded
|
// Schedule the module to be loaded
|
||||||
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule {
|
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule {
|
||||||
module_data: SerializedModule::FromUncompressedFile(mmap, file),
|
module_data: SerializedModule::FromUncompressedFile(mmap, file),
|
||||||
module_name: CString::new(module.name.clone()).unwrap(),
|
work_product: module.source,
|
||||||
})));
|
})));
|
||||||
|
|
||||||
// Note: We also schedule for the cached files to be copied to the output
|
|
||||||
// directory
|
|
||||||
submit_post_lto_module_to_llvm(tcx, module);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_lto_bitcode_filename(wp: &WorkProduct) -> String {
|
pub(super) fn pre_lto_bitcode_filename(module_name: &str) -> String {
|
||||||
wp.saved_files
|
format!("{}.{}", module_name, PRE_THIN_LTO_BC_EXT)
|
||||||
.iter()
|
|
||||||
.find(|&&(kind, _)| kind == WorkProductFileKind::PreThinLtoBytecode)
|
|
||||||
.map(|&(_, ref filename)| filename.clone())
|
|
||||||
.unwrap_or_else(|| panic!("Couldn't find pre-thin-lto bytecode for `{}`",
|
|
||||||
wp.cgu_name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msvc_imps_needed(tcx: TyCtxt) -> bool {
|
fn msvc_imps_needed(tcx: TyCtxt) -> bool {
|
||||||
|
|
|
@ -29,7 +29,6 @@ use super::ModuleKind;
|
||||||
use super::CachedModuleCodegen;
|
use super::CachedModuleCodegen;
|
||||||
|
|
||||||
use abi;
|
use abi;
|
||||||
use back::lto;
|
|
||||||
use back::write::{self, OngoingCodegen};
|
use back::write::{self, OngoingCodegen};
|
||||||
use llvm::{self, TypeKind, get_param};
|
use llvm::{self, TypeKind, get_param};
|
||||||
use metadata;
|
use metadata;
|
||||||
|
@ -45,7 +44,7 @@ use rustc::middle::cstore::{self, LinkagePreference};
|
||||||
use rustc::middle::exported_symbols;
|
use rustc::middle::exported_symbols;
|
||||||
use rustc::util::common::{time, print_time_passes_entry};
|
use rustc::util::common::{time, print_time_passes_entry};
|
||||||
use rustc::util::profiling::ProfileCategory;
|
use rustc::util::profiling::ProfileCategory;
|
||||||
use rustc::session::config::{self, DebugInfo, EntryFnType};
|
use rustc::session::config::{self, DebugInfo, EntryFnType, Lto};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use rustc_incremental;
|
use rustc_incremental;
|
||||||
use allocator;
|
use allocator;
|
||||||
|
@ -698,77 +697,48 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
enum CguReUsable {
|
enum CguReUsable {
|
||||||
No,
|
PreLto,
|
||||||
PreThinLto,
|
PostLto,
|
||||||
PostThinLto,
|
No
|
||||||
PostThinLtoButImportedFrom,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_cgu_reuse<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn determine_cgu_reuse<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
codegen_units: &[Arc<CodegenUnit<'tcx>>])
|
cgu: &CodegenUnit<'tcx>)
|
||||||
-> FxHashMap<InternedString, CguReUsable> {
|
-> CguReUsable {
|
||||||
if !tcx.dep_graph.is_fully_enabled() {
|
if !tcx.dep_graph.is_fully_enabled() {
|
||||||
return codegen_units.iter()
|
return CguReUsable::No
|
||||||
.map(|cgu| (cgu.name().clone(), CguReUsable::No))
|
|
||||||
.collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let thin_lto_imports = load_thin_lto_imports(tcx.sess);
|
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.
|
||||||
|
return CguReUsable::No
|
||||||
|
}
|
||||||
|
|
||||||
let mut reusable_cgus = FxHashMap();
|
// Try to mark the CGU as green. If it we can do so, it means that nothing
|
||||||
let mut green_cgus = FxHashMap();
|
// affecting the LLVM module has changed and we can re-use a cached version.
|
||||||
let mut need_for_importing = FxHashSet();
|
// If we compile with any kind of LTO, this means we can re-use the bitcode
|
||||||
|
// of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
|
||||||
|
// know that later). If we are not doing LTO, there is only one optimized
|
||||||
|
// version of each module, so we re-use that.
|
||||||
|
let dep_node = cgu.codegen_dep_node(tcx);
|
||||||
|
assert!(!tcx.dep_graph.dep_node_exists(&dep_node),
|
||||||
|
"CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
|
||||||
|
cgu.name());
|
||||||
|
|
||||||
for cgu in codegen_units {
|
if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
|
||||||
let work_product_id = &cgu.work_product_id();
|
// We can re-use either the pre- or the post-thinlto state
|
||||||
if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
|
if tcx.sess.lto() != Lto::No {
|
||||||
// We don't have anything cached for this CGU. This can happen
|
CguReUsable::PreLto
|
||||||
// if the CGU did not exist in the previous session.
|
|
||||||
reusable_cgus.insert(cgu.name().clone(), CguReUsable::No);
|
|
||||||
continue
|
|
||||||
};
|
|
||||||
// Try to mark the CGU as green
|
|
||||||
let dep_node = cgu.codegen_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() {
|
|
||||||
// We can re-use either the pre- or the post-thinlto state
|
|
||||||
green_cgus.insert(cgu.name().to_string(), cgu);
|
|
||||||
} else {
|
} else {
|
||||||
// We definitely cannot re-use this CGU
|
CguReUsable::PostLto
|
||||||
reusable_cgus.insert(cgu.name().clone(), CguReUsable::No);
|
|
||||||
|
|
||||||
let imported_cgus = thin_lto_imports.modules_imported_by(&cgu.name().as_str());
|
|
||||||
need_for_importing.extend(imported_cgus.iter().cloned());
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
CguReUsable::No
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, cgu) 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_key(&imported_cgu[..])
|
|
||||||
});
|
|
||||||
if all_imports_green {
|
|
||||||
reusable_cgus.insert(cgu.name().clone(), CguReUsable::PostThinLto);
|
|
||||||
} else {
|
|
||||||
reusable_cgus.insert(cgu.name().clone(), CguReUsable::PreThinLto);
|
|
||||||
need_for_importing.extend(imported_cgus.iter().cloned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name, state) in reusable_cgus.iter_mut() {
|
|
||||||
if *state == CguReUsable::PostThinLto && need_for_importing.contains(&name.as_str()[..]) {
|
|
||||||
*state = CguReUsable::PostThinLtoButImportedFrom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reusable_cgus
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
@ -920,13 +890,11 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let mut total_codegen_time = Duration::new(0, 0);
|
let mut total_codegen_time = Duration::new(0, 0);
|
||||||
let mut all_stats = Stats::default();
|
let mut all_stats = Stats::default();
|
||||||
|
|
||||||
let cgu_reuse = determine_cgu_reuse(tcx, &codegen_units);
|
|
||||||
|
|
||||||
for cgu in codegen_units.into_iter() {
|
for cgu in codegen_units.into_iter() {
|
||||||
ongoing_codegen.wait_for_signal_to_codegen_item();
|
ongoing_codegen.wait_for_signal_to_codegen_item();
|
||||||
ongoing_codegen.check_for_errors(tcx.sess);
|
ongoing_codegen.check_for_errors(tcx.sess);
|
||||||
|
|
||||||
let loaded_from_cache = match cgu_reuse[cgu.name()] {
|
let loaded_from_cache = match determine_cgu_reuse(tcx, &cgu) {
|
||||||
CguReUsable::No => {
|
CguReUsable::No => {
|
||||||
let _timing_guard = time_graph.as_ref().map(|time_graph| {
|
let _timing_guard = time_graph.as_ref().map(|time_graph| {
|
||||||
time_graph.start(write::CODEGEN_WORKER_TIMELINE,
|
time_graph.start(write::CODEGEN_WORKER_TIMELINE,
|
||||||
|
@ -939,21 +907,14 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
total_codegen_time += start_time.elapsed();
|
total_codegen_time += start_time.elapsed();
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
CguReUsable::PreThinLto => {
|
CguReUsable::PreLto => {
|
||||||
write::submit_pre_lto_module_to_llvm(tcx, CachedModuleCodegen {
|
write::submit_pre_lto_module_to_llvm(tcx, CachedModuleCodegen {
|
||||||
name: cgu.name().to_string(),
|
name: cgu.name().to_string(),
|
||||||
source: cgu.work_product(tcx),
|
source: cgu.work_product(tcx),
|
||||||
});
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
CguReUsable::PostThinLtoButImportedFrom => {
|
CguReUsable::PostLto => {
|
||||||
write::submit_import_only_module_to_llvm(tcx, CachedModuleCodegen {
|
|
||||||
name: cgu.name().to_string(),
|
|
||||||
source: cgu.work_product(tcx),
|
|
||||||
});
|
|
||||||
true
|
|
||||||
}
|
|
||||||
CguReUsable::PostThinLto => {
|
|
||||||
write::submit_post_lto_module_to_llvm(tcx, CachedModuleCodegen {
|
write::submit_post_lto_module_to_llvm(tcx, CachedModuleCodegen {
|
||||||
name: cgu.name().to_string(),
|
name: cgu.name().to_string(),
|
||||||
source: cgu.work_product(tcx),
|
source: cgu.work_product(tcx),
|
||||||
|
@ -1391,28 +1352,6 @@ pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_thin_lto_imports(sess: &Session) -> lto::ThinLTOImports {
|
|
||||||
if sess.opts.incremental.is_none() {
|
|
||||||
return lto::ThinLTOImports::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
|
// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
|
||||||
// the HashStable trait. Normally DepGraph::with_task() calls are
|
// the HashStable trait. Normally DepGraph::with_task() calls are
|
||||||
// hidden behind queries, but CGU creation is a special case in two
|
// hidden behind queries, but CGU creation is a special case in two
|
||||||
|
|
|
@ -36,7 +36,6 @@ pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
|
||||||
WorkProductFileKind::Object => "o",
|
WorkProductFileKind::Object => "o",
|
||||||
WorkProductFileKind::Bytecode => "bc",
|
WorkProductFileKind::Bytecode => "bc",
|
||||||
WorkProductFileKind::BytecodeCompressed => "bc.z",
|
WorkProductFileKind::BytecodeCompressed => "bc.z",
|
||||||
WorkProductFileKind::PreThinLtoBytecode => "pre-thinlto.bc",
|
|
||||||
};
|
};
|
||||||
let file_name = format!("{}.{}", cgu_name, extension);
|
let file_name = format!("{}.{}", cgu_name, extension);
|
||||||
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
|
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
|
||||||
|
|
Loading…
Reference in New Issue