From ef89cc8f042a980e72e9d0262c267bfffd9e75fe Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Apr 2020 11:45:55 -0700 Subject: [PATCH] Store LLVM bitcode in object files, not compressed This commit is an attempted resurrection of #70458 where LLVM bitcode emitted by rustc into rlibs is stored into object file sections rather than in a separate file. The main rationale for doing this is that when rustc emits bitcode it will no longer use a custom compression scheme which makes it both easier to interoperate with existing tools and also cuts down on compile time since this compression isn't happening. The blocker for this in #70458 turned out to be that native linkers didn't handle the new sections well, causing the sections to either trigger bugs in the linker or actually end up in the final linked artifact. This commit attempts to address these issues by ensuring that native linkers ignore the new sections by inserting custom flags with module-level inline assembly. Note that this does not currently change the API of the compiler at all. The pre-existing `-C bitcode-in-rlib` flag is co-opted to indicate whether the bitcode should be present in the object file or not. Finally, note that an important consequence of this commit, which is also one of its primary purposes, is to enable rustc's `-Clto` bitcode loading to load rlibs produced with `-Clinker-plugin-lto`. The goal here is that when you're building with LTO Cargo will tell rustc to skip codegen of all intermediate crates and only generate LLVM IR. Today rustc will generate both object code and LLVM IR, but the object code is later simply thrown away, wastefully. --- src/doc/rustc/src/codegen-options/index.md | 46 +++--- src/librustc_codegen_llvm/back/archive.rs | 6 +- src/librustc_codegen_llvm/back/bytecode.rs | 141 ------------------ src/librustc_codegen_llvm/back/lto.rs | 48 ++++-- src/librustc_codegen_llvm/back/write.rs | 66 ++++++-- src/librustc_codegen_llvm/lib.rs | 1 - src/librustc_codegen_llvm/llvm/ffi.rs | 5 + src/librustc_codegen_ssa/back/link.rs | 22 +-- src/librustc_codegen_ssa/back/write.rs | 32 +--- src/librustc_codegen_ssa/lib.rs | 18 +-- .../persist/work_product.rs | 1 - src/librustc_query_system/dep_graph/graph.rs | 1 - src/llvm-project | 2 +- src/rustllvm/PassWrapper.cpp | 28 ++++ .../lto-rustc-loads-linker-plugin.rs | 6 + src/test/ui/lto-duplicate-symbols.stderr | 2 +- src/test/ui/lto-rustc-loads-linker-plugin.rs | 17 +++ .../ui/lto-thin-rustc-loads-linker-plugin.rs | 13 ++ 18 files changed, 189 insertions(+), 266 deletions(-) delete mode 100644 src/librustc_codegen_llvm/back/bytecode.rs create mode 100644 src/test/ui/auxiliary/lto-rustc-loads-linker-plugin.rs create mode 100644 src/test/ui/lto-rustc-loads-linker-plugin.rs create mode 100644 src/test/ui/lto-thin-rustc-loads-linker-plugin.rs diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index a503679f19bf7..14ffe161c91f8 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -7,6 +7,32 @@ a version of this list for your exact compiler by running `rustc -C help`. This option is deprecated and does nothing. +## bitcode-in-rlib + +This flag controls whether or not the compiler puts LLVM bitcode into generated +rlibs. It takes one of the following values: + +* `y`, `yes`, `on`, or no value: put bitcode in rlibs (the default). +* `n`, `no`, or `off`: omit bitcode from rlibs. + +LLVM bitcode is only needed when link-time optimization (LTO) is being +performed, but it is enabled by default for backwards compatibility reasons. + +The use of `-C bitcode-in-rlib=no` can significantly improve compile times and +reduce generated file sizes. For these reasons, Cargo uses `-C +bitcode-in-rlib=no` whenever possible. Likewise, if you are building directly +with `rustc` we recommend using `-C bitcode-in-rlib=no` whenever you are not +using LTO. + +If combined with `-C lto`, `-C bitcode-in-rlib=no` will cause `rustc` to abort +at start-up, because the combination is invalid. + +> **Note**: the implementation of this flag today is to enable the +> `-Zembed-bitcode` option. When bitcode is embedded into an rlib then all +> object files within the rlib will have a special section (typically named +> `.llvmbc`, depends on the platform though) which contains LLVM bytecode. This +> section of the object file will not appear in the final linked artifact. + ## code-model This option lets you choose which code model to use. @@ -387,26 +413,6 @@ This also supports the feature `+crt-static` and `-crt-static` to control Each target and [`target-cpu`](#target-cpu) has a default set of enabled features. -## bitcode-in-rlib - -This flag controls whether or not the compiler puts compressed LLVM bitcode -into generated rlibs. It takes one of the following values: - -* `y`, `yes`, `on`, or no value: put bitcode in rlibs (the default). -* `n`, `no`, or `off`: omit bitcode from rlibs. - -LLVM bitcode is only needed when link-time optimization (LTO) is being -performed, but it is enabled by default for backwards compatibility reasons. - -The use of `-C bitcode-in-rlib=no` can significantly improve compile times and -reduce generated file sizes. For these reasons, Cargo uses `-C -bitcode-in-rlib=no` whenever possible. Likewise, if you are building directly -with `rustc` we recommend using `-C bitcode-in-rlib=no` whenever you are not -using LTO. - -If combined with `-C lto`, `-C bitcode-in-rlib=no` will cause `rustc` to abort -at start-up, because the combination is invalid. - [option-emit]: ../command-line-arguments.md#option-emit [option-o-optimize]: ../command-line-arguments.md#option-o-optimize [profile-guided optimization]: ../profile-guided-optimization.md diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs index f1fe40d919eeb..a115a1e95163e 100644 --- a/src/librustc_codegen_llvm/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -10,7 +10,7 @@ use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; -use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; +use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -129,8 +129,8 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { let obj_start = name.to_owned(); self.add_archive(rlib, move |fname: &str| { - // Ignore bytecode/metadata files, no matter the name. - if fname.ends_with(RLIB_BYTECODE_EXTENSION) || fname == METADATA_FILENAME { + // Ignore metadata files, no matter the name. + if fname == METADATA_FILENAME { return true; } diff --git a/src/librustc_codegen_llvm/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs deleted file mode 100644 index 0c8ce39132abb..0000000000000 --- a/src/librustc_codegen_llvm/back/bytecode.rs +++ /dev/null @@ -1,141 +0,0 @@ -//! Management of the encoding of LLVM bytecode into rlibs -//! -//! This module contains the management of encoding LLVM bytecode into rlibs, -//! primarily for the usage in LTO situations. Currently the compiler will -//! unconditionally encode LLVM-IR into rlibs regardless of what's happening -//! elsewhere, so we currently compress the bytecode via deflate to avoid taking -//! up too much space on disk. -//! -//! After compressing the bytecode we then have the rest of the format to -//! basically deal with various bugs in various archive implementations. The -//! format currently is: -//! -//! RLIB LLVM-BYTECODE OBJECT LAYOUT -//! Version 2 -//! Bytes Data -//! 0..10 "RUST_OBJECT" encoded in ASCII -//! 11..14 format version as little-endian u32 -//! 15..19 the length of the module identifier string -//! 20..n the module identifier string -//! n..n+8 size in bytes of deflate compressed LLVM bitcode as -//! little-endian u64 -//! n+9.. compressed LLVM bitcode -//! ? maybe a byte to make this whole thing even length - -use std::io::{Read, Write}; -use std::ptr; -use std::str; - -use flate2::read::DeflateDecoder; -use flate2::write::DeflateEncoder; -use flate2::Compression; - -// This is the "magic number" expected at the beginning of a LLVM bytecode -// object in an rlib. -pub const RLIB_BYTECODE_OBJECT_MAGIC: &[u8] = b"RUST_OBJECT"; - -// The version number this compiler will write to bytecode objects in rlibs -pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2; - -pub fn encode(identifier: &str, bytecode: &[u8]) -> Vec { - let mut encoded = Vec::new(); - - // Start off with the magic string - encoded.extend_from_slice(RLIB_BYTECODE_OBJECT_MAGIC); - - // Next up is the version - encoded.extend_from_slice(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]); - - // Next is the LLVM module identifier length + contents - let identifier_len = identifier.len(); - encoded.extend_from_slice(&[ - (identifier_len >> 0) as u8, - (identifier_len >> 8) as u8, - (identifier_len >> 16) as u8, - (identifier_len >> 24) as u8, - ]); - encoded.extend_from_slice(identifier.as_bytes()); - - // Next is the LLVM module deflate compressed, prefixed with its length. We - // don't know its length yet, so fill in 0s - let deflated_size_pos = encoded.len(); - encoded.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); - - let before = encoded.len(); - DeflateEncoder::new(&mut encoded, Compression::fast()).write_all(bytecode).unwrap(); - let after = encoded.len(); - - // Fill in the length we reserved space for before - let bytecode_len = (after - before) as u64; - encoded[deflated_size_pos + 0] = (bytecode_len >> 0) as u8; - encoded[deflated_size_pos + 1] = (bytecode_len >> 8) as u8; - encoded[deflated_size_pos + 2] = (bytecode_len >> 16) as u8; - encoded[deflated_size_pos + 3] = (bytecode_len >> 24) as u8; - encoded[deflated_size_pos + 4] = (bytecode_len >> 32) as u8; - encoded[deflated_size_pos + 5] = (bytecode_len >> 40) as u8; - encoded[deflated_size_pos + 6] = (bytecode_len >> 48) as u8; - encoded[deflated_size_pos + 7] = (bytecode_len >> 56) as u8; - - // If the number of bytes written to the object so far is odd, add a - // padding byte to make it even. This works around a crash bug in LLDB - // (see issue #15950) - if encoded.len() % 2 == 1 { - encoded.push(0); - } - - encoded -} - -pub struct DecodedBytecode<'a> { - identifier: &'a str, - encoded_bytecode: &'a [u8], -} - -impl<'a> DecodedBytecode<'a> { - pub fn new(data: &'a [u8]) -> Result, &'static str> { - if !data.starts_with(RLIB_BYTECODE_OBJECT_MAGIC) { - return Err("magic bytecode prefix not found"); - } - let data = &data[RLIB_BYTECODE_OBJECT_MAGIC.len()..]; - if !data.starts_with(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]) { - return Err("wrong version prefix found in bytecode"); - } - let data = &data[4..]; - if data.len() < 4 { - return Err("bytecode corrupted"); - } - let identifier_len = - unsafe { u32::from_le(ptr::read_unaligned(data.as_ptr() as *const u32)) as usize }; - let data = &data[4..]; - if data.len() < identifier_len { - return Err("bytecode corrupted"); - } - let identifier = match str::from_utf8(&data[..identifier_len]) { - Ok(s) => s, - Err(_) => return Err("bytecode corrupted"), - }; - let data = &data[identifier_len..]; - if data.len() < 8 { - return Err("bytecode corrupted"); - } - let bytecode_len = - unsafe { u64::from_le(ptr::read_unaligned(data.as_ptr() as *const u64)) as usize }; - let data = &data[8..]; - if data.len() < bytecode_len { - return Err("bytecode corrupted"); - } - let encoded_bytecode = &data[..bytecode_len]; - - Ok(DecodedBytecode { identifier, encoded_bytecode }) - } - - pub fn bytecode(&self) -> Vec { - let mut data = Vec::new(); - DeflateDecoder::new(self.encoded_bytecode).read_to_end(&mut data).unwrap(); - data - } - - pub fn identifier(&self) -> &'a str { - self.identifier - } -} diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 7292492a0c02f..e65bdbe171b26 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -1,4 +1,3 @@ -use crate::back::bytecode::DecodedBytecode; use crate::back::write::{ self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers, }; @@ -10,7 +9,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, RLIB_BYTECODE_EXTENSION}; +use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{FatalError, Handler}; use rustc_hir::def_id::LOCAL_CRATE; @@ -111,22 +110,19 @@ fn prepare_lto( } let archive = ArchiveRO::open(&path).expect("wanted an rlib"); - let bytecodes = archive + let obj_files = archive .iter() .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c)))) - .filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION)); - for (name, data) in bytecodes { - let _timer = - cgcx.prof.generic_activity_with_arg("LLVM_lto_load_upstream_bitcode", name); - info!("adding bytecode {}", name); - let bc_encoded = data.data(); - - let (bc, id) = match DecodedBytecode::new(bc_encoded) { - Ok(b) => Ok((b.bytecode(), b.identifier().to_string())), - Err(e) => Err(diag_handler.fatal(&e)), - }?; - let bc = SerializedModule::FromRlib(bc); - upstream_modules.push((bc, CString::new(id).unwrap())); + .filter(|&(name, _)| looks_like_rust_object_file(name)); + for (name, child) in obj_files { + info!("adding bitcode from {}", name); + match get_bitcode_slice_from_object_data(child.data()) { + Ok(data) => { + let module = SerializedModule::FromRlib(data.to_vec()); + upstream_modules.push((module, CString::new(name).unwrap())); + } + Err(msg) => return Err(diag_handler.fatal(&msg)), + } } } } @@ -134,6 +130,26 @@ fn prepare_lto( Ok((symbol_white_list, upstream_modules)) } +fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], String> { + let mut len = 0; + let data = + unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) }; + if !data.is_null() { + assert!(len != 0); + let bc = unsafe { slice::from_raw_parts(data, len) }; + + // `bc` must be a sub-slice of `obj`. + assert!(obj.as_ptr() <= bc.as_ptr()); + assert!(bc[bc.len()..bc.len()].as_ptr() <= obj[obj.len()..obj.len()].as_ptr()); + + Ok(bc) + } else { + assert!(len == 0); + let msg = llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string()); + Err(format!("failed to get bitcode from object file for LTO ({})", msg)) + } +} + /// Performs fat LTO by merging all modules into a single one and returning it /// for further optimization. pub(crate) fn run_fat( diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index b57ad102d6348..5f4c122f02c92 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -1,5 +1,4 @@ use crate::attributes; -use crate::back::bytecode; use crate::back::lto::ThinBuffer; use crate::back::profiling::{ selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler, @@ -16,7 +15,7 @@ use crate::ModuleLlvm; use log::debug; use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, RLIB_BYTECODE_EXTENSION}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{FatalError, Handler}; use rustc_fs_util::{link_or_copy, path_to_c_string}; @@ -669,19 +668,6 @@ pub(crate) unsafe fn codegen( ); embed_bitcode(cgcx, llcx, llmod, Some(data)); } - - if config.emit_bc_compressed { - let _timer = cgcx.prof.generic_activity_with_arg( - "LLVM_module_codegen_emit_compressed_bitcode", - &module.name[..], - ); - let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); - let data = bytecode::encode(&module.name, data); - if let Err(e) = fs::write(&dst, data) { - let msg = format!("failed to write bytecode to {}: {}", dst.display(), e); - diag_handler.err(&msg); - } - } } else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) { embed_bitcode(cgcx, llcx, llmod, None); } @@ -792,7 +778,6 @@ pub(crate) unsafe fn codegen( Ok(module.into_compiled_module( config.emit_obj != EmitObj::None, config.emit_bc, - config.emit_bc_compressed, &cgcx.output_filenames, )) } @@ -847,6 +832,55 @@ unsafe fn embed_bitcode( let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" }; llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + + // We're adding custom sections to the output object file, but we definitely + // do not want these custom sections to make their way into the final linked + // executable. The purpose of these custom sections is for tooling + // surrounding object files to work with the LLVM IR, if necessary. For + // example rustc's own LTO will look for LLVM IR inside of the object file + // in these sections by default. + // + // To handle this is a bit different depending on the object file format + // used by the backend, broken down into a few different categories: + // + // * Mach-O - this is for macOS. Inspecting the source code for the native + // linker here shows that the `.llvmbc` and `.llvmcmd` sections are + // automatically skipped by the linker. In that case there's nothing extra + // that we need to do here. + // + // * Wasm - the native LLD linker is hard-coded to skip `.llvmbc` and + // `.llvmcmd` sections, so there's nothing extra we need to do. + // + // * COFF - if we don't do anything the linker will by default copy all + // these sections to the output artifact, not what we want! To subvert + // this we want to flag the sections we inserted here as + // `IMAGE_SCN_LNK_REMOVE`. Unfortunately though LLVM has no native way to + // do this. Thankfully though we can do this with some inline assembly, + // which is easy enough to add via module-level global inline asm. + // + // * ELF - this is very similar to COFF above. One difference is that these + // sections are removed from the output linked artifact when + // `--gc-sections` is passed, which we pass by default. If that flag isn't + // passed though then these sections will show up in the final output. + // Additionally the flag that we need to set here is `SHF_EXCLUDE`. + if is_apple + || cgcx.opts.target_triple.triple().starts_with("wasm") + || cgcx.opts.target_triple.triple().starts_with("asmjs") + { + // nothing to do here + } else if cgcx.opts.target_triple.triple().contains("windows") { + let asm = " + .section .llvmbc,\"n\" + .section .llvmcmd,\"n\" + "; + llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + } else { + let asm = " + .section .llvmbc,\"e\" + .section .llvmcmd,\"e\" + "; + llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + } } pub unsafe fn with_llvm_pmb( diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 641586797407b..5effde444af6f 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -40,7 +40,6 @@ use std::sync::Arc; mod back { pub mod archive; - pub mod bytecode; pub mod lto; mod profiling; pub mod write; diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index aeb34e5c9c954..ceeb528430fff 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -2138,6 +2138,11 @@ extern "C" { len: usize, Identifier: *const c_char, ) -> Option<&Module>; + pub fn LLVMRustGetBitcodeSliceFromObjectData( + Data: *const u8, + len: usize, + out_len: &mut usize, + ) -> *const u8; pub fn LLVMRustThinLTOGetDICompileUnit( M: &Module, CU1: &mut *mut c_void, diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 8725bfaa02575..657dae504b918 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -18,10 +18,7 @@ use super::archive::ArchiveBuilder; use super::command::Command; use super::linker::Linker; use super::rpath::{self, RPathConfig}; -use crate::{ - looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME, - RLIB_BYTECODE_EXTENSION, -}; +use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME}; use cc::windows_registry; use tempfile::{Builder as TempFileBuilder, TempDir}; @@ -130,10 +127,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( remove(sess, obj); } } - for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) - { - remove(sess, obj); - } if let Some(ref metadata_module) = codegen_results.metadata_module { if let Some(ref obj) = metadata_module.object { remove(sess, obj); @@ -143,9 +136,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( if let Some(ref obj) = allocator_module.object { remove(sess, obj); } - if let Some(ref bc) = allocator_module.bytecode_compressed { - remove(sess, bc); - } } } }); @@ -378,14 +368,6 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // contain the metadata in a separate file. ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir)); - // For LTO purposes, the bytecode of this library is also inserted - // into the archive. - for bytecode in - codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) - { - ab.add_file(bytecode); - } - // After adding all files to the archive, we need to update the // symbol table of the archive. This currently dies on macOS (see // #11162), and isn't necessary there anyway @@ -1829,7 +1811,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let mut any_objects = false; for f in archive.src_files() { - if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME { + if f == METADATA_FILENAME { archive.remove_file(&f); continue; } diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index db60760e4596f..598f56308c00b 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -5,7 +5,6 @@ use super::symbol_export::symbol_name_for_instance_in_crate; use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, - RLIB_BYTECODE_EXTENSION, }; use crate::traits::*; @@ -100,7 +99,6 @@ pub struct ModuleConfig { pub emit_pre_lto_bc: bool, pub emit_no_opt_bc: bool, pub emit_bc: bool, - pub emit_bc_compressed: bool, pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, @@ -145,9 +143,10 @@ impl ModuleConfig { || sess.opts.cg.linker_plugin_lto.enabled() { EmitObj::Bitcode - } else if sess.opts.debugging_opts.embed_bitcode { + } else if sess.opts.debugging_opts.embed_bitcode || need_crate_bitcode_for_rlib(sess) { + let force_full = need_crate_bitcode_for_rlib(sess); match sess.opts.optimize { - config::OptLevel::No | config::OptLevel::Less => { + config::OptLevel::No | config::OptLevel::Less if !force_full => { EmitObj::ObjectCode(BitcodeSection::Marker) } _ => EmitObj::ObjectCode(BitcodeSection::Full), @@ -196,16 +195,6 @@ impl ModuleConfig { save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode), save_temps ), - emit_bc_compressed: match kind { - ModuleKind::Regular | ModuleKind::Allocator => { - // Emit compressed bitcode files for the crate if we're - // emitting an rlib. Whenever an rlib is created, the - // bitcode is inserted into the archive in order to allow - // LTO against it. - need_crate_bitcode_for_rlib(sess) - } - ModuleKind::Metadata => false, - }, emit_ir: if_regular!( sess.opts.output_types.contains_key(&OutputType::LlvmAssembly), false @@ -261,7 +250,6 @@ impl ModuleConfig { pub fn bitcode_needed(&self) -> bool { self.emit_bc - || self.emit_bc_compressed || self.emit_obj == EmitObj::Bitcode || self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) } @@ -482,9 +470,6 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( 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 let Some((id, product)) = copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) @@ -821,7 +806,6 @@ fn execute_copy_from_cache_work_item( let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); let mut object = None; let mut bytecode = None; - let mut bytecode_compressed = None; for (kind, saved_file) in &module.source.saved_files { let obj_out = match kind { WorkProductFileKind::Object => { @@ -834,14 +818,6 @@ fn execute_copy_from_cache_work_item( bytecode = Some(path.clone()); path } - WorkProductFileKind::BytecodeCompressed => { - let path = cgcx - .output_filenames - .temp_path(OutputType::Bitcode, Some(&module.name)) - .with_extension(RLIB_BYTECODE_EXTENSION); - bytecode_compressed = Some(path.clone()); - path - } }; let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file); debug!( @@ -863,14 +839,12 @@ fn execute_copy_from_cache_work_item( assert_eq!(object.is_some(), module_config.emit_obj != EmitObj::None); assert_eq!(bytecode.is_some(), module_config.emit_bc); - assert_eq!(bytecode_compressed.is_some(), module_config.emit_bc_compressed); Ok(WorkItemResult::Compiled(CompiledModule { name: module.name, kind: ModuleKind::Regular, object, bytecode, - bytecode_compressed, })) } diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 5ba06bd8665b8..7dc09b595c36e 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -55,31 +55,18 @@ pub struct ModuleCodegen { // FIXME(eddyb) maybe include the crate name in this? pub const METADATA_FILENAME: &str = "lib.rmeta"; -pub const RLIB_BYTECODE_EXTENSION: &str = "bc.z"; impl ModuleCodegen { pub fn into_compiled_module( self, emit_obj: bool, emit_bc: bool, - emit_bc_compressed: bool, outputs: &OutputFilenames, ) -> CompiledModule { let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); - let bytecode_compressed = emit_bc_compressed.then(|| { - outputs - .temp_path(OutputType::Bitcode, Some(&self.name)) - .with_extension(RLIB_BYTECODE_EXTENSION) - }); - - CompiledModule { - name: self.name.clone(), - kind: self.kind, - object, - bytecode, - bytecode_compressed, - } + + CompiledModule { name: self.name.clone(), kind: self.kind, object, bytecode } } } @@ -89,7 +76,6 @@ pub struct CompiledModule { pub kind: ModuleKind, pub object: Option, pub bytecode: Option, - pub bytecode_compressed: Option, } pub struct CachedModuleCodegen { diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index 4dd81b1df5759..3601b99705916 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -21,7 +21,6 @@ pub fn copy_cgu_workproducts_to_incr_comp_cache_dir( let extension = match kind { WorkProductFileKind::Object => "o", WorkProductFileKind::Bytecode => "bc", - WorkProductFileKind::BytecodeCompressed => "bc.z", }; let file_name = format!("{}.{}", cgu_name, extension); let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index fa2b51058a378..ba3ce16ae36fe 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -868,7 +868,6 @@ pub struct WorkProduct { pub enum WorkProductFileKind { Object, Bytecode, - BytecodeCompressed, } #[derive(Clone)] diff --git a/src/llvm-project b/src/llvm-project index 9f9da27fbdb0b..3ba91917e52bd 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 9f9da27fbdb0ba7d887f8d2521e082f12b009417 +Subproject commit 3ba91917e52bd66ac37161ad4a1bc87d32aa2e18 diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index b221c17b422f5..afdad5650b711 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -13,6 +13,8 @@ #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Verifier.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Passes/PassBuilder.h" #if LLVM_VERSION_GE(9, 0) #include "llvm/Passes/StandardInstrumentations.h" @@ -1478,6 +1480,32 @@ LLVMRustParseBitcodeForLTO(LLVMContextRef Context, return wrap(std::move(*SrcOrError).release()); } +// Find the bitcode section in the object file data and return it as a slice. +// Fail if the bitcode section is present but empty. +// +// On success, the return value is the pointer to the start of the slice and +// `out_len` is filled with the (non-zero) length. On failure, the return value +// is `nullptr` and `out_len` is set to zero. +extern "C" const char* +LLVMRustGetBitcodeSliceFromObjectData(const char *data, + size_t len, + size_t *out_len) { + *out_len = 0; + + StringRef Data(data, len); + MemoryBufferRef Buffer(Data, ""); // The id is unused. + + Expected BitcodeOrError = + object::IRObjectFile::findBitcodeInMemBuffer(Buffer); + if (!BitcodeOrError) { + LLVMRustSetLastError(toString(BitcodeOrError.takeError()).c_str()); + return nullptr; + } + + *out_len = BitcodeOrError->getBufferSize(); + return BitcodeOrError->getBufferStart(); +} + // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void diff --git a/src/test/ui/auxiliary/lto-rustc-loads-linker-plugin.rs b/src/test/ui/auxiliary/lto-rustc-loads-linker-plugin.rs new file mode 100644 index 0000000000000..d24375b2d0a63 --- /dev/null +++ b/src/test/ui/auxiliary/lto-rustc-loads-linker-plugin.rs @@ -0,0 +1,6 @@ +// compile-flags: -Clinker-plugin-lto +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub fn foo() {} diff --git a/src/test/ui/lto-duplicate-symbols.stderr b/src/test/ui/lto-duplicate-symbols.stderr index 02204830120a5..713b79bae32e6 100644 --- a/src/test/ui/lto-duplicate-symbols.stderr +++ b/src/test/ui/lto-duplicate-symbols.stderr @@ -1,6 +1,6 @@ warning: Linking globals named 'foo': symbol multiply defined! -error: failed to load bc of "lto_duplicate_symbols2.3a1fbbbh-cgu.0": +error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.3a1fbbbh-cgu.0.rcgu.o": error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lto-rustc-loads-linker-plugin.rs b/src/test/ui/lto-rustc-loads-linker-plugin.rs new file mode 100644 index 0000000000000..6ef1d4540b8d7 --- /dev/null +++ b/src/test/ui/lto-rustc-loads-linker-plugin.rs @@ -0,0 +1,17 @@ +// compile-flags: -C lto +// aux-build:lto-rustc-loads-linker-plugin.rs +// run-pass +// no-prefer-dynamic + +// This test ensures that if a dependency was compiled with +// `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against +// that upstream rlib. This should work because LTO implies we're not actually +// linking against upstream rlibs since we're generating the object code +// locally. This test will fail if rustc can't find bytecode in rlibs compiled +// with `-Clinker-plugin-lto`. + +extern crate lto_rustc_loads_linker_plugin; + +fn main() { + lto_rustc_loads_linker_plugin::foo(); +} diff --git a/src/test/ui/lto-thin-rustc-loads-linker-plugin.rs b/src/test/ui/lto-thin-rustc-loads-linker-plugin.rs new file mode 100644 index 0000000000000..4d54ce32fb563 --- /dev/null +++ b/src/test/ui/lto-thin-rustc-loads-linker-plugin.rs @@ -0,0 +1,13 @@ +// compile-flags: -C lto=thin +// aux-build:lto-rustc-loads-linker-plugin.rs +// run-pass +// no-prefer-dynamic + +// Same as the adjacent `lto-thin-rustc-loads-linker-plugin.rs` test, only with +// ThinLTO. + +extern crate lto_rustc_loads_linker_plugin; + +fn main() { + lto_rustc_loads_linker_plugin::foo(); +}