Skip to content

Commit d97d1e1

Browse files
Persist ThinLTO import data in incr. comp. session directory.
1 parent 2e587df commit d97d1e1

File tree

5 files changed

+139
-4
lines changed

5 files changed

+139
-4
lines changed

src/librustc_codegen_llvm/back/lto.rs

+116-3
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,23 @@ use rustc::hir::def_id::LOCAL_CRATE;
2020
use rustc::middle::exported_symbols::SymbolExportLevel;
2121
use rustc::session::config::{self, Lto};
2222
use rustc::util::common::time_ext;
23+
use rustc_data_structures::fx::FxHashMap;
2324
use time_graph::Timeline;
2425
use {ModuleCodegen, ModuleLlvm, ModuleKind, ModuleSource};
2526

2627
use libc;
2728

28-
use std::ffi::CString;
29+
use std::ffi::{CStr, CString};
30+
use std::fs::File;
31+
use std::io;
32+
use std::mem;
33+
use std::path::Path;
2934
use std::ptr;
3035
use std::slice;
3136
use std::sync::Arc;
3237

38+
pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-imports.bin";
39+
3340
pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
3441
match crate_type {
3542
config::CrateType::Executable |
@@ -199,7 +206,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
199206
unreachable!("We should never reach this case if the LTO step \
200207
is deferred to the linker");
201208
}
202-
thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
209+
thin_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
203210
}
204211
Lto::No => unreachable!(),
205212
}
@@ -362,7 +369,8 @@ impl Drop for Linker<'a> {
362369
/// calculating the *index* for ThinLTO. This index will then be shared amongst
363370
/// all of the `LtoModuleCodegen` units returned below and destroyed once
364371
/// they all go out of scope.
365-
fn thin_lto(diag_handler: &Handler,
372+
fn thin_lto(cgcx: &CodegenContext,
373+
diag_handler: &Handler,
366374
modules: Vec<ModuleCodegen>,
367375
serialized_modules: Vec<(SerializedModule, CString)>,
368376
symbol_white_list: &[*const libc::c_char],
@@ -439,6 +447,17 @@ fn thin_lto(diag_handler: &Handler,
439447
write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
440448
})?;
441449

450+
// Save the ThinLTO import information for incremental compilation.
451+
if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
452+
let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME);
453+
let imports = ThinLTOImports::from_thin_lto_data(data);
454+
if let Err(err) = imports.save_to_file(&path) {
455+
let msg = format!("Error while writing ThinLTO import data: {}",
456+
err);
457+
return Err(write::llvm_err(&diag_handler, msg));
458+
}
459+
}
460+
442461
let data = ThinData(data);
443462
info!("thin LTO data created");
444463
timeline.record("data");
@@ -776,3 +795,97 @@ impl ThinModule {
776795
Ok(module)
777796
}
778797
}
798+
799+
#[derive(Debug)]
800+
pub struct ThinLTOImports {
801+
// key = llvm name of importing module, value = list of modules it imports from
802+
imports: FxHashMap<String, Vec<String>>,
803+
}
804+
805+
impl ThinLTOImports {
806+
pub fn new() -> ThinLTOImports {
807+
ThinLTOImports {
808+
imports: FxHashMap(),
809+
}
810+
}
811+
812+
/// Load the ThinLTO import map from ThinLTOData.
813+
unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports {
814+
fn module_name_to_str(c_str: &CStr) -> &str {
815+
match c_str.to_str() {
816+
Ok(s) => s,
817+
Err(e) => {
818+
bug!("Encountered non-utf8 LLVM module name `{}`: {}",
819+
c_str.to_string_lossy(),
820+
e)
821+
}
822+
}
823+
}
824+
unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void,
825+
importing_module_name: *const libc::c_char,
826+
imported_module_name: *const libc::c_char) {
827+
let map = &mut* (payload as *mut ThinLTOImports);
828+
let importing_module_name = CStr::from_ptr(importing_module_name);
829+
let importing_module_name = module_name_to_str(&importing_module_name);
830+
let imported_module_name = CStr::from_ptr(imported_module_name);
831+
let imported_module_name = module_name_to_str(&imported_module_name);
832+
if !map.imports.contains_key(importing_module_name) {
833+
map.imports.insert(importing_module_name.to_owned(), vec![]);
834+
}
835+
map.imports
836+
.get_mut(importing_module_name)
837+
.unwrap()
838+
.push(imported_module_name.to_owned());
839+
}
840+
let mut map = ThinLTOImports {
841+
imports: FxHashMap(),
842+
};
843+
llvm::LLVMRustGetThinLTOModuleImports(data,
844+
imported_module_callback,
845+
&mut map as *mut _ as *mut libc::c_void);
846+
map
847+
}
848+
849+
pub fn save_to_file(&self, path: &Path) -> io::Result<()> {
850+
use std::io::Write;
851+
let file = File::create(path)?;
852+
let mut writer = io::BufWriter::new(file);
853+
for (importing_module_name, imported_modules) in &self.imports {
854+
writeln!(writer, "{}", importing_module_name)?;
855+
for imported_module in imported_modules {
856+
writeln!(writer, " {}", imported_module)?;
857+
}
858+
writeln!(writer)?;
859+
}
860+
Ok(())
861+
}
862+
863+
pub fn load_from_file(path: &Path) -> io::Result<ThinLTOImports> {
864+
use std::io::BufRead;
865+
let mut imports = FxHashMap();
866+
let mut current_module = None;
867+
let mut current_imports = vec![];
868+
let file = File::open(path)?;
869+
for line in io::BufReader::new(file).lines() {
870+
let line = line?;
871+
if line.is_empty() {
872+
let importing_module = current_module
873+
.take()
874+
.expect("Importing module not set");
875+
imports.insert(importing_module,
876+
mem::replace(&mut current_imports, vec![]));
877+
} else if line.starts_with(" ") {
878+
// This is an imported module
879+
assert_ne!(current_module, None);
880+
current_imports.push(line.trim().to_string());
881+
} else {
882+
// This is the beginning of a new module
883+
assert_eq!(current_module, None);
884+
current_module = Some(line.trim().to_string());
885+
}
886+
}
887+
Ok(ThinLTOImports {
888+
imports
889+
})
890+
}
891+
}

