rustc: Move bytecode compression into codegen

This commit moves compression of the bytecode from the `link` module to the
`write` module, namely allowing it to be (a) cached by incremental compilation
and (b) produced in parallel. The parallelization may show up as some nice wins
during normal compilation and the caching in incremental mode should be
beneficial for incremental compiles! (no more need to recompress the entire
crate's bitcode on all builds)
This commit is contained in:
Alex Crichton 2017-10-19 18:44:33 -07:00
parent ff8773d7be
commit 8197a0bbaf
7 changed files with 194 additions and 176 deletions

View File

@ -12,7 +12,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
StableHashingContextProvider}; StableHashingContextProvider};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use session::config::OutputType;
use std::cell::{Ref, RefCell}; use std::cell::{Ref, RefCell};
use std::env; use std::env;
use std::hash::Hash; use std::hash::Hash;
@ -647,7 +646,14 @@ impl DepGraph {
pub struct WorkProduct { pub struct WorkProduct {
pub cgu_name: String, pub cgu_name: String,
/// Saved files associated with this CGU /// Saved files associated with this CGU
pub saved_files: Vec<(OutputType, String)>, pub saved_files: Vec<(WorkProductFileKind, String)>,
}
#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
pub enum WorkProductFileKind {
Object,
Bytecode,
BytecodeCompressed,
} }
pub(super) struct CurrentDepGraph { pub(super) struct CurrentDepGraph {

View File

@ -21,6 +21,7 @@ mod serialized;
pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs}; pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs};
pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor}; pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor};
pub use self::graph::WorkProductFileKind;
pub use self::prev::PreviousDepGraph; pub use self::prev::PreviousDepGraph;
pub use self::query::DepGraphQuery; pub use self::query::DepGraphQuery;
pub use self::safe::AssertDepGraphSafe; pub use self::safe::AssertDepGraphSafe;

View File

