From 8dc7ddb9763f28b83de7bf3b3025f8042ea9e830 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 9 Jul 2018 17:00:24 +0200 Subject: [PATCH] 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 28b9d2e7afa..ef03e76f946 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 179fffc4e7f..ca4b1fe44ae 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 a2f28417520..a1d9f02f458 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -89,7 +89,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 3839c133a6e..cc560ed4580 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 e1f00db56d5..17d36ba3fa7 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;