src/librustc_codegen_llvm/base.rs

+20
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use super::ModuleCodegen;
2929
use super::ModuleKind;
3030

3131
use abi;
32+
use back::lto;
3233
use back::write::{self, OngoingCodegen};
3334
use llvm::{self, TypeKind, get_param};
3435
use metadata;
@@ -1314,6 +1315,25 @@ pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
13141315
}
13151316
}
13161317

1318+
#[allow(unused)]
1319+
fn load_thin_lto_imports(sess: &Session) -> lto::ThinLTOImports {
1320+
let path = rustc_incremental::in_incr_comp_dir_sess(
1321+
sess,
1322+
lto::THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME
1323+
);
1324+
if !path.exists() {
1325+
return lto::ThinLTOImports::new();
1326+
}
1327+
match lto::ThinLTOImports::load_from_file(&path) {
1328+
Ok(imports) => imports,
1329+
Err(e) => {
1330+
let msg = format!("Error while trying to load ThinLTO import data \
1331+
for incremental compilation: {}", e);
1332+
sess.fatal(&msg)
1333+
}
1334+
}
1335+
}
1336+
13171337
// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
13181338
// the HashStable trait. Normally DepGraph::with_task() calls are
13191339
// hidden behind queries, but CGU creation is a special case in two

src/librustc_codegen_llvm/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ mod back {
100100
mod command;
101101
pub mod linker;
102102
pub mod link;
103-
mod lto;
103+
pub mod lto;
104104
pub mod symbol_export;
105105
pub mod write;
106106
mod rpath;

src/librustc_incremental/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
4444
pub use persist::save_dep_graph;
4545
pub use persist::save_work_product_index;
4646
pub use persist::in_incr_comp_dir;
47+
pub use persist::in_incr_comp_dir_sess;
4748
pub use persist::prepare_session_directory;
4849
pub use persist::finalize_session_directory;
4950
pub use persist::delete_workproduct_files;

src/librustc_incremental/persist/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod file_format;
2323
pub use self::fs::finalize_session_directory;
2424
pub use self::fs::garbage_collect_session_directories;
2525
pub use self::fs::in_incr_comp_dir;
26+
pub use self::fs::in_incr_comp_dir_sess;
2627
pub use self::fs::prepare_session_directory;
2728
pub use self::load::dep_graph_tcx_init;
2829
pub use self::load::load_dep_graph;

0 commit comments

Comments
 (0)