@ -11,9 +11,8 @@
//! This module contains files for saving intermediate work-products. //! This module contains files for saving intermediate work-products.
use persist::fs::*; use persist::fs::*;
use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph}; use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
use rustc::session::Session; use rustc::session::Session;
use rustc::session::config::OutputType;
use rustc::util::fs::link_or_copy; use rustc::util::fs::link_or_copy;
use std::path::PathBuf; use std::path::PathBuf;
use std::fs as std_fs; use std::fs as std_fs;
@ -21,19 +20,24 @@ use std::fs as std_fs;
pub fn save_trans_partition(sess: &Session, pub fn save_trans_partition(sess: &Session,
dep_graph: &DepGraph, dep_graph: &DepGraph,
cgu_name: &str, cgu_name: &str,
files: &[(OutputType, PathBuf)]) { files: &[(WorkProductFileKind, PathBuf)]) {
debug!("save_trans_partition({:?},{:?})", debug!("save_trans_partition({:?},{:?})",
cgu_name, cgu_name,
files); files);
if sess.opts.incremental.is_none() { if sess.opts.incremental.is_none() {
return; return
} }
let work_product_id = WorkProductId::from_cgu_name(cgu_name); let work_product_id = WorkProductId::from_cgu_name(cgu_name);
let saved_files: Option<Vec<_>> = let saved_files: Option<Vec<_>> =
files.iter() files.iter()
.map(|&(kind, ref path)| { .map(|&(kind, ref path)| {
let file_name = format!("cgu-{}.{}", cgu_name, kind.extension()); let extension = match kind {
WorkProductFileKind::Object => "o",
WorkProductFileKind::Bytecode => "bc",
WorkProductFileKind::BytecodeCompressed => "bc-compressed",
};
let file_name = format!("cgu-{}.{}", 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);
match link_or_copy(path, &path_in_incr_dir) { match link_or_copy(path, &path_in_incr_dir) {
Ok(_) => Some((kind, file_name)), Ok(_) => Some((kind, file_name)),

View File

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use super::archive::{ArchiveBuilder, ArchiveConfig}; use super::archive::{ArchiveBuilder, ArchiveConfig};
use super::bytecode::{self, RLIB_BYTECODE_EXTENSION}; use super::bytecode::RLIB_BYTECODE_EXTENSION;
use super::linker::Linker; use super::linker::Linker;
use super::command::Command; use super::command::Command;
use super::rpath::RPathConfig; use super::rpath::RPathConfig;
@ -37,7 +37,7 @@ use std::env;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt; use std::fmt;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{self, Read, Write, BufWriter}; use std::io::{self, Write, BufWriter};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Output, Stdio}; use std::process::{Output, Stdio};
use std::str; use std::str;
@ -126,14 +126,6 @@ fn command_path(sess: &Session) -> OsString {
env::join_paths(new_path).unwrap() env::join_paths(new_path).unwrap()
} }
fn metadata_obj(outputs: &OutputFilenames) -> PathBuf {
outputs.temp_path(OutputType::Object, Some(METADATA_MODULE_NAME))
}
fn allocator_obj(outputs: &OutputFilenames) -> PathBuf {
outputs.temp_path(OutputType::Object, Some(ALLOCATOR_MODULE_NAME))
}
pub fn remove(sess: &Session, path: &Path) { pub fn remove(sess: &Session, path: &Path) {
match fs::remove_file(path) { match fs::remove_file(path) {
Ok(..) => {} Ok(..) => {}
@ -175,13 +167,23 @@ pub fn link_binary(sess: &Session,
// Remove the temporary object file and metadata if we aren't saving temps // Remove the temporary object file and metadata if we aren't saving temps
if !sess.opts.cg.save_temps { if !sess.opts.cg.save_temps {
if sess.opts.output_types.should_trans() { if sess.opts.output_types.should_trans() {
for obj in trans.modules.iter() { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
remove(sess, &obj.object); remove(sess, obj);
} }
} }
remove(sess, &metadata_obj(outputs)); for obj in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
if trans.allocator_module.is_some() { remove(sess, obj);
remove(sess, &allocator_obj(outputs)); }
if let Some(ref obj) = trans.metadata_module.object {
remove(sess, obj);
}
if let Some(ref allocator) = trans.allocator_module {
if let Some(ref obj) = allocator.object {
remove(sess, obj);
}
if let Some(ref bc) = allocator.bytecode_compressed {
remove(sess, bc);
}
} }
} }
@ -256,8 +258,8 @@ fn link_binary_output(sess: &Session,
crate_type: config::CrateType, crate_type: config::CrateType,
outputs: &OutputFilenames, outputs: &OutputFilenames,
crate_name: &str) -> Vec<PathBuf> { crate_name: &str) -> Vec<PathBuf> {
for module in trans.modules.iter() { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
check_file_is_writeable(&module.object, sess); check_file_is_writeable(obj, sess);
} }
let tmpdir = match TempDir::new("rustc") { let tmpdir = match TempDir::new("rustc") {
@ -280,20 +282,14 @@ fn link_binary_output(sess: &Session,
link_rlib(sess, link_rlib(sess,
trans, trans,
RlibFlavor::Normal, RlibFlavor::Normal,
outputs,
&out_filename, &out_filename,
tmpdir.path()).build(); tmpdir.path()).build();
} }
config::CrateTypeStaticlib => { config::CrateTypeStaticlib => {
link_staticlib(sess, link_staticlib(sess, trans, &out_filename, tmpdir.path());
trans,
outputs,
&out_filename,
tmpdir.path());
} }
_ => { _ => {
link_natively(sess, crate_type, &out_filename, link_natively(sess, crate_type, &out_filename, trans, tmpdir.path());
trans, outputs, tmpdir.path());
} }
} }
out_filenames.push(out_filename); out_filenames.push(out_filename);
@ -349,14 +345,13 @@ enum RlibFlavor {
fn link_rlib<'a>(sess: &'a Session, fn link_rlib<'a>(sess: &'a Session,
trans: &CrateTranslation, trans: &CrateTranslation,
flavor: RlibFlavor, flavor: RlibFlavor,
outputs: &OutputFilenames,
out_filename: &Path, out_filename: &Path,
tmpdir: &Path) -> ArchiveBuilder<'a> { tmpdir: &Path) -> ArchiveBuilder<'a> {
info!("preparing rlib to {:?}", out_filename); info!("preparing rlib to {:?}", out_filename);
let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None));
for module in trans.modules.iter() { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
ab.add_file(&module.object); ab.add_file(obj);
} }
// Note that in this loop we are ignoring the value of `lib.cfg`. That is, // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
@ -421,56 +416,9 @@ fn link_rlib<'a>(sess: &'a Session,
ab.add_file(&metadata); ab.add_file(&metadata);
// For LTO purposes, the bytecode of this library is also inserted // For LTO purposes, the bytecode of this library is also inserted
// into the archive. If codegen_units > 1, we insert each of the // into the archive.
// bitcode files. for bytecode in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
for module in trans.modules.iter() { ab.add_file(bytecode);
// Note that we make sure that the bytecode filename in the
// archive is never exactly 16 bytes long by adding a 16 byte
// extension to it. This is to work around a bug in LLDB that
// would cause it to crash if the name of a file in an archive
// was exactly 16 bytes.
let bc_filename = module.object.with_extension("bc");
let bc_encoded_filename = tmpdir.join({
module.object.with_extension(RLIB_BYTECODE_EXTENSION).file_name().unwrap()
});
let mut bc_data = Vec::new();
match fs::File::open(&bc_filename).and_then(|mut f| {
f.read_to_end(&mut bc_data)
}) {
Ok(..) => {}
Err(e) => sess.fatal(&format!("failed to read bytecode: {}",
e))
}
let encoded = bytecode::encode(&module.llmod_id, &bc_data);
let mut bc_file_deflated = match fs::File::create(&bc_encoded_filename) {
Ok(file) => file,
Err(e) => {
sess.fatal(&format!("failed to create compressed \
bytecode file: {}", e))
}
};
match bc_file_deflated.write_all(&encoded) {
Ok(()) => {}
Err(e) => {
sess.fatal(&format!("failed to write compressed \
bytecode: {}", e));
}
};
ab.add_file(&bc_encoded_filename);
// See the bottom of back::write::run_passes for an explanation
// of when we do and don't keep .#module-name#.bc files around.
let user_wants_numbered_bitcode =
sess.opts.output_types.contains_key(&OutputType::Bitcode) &&
sess.codegen_units() > 1;
if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
remove(sess, &bc_filename);
}
} }
// After adding all files to the archive, we need to update the // After adding all files to the archive, we need to update the
@ -482,8 +430,11 @@ fn link_rlib<'a>(sess: &'a Session,
} }
RlibFlavor::StaticlibBase => { RlibFlavor::StaticlibBase => {
if trans.allocator_module.is_some() { let obj = trans.allocator_module
ab.add_file(&allocator_obj(outputs)); .as_ref()
.and_then(|m| m.object.as_ref());
if let Some(obj) = obj {
ab.add_file(obj);
} }
} }
} }
@ -505,13 +456,11 @@ fn link_rlib<'a>(sess: &'a Session,
// metadata file). // metadata file).
fn link_staticlib(sess: &Session, fn link_staticlib(sess: &Session,
trans: &CrateTranslation, trans: &CrateTranslation,
outputs: &OutputFilenames,
out_filename: &Path, out_filename: &Path,
tempdir: &Path) { tempdir: &Path) {
let mut ab = link_rlib(sess, let mut ab = link_rlib(sess,
trans, trans,
RlibFlavor::StaticlibBase, RlibFlavor::StaticlibBase,
outputs,
out_filename, out_filename,
tempdir); tempdir);
let mut all_native_libs = vec![]; let mut all_native_libs = vec![];
@ -616,7 +565,6 @@ fn link_natively(sess: &Session,
crate_type: config::CrateType, crate_type: config::CrateType,
out_filename: &Path, out_filename: &Path,
trans: &CrateTranslation, trans: &CrateTranslation,
outputs: &OutputFilenames,
tmpdir: &Path) { tmpdir: &Path) {
info!("preparing {:?} to {:?}", crate_type, out_filename); info!("preparing {:?} to {:?}", crate_type, out_filename);
let flavor = sess.linker_flavor(); let flavor = sess.linker_flavor();
@ -656,7 +604,7 @@ fn link_natively(sess: &Session,
{ {
let mut linker = trans.linker_info.to_linker(cmd, &sess); let mut linker = trans.linker_info.to_linker(cmd, &sess);
link_args(&mut *linker, sess, crate_type, tmpdir, link_args(&mut *linker, sess, crate_type, tmpdir,
out_filename, outputs, trans); out_filename, trans);
cmd = linker.finalize(); cmd = linker.finalize();
} }
if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
@ -878,7 +826,6 @@ fn link_args(cmd: &mut Linker,
crate_type: config::CrateType, crate_type: config::CrateType,
tmpdir: &Path, tmpdir: &Path,
out_filename: &Path, out_filename: &Path,
outputs: &OutputFilenames,
trans: &CrateTranslation) { trans: &CrateTranslation) {
// The default library location, we need this to find the runtime. // The default library location, we need this to find the runtime.
@ -889,8 +836,8 @@ fn link_args(cmd: &mut Linker,
let t = &sess.target.target; let t = &sess.target.target;
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
for module in trans.modules.iter() { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
cmd.add_object(&module.object); cmd.add_object(obj);
} }
cmd.output_filename(out_filename); cmd.output_filename(out_filename);
@ -913,11 +860,16 @@ fn link_args(cmd: &mut Linker,
// object file, so we link that in here. // object file, so we link that in here.
if crate_type == config::CrateTypeDylib || if crate_type == config::CrateTypeDylib ||
crate_type == config::CrateTypeProcMacro { crate_type == config::CrateTypeProcMacro {
cmd.add_object(&metadata_obj(outputs)); if let Some(obj) = trans.metadata_module.object.as_ref() {
cmd.add_object(obj);
}
} }
if trans.allocator_module.is_some() { let obj = trans.allocator_module
cmd.add_object(&allocator_obj(outputs)); .as_ref()
.and_then(|m| m.object.as_ref());
if let Some(obj) = obj {
cmd.add_object(obj);
} }
// Try to strip as much out of the generated object by removing unused // Try to strip as much out of the generated object by removing unused
@ -1185,9 +1137,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
for f in archive.src_files() { for f in archive.src_files() {
if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
archive.remove_file(&f); archive.remove_file(&f);
continue continue
} }
} }
archive.build(); archive.build();

View File

@ -343,8 +343,7 @@ fn thin_lto(diag_handler: &Handler,
info!("local module: {} - {}", i, module.llmod_id); info!("local module: {} - {}", i, module.llmod_id);
let llvm = module.llvm().expect("can't lto pretranslated module"); let llvm = module.llvm().expect("can't lto pretranslated module");
let name = CString::new(module.llmod_id.clone()).unwrap(); let name = CString::new(module.llmod_id.clone()).unwrap();
let buffer = llvm::LLVMRustThinLTOBufferCreate(llvm.llmod); let buffer = ThinBuffer::new(llvm.llmod);
let buffer = ThinBuffer(buffer);
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(),
@ -499,13 +498,13 @@ unsafe impl Send for ModuleBuffer {}
unsafe impl Sync for ModuleBuffer {} unsafe impl Sync for ModuleBuffer {}
impl ModuleBuffer { impl ModuleBuffer {
fn new(m: ModuleRef) -> ModuleBuffer { pub fn new(m: ModuleRef) -> ModuleBuffer {
ModuleBuffer(unsafe { ModuleBuffer(unsafe {
llvm::LLVMRustModuleBufferCreate(m) llvm::LLVMRustModuleBufferCreate(m)
}) })
} }
fn data(&self) -> &[u8] { pub fn data(&self) -> &[u8] {
unsafe { unsafe {
let ptr = llvm::LLVMRustModuleBufferPtr(self.0); let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
let len = llvm::LLVMRustModuleBufferLen(self.0); let len = llvm::LLVMRustModuleBufferLen(self.0);
@ -545,13 +544,20 @@ impl Drop for ThinData {
} }
} }
struct ThinBuffer(*mut llvm::ThinLTOBuffer); pub struct ThinBuffer(*mut llvm::ThinLTOBuffer);
unsafe impl Send for ThinBuffer {} unsafe impl Send for ThinBuffer {}
unsafe impl Sync for ThinBuffer {} unsafe impl Sync for ThinBuffer {}
impl ThinBuffer { impl ThinBuffer {
fn data(&self) -> &[u8] { pub fn new(m: ModuleRef) -> ThinBuffer {
unsafe {
let buffer = llvm::LLVMRustThinLTOBufferCreate(m);
ThinBuffer(buffer)
}
}
pub fn data(&self) -> &[u8] {
unsafe { unsafe {
let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _; let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
let len = llvm::LLVMRustThinLTOBufferLen(self.0); let len = llvm::LLVMRustThinLTOBufferLen(self.0);

View File

@ -8,14 +8,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use back::lto; use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
use back::lto::{self, ModuleBuffer, ThinBuffer};
use back::link::{self, get_linker, remove}; use back::link::{self, get_linker, remove};
use back::linker::LinkerInfo; use back::linker::LinkerInfo;
use back::symbol_export::ExportedSymbols; use back::symbol_export::ExportedSymbols;
use base; use base;
use consts; use consts;
use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
use rustc::dep_graph::DepGraph; use rustc::dep_graph::{DepGraph, WorkProductFileKind};
use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses, use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
AllPasses, Sanitizer}; AllPasses, Sanitizer};
@ -44,7 +45,7 @@ use rustc_demangle;
use std::any::Any; use std::any::Any;
use std::ffi::{CString, CStr}; use std::ffi::{CString, CStr};
use std::fs; use std::fs::{self, File};
use std::io; use std::io;
use std::io::Write; use std::io::Write;
use std::mem; use std::mem;
@ -228,6 +229,7 @@ pub struct ModuleConfig {
// Flags indicating which outputs to produce. // Flags indicating which outputs to produce.
emit_no_opt_bc: bool, emit_no_opt_bc: bool,
emit_bc: bool, emit_bc: bool,
emit_bc_compressed: bool,
emit_lto_bc: bool, emit_lto_bc: bool,
emit_ir: bool, emit_ir: bool,
emit_asm: bool, emit_asm: bool,
@ -257,6 +259,7 @@ impl ModuleConfig {
emit_no_opt_bc: false, emit_no_opt_bc: false,
emit_bc: false, emit_bc: false,
emit_bc_compressed: false,
emit_lto_bc: false, emit_lto_bc: false,
emit_ir: false, emit_ir: false,
emit_asm: false, emit_asm: false,
@ -627,20 +630,34 @@ unsafe fn codegen(cgcx: &CodegenContext,
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
if write_bc {
let bc_out_c = path2cstr(&bc_out); if write_bc || config.emit_bc_compressed {
if llvm::LLVMRustThinLTOAvailable() { let thin;
with_codegen(tm, llmod, config.no_builtins, |cpm| { let old;
llvm::LLVMRustWriteThinBitcodeToFile( let data = if llvm::LLVMRustThinLTOAvailable() {
cpm, thin = ThinBuffer::new(llmod);
llmod, thin.data()
bc_out_c.as_ptr(),
)
});
} else { } else {
llvm::LLVMWriteBitcodeToFile(llmod, bc_out_c.as_ptr()); old = ModuleBuffer::new(llmod);
old.data()
};
timeline.record("make-bc");
if write_bc {
if let Err(e) = File::create(&bc_out).and_then(|mut f| f.write_all(data)) {
diag_handler.err(&format!("failed to write bytecode: {}", e));
}
timeline.record("write-bc");
}
if config.emit_bc_compressed {
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
let data = bytecode::encode(&mtrans.llmod_id, data);
if let Err(e) = File::create(&dst).and_then(|mut f| f.write_all(&data)) {
diag_handler.err(&format!("failed to write bytecode: {}", e));
}
timeline.record("compress-bc");
} }
timeline.record("bc");
} }
time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()), time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
@ -736,6 +753,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
drop(handlers); drop(handlers);
Ok(mtrans.into_compiled_module(config.emit_obj, Ok(mtrans.into_compiled_module(config.emit_obj,
config.emit_bc, config.emit_bc,
config.emit_bc_compressed,
&cgcx.output_filenames)) &cgcx.output_filenames))
} }
@ -822,11 +840,12 @@ pub fn start_async_translation(tcx: TyCtxt,
allocator_config.emit_bc = true; allocator_config.emit_bc = true;
} }
// Emit bitcode files for the crate if we're emitting an rlib. // Emit compressed bitcode files for the crate if we're emitting an rlib.
// Whenever an rlib is created, the bitcode is inserted into the // Whenever an rlib is created, the bitcode is inserted into the archive in
// archive in order to allow LTO against it. // order to allow LTO against it.
if need_crate_bitcode_for_rlib(sess) { if need_crate_bitcode_for_rlib(sess) {
modules_config.emit_bc = true; modules_config.emit_bc_compressed = true;
allocator_config.emit_bc_compressed = true;
} }
for output_type in output_types_override.keys() { for output_type in output_types_override.keys() {
@ -906,8 +925,7 @@ pub fn start_async_translation(tcx: TyCtxt,
fn copy_module_artifacts_into_incr_comp_cache(sess: &Session, fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
dep_graph: &DepGraph, dep_graph: &DepGraph,
compiled_modules: &CompiledModules, compiled_modules: &CompiledModules) {
crate_output: &OutputFilenames) {
if sess.opts.incremental.is_none() { if sess.opts.incremental.is_none() {
return; return;
} }
@ -915,20 +933,17 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
for module in compiled_modules.modules.iter() { for module in compiled_modules.modules.iter() {
let mut files = vec![]; let mut files = vec![];
if module.emit_obj { if let Some(ref path) = module.object {
let path = crate_output.temp_path(OutputType::Object, Some(&module.name)); files.push((WorkProductFileKind::Object, path.clone()));
files.push((OutputType::Object, path)); }
if let Some(ref path) = module.bytecode {
files.push((WorkProductFileKind::Bytecode, path.clone()));
}
if let Some(ref path) = module.bytecode_compressed {
files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
} }
if module.emit_bc { save_trans_partition(sess, dep_graph, &module.name, &files);
let path = crate_output.temp_path(OutputType::Bitcode, Some(&module.name));
files.push((OutputType::Bitcode, path));
}
save_trans_partition(sess,
dep_graph,
&module.name,
&files);
} }
} }
@ -1032,8 +1047,6 @@ fn produce_final_output_artifacts(sess: &Session,
// well. // well.
// Specific rules for keeping .#module-name#.bc: // Specific rules for keeping .#module-name#.bc:
// - If we're building an rlib (`needs_crate_bitcode`), then keep
// it.
// - If the user requested bitcode (`user_wants_bitcode`), and // - If the user requested bitcode (`user_wants_bitcode`), and
// codegen_units > 1, then keep it. // codegen_units > 1, then keep it.
// - If the user requested bitcode but codegen_units == 1, then we // - If the user requested bitcode but codegen_units == 1, then we
@ -1043,41 +1056,37 @@ fn produce_final_output_artifacts(sess: &Session,
// If you change how this works, also update back::link::link_rlib, // If you change how this works, also update back::link::link_rlib,
// where .#module-name#.bc files are (maybe) deleted after making an // where .#module-name#.bc files are (maybe) deleted after making an
// rlib. // rlib.
let needs_crate_bitcode = need_crate_bitcode_for_rlib(sess);
let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe);
let keep_numbered_bitcode = needs_crate_bitcode || let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units() > 1;
(user_wants_bitcode && sess.codegen_units() > 1);
let keep_numbered_objects = needs_crate_object || let keep_numbered_objects = needs_crate_object ||
(user_wants_objects && sess.codegen_units() > 1); (user_wants_objects && sess.codegen_units() > 1);
for module in compiled_modules.modules.iter() { for module in compiled_modules.modules.iter() {
let module_name = Some(&module.name[..]); if let Some(ref path) = module.object {
if !keep_numbered_objects {
if module.emit_obj && !keep_numbered_objects { remove(sess, path);
let path = crate_output.temp_path(OutputType::Object, module_name); }
remove(sess, &path);
} }
if module.emit_bc && !keep_numbered_bitcode { if let Some(ref path) = module.bytecode {
let path = crate_output.temp_path(OutputType::Bitcode, module_name); if !keep_numbered_bitcode {
remove(sess, &path); remove(sess, path);
}
} }
} }
if compiled_modules.metadata_module.emit_bc && !user_wants_bitcode { if !user_wants_bitcode {
let path = crate_output.temp_path(OutputType::Bitcode, if let Some(ref path) = compiled_modules.metadata_module.bytecode {
Some(&compiled_modules.metadata_module.name));
remove(sess, &path);
}
if let Some(ref allocator_module) = compiled_modules.allocator_module {
if allocator_module.emit_bc && !user_wants_bitcode {
let path = crate_output.temp_path(OutputType::Bitcode,
Some(&allocator_module.name));
remove(sess, &path); remove(sess, &path);
} }
if let Some(ref allocator_module) = compiled_modules.allocator_module {
if let Some(ref path) = allocator_module.bytecode {
remove(sess, path);
}
}
} }
} }
@ -1149,8 +1158,28 @@ fn execute_work_item(cgcx: &CodegenContext,
.as_ref() .as_ref()
.unwrap(); .unwrap();
let name = &mtrans.name; let name = &mtrans.name;
let mut object = None;
let mut bytecode = None;
let mut bytecode_compressed = None;
for (kind, saved_file) in wp.saved_files { for (kind, saved_file) in wp.saved_files {
let obj_out = cgcx.output_filenames.temp_path(kind, Some(name)); let obj_out = match kind {
WorkProductFileKind::Object => {
let path = cgcx.output_filenames.temp_path(OutputType::Object, Some(name));
object = Some(path.clone());
path
}
WorkProductFileKind::Bytecode => {
let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name));
bytecode = Some(path.clone());
path
}
WorkProductFileKind::BytecodeCompressed => {
let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name))
.with_extension(RLIB_BYTECODE_EXTENSION);
bytecode_compressed = Some(path.clone());
path
}
};
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);
debug!("copying pre-existing module `{}` from {:?} to {}", debug!("copying pre-existing module `{}` from {:?} to {}",
@ -1167,16 +1196,18 @@ fn execute_work_item(cgcx: &CodegenContext,
} }
} }
} }
let object = cgcx.output_filenames.temp_path(OutputType::Object, Some(name)); assert_eq!(object.is_some(), config.emit_obj);
assert_eq!(bytecode.is_some(), config.emit_bc);
assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed);
Ok(WorkItemResult::Compiled(CompiledModule { Ok(WorkItemResult::Compiled(CompiledModule {
object,
llmod_id: mtrans.llmod_id.clone(), llmod_id: mtrans.llmod_id.clone(),
name: module_name, name: module_name,
kind: ModuleKind::Regular, kind: ModuleKind::Regular,
pre_existing: true, pre_existing: true,
emit_bc: config.emit_bc, object,
emit_obj: config.emit_obj, bytecode,
bytecode_compressed,
})) }))
} else { } else {
debug!("llvm-optimizing {:?}", module_name); debug!("llvm-optimizing {:?}", module_name);
@ -2053,8 +2084,7 @@ impl OngoingCrateTranslation {
copy_module_artifacts_into_incr_comp_cache(sess, copy_module_artifacts_into_incr_comp_cache(sess,
dep_graph, dep_graph,
&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);
@ -2075,6 +2105,7 @@ impl OngoingCrateTranslation {
modules: compiled_modules.modules, modules: compiled_modules.modules,
allocator_module: compiled_modules.allocator_module, allocator_module: compiled_modules.allocator_module,
metadata_module: compiled_modules.metadata_module,
}; };
if self.no_integrated_as { if self.no_integrated_as {

View File

@ -64,6 +64,7 @@ extern crate serialize;
extern crate cc; // Used to locate MSVC extern crate cc; // Used to locate MSVC
pub use base::trans_crate; pub use base::trans_crate;
use back::bytecode::RLIB_BYTECODE_EXTENSION;
pub use metadata::LlvmMetadataLoader; pub use metadata::LlvmMetadataLoader;
pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug}; pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug};
@ -90,7 +91,7 @@ mod diagnostics;
pub mod back { pub mod back {
mod archive; mod archive;
mod bytecode; pub mod bytecode;
mod command; mod command;
pub(crate) mod linker; pub(crate) mod linker;
pub mod link; pub mod link;
@ -227,21 +228,37 @@ impl ModuleTranslation {
pub fn into_compiled_module(self, pub fn into_compiled_module(self,
emit_obj: bool, emit_obj: bool,
emit_bc: bool, emit_bc: bool,
emit_bc_compressed: bool,
outputs: &OutputFilenames) -> CompiledModule { outputs: &OutputFilenames) -> CompiledModule {
let pre_existing = match self.source { let pre_existing = match self.source {
ModuleSource::Preexisting(_) => true, ModuleSource::Preexisting(_) => true,
ModuleSource::Translated(_) => false, ModuleSource::Translated(_) => false,
}; };
let object = outputs.temp_path(OutputType::Object, Some(&self.name)); let object = if emit_obj {
Some(outputs.temp_path(OutputType::Object, Some(&self.name)))
} else {
None
};
let bytecode = if emit_bc {
Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)))
} else {
None
};
let bytecode_compressed = if emit_bc_compressed {
Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
.with_extension(RLIB_BYTECODE_EXTENSION))
} else {
None
};
CompiledModule { CompiledModule {
llmod_id: self.llmod_id, llmod_id: self.llmod_id,
name: self.name.clone(), name: self.name.clone(),
kind: self.kind, kind: self.kind,
pre_existing, pre_existing,
emit_obj,
emit_bc,
object, object,
bytecode,
bytecode_compressed,
} }
} }
} }
@ -250,11 +267,11 @@ impl ModuleTranslation {
pub struct CompiledModule { pub struct CompiledModule {
pub name: String, pub name: String,
pub llmod_id: String, pub llmod_id: String,
pub object: PathBuf,
pub kind: ModuleKind, pub kind: ModuleKind,
pub pre_existing: bool, pub pre_existing: bool,
pub emit_obj: bool, pub object: Option<PathBuf>,
pub emit_bc: bool, pub bytecode: Option<PathBuf>,
pub bytecode_compressed: Option<PathBuf>,
} }
pub enum ModuleSource { pub enum ModuleSource {
@ -289,6 +306,7 @@ pub struct CrateTranslation {
pub crate_name: Symbol, pub crate_name: Symbol,
pub modules: Vec<CompiledModule>, pub modules: Vec<CompiledModule>,
allocator_module: Option<CompiledModule>, allocator_module: Option<CompiledModule>,
metadata_module: CompiledModule,
pub link: rustc::middle::cstore::LinkMeta, pub link: rustc::middle::cstore::LinkMeta,
pub metadata: rustc::middle::cstore::EncodedMetadata, pub metadata: rustc::middle::cstore::EncodedMetadata,
windows_subsystem: Option<String>, windows_subsystem: Option<String>,