From aa91871539ca518e81af58485df895f8db30496a Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 19 Jan 2024 14:42:43 -0500 Subject: [PATCH 1/6] rustc_codegen_llvm: add support for writing summary bitcode Typical uses of ThinLTO don't have any use for this as a standalone file, but distributed ThinLTO uses this to make the linker phase more efficient. With clang you'd do something like `clang -flto=thin -fthin-link-bitcode=foo.indexing.o -c foo.c` and then get both foo.o (full of bitcode) and foo.indexing.o (just the summary or index part of the bitcode). That's then usable by a two-stage linking process that's more friendly to distributed build systems like bazel, which is why I'm working on this area. I talked some to @teresajohnson about naming in this area, as things seem to be a little confused between various blog posts and build systems. "bitcode index" and "bitcode summary" tend to be a little too ambiguous, and she tends to use "thin link bitcode" and "minimized bitcode" (which matches the descriptions in LLVM). Since the clang option is thin-link-bitcode, I went with that to try and not add a new spelling in the world. Per @dtolnay, you can work around the lack of this by using `lld --thinlto-index-only` to do the indexing on regular .o files of bitcode, but that is a bit wasteful on actions when we already have all the information in rustc and could just write out the matching minimized bitcode. I didn't test that at all in our infrastructure, because by the time I learned that I already had this patch largely written. --- .../rustc_codegen_cranelift/src/driver/aot.rs | 2 +- compiler/rustc_codegen_gcc/src/lib.rs | 4 +++ compiler/rustc_codegen_llvm/src/back/lto.rs | 8 +++++ compiler/rustc_codegen_llvm/src/back/write.rs | 32 ++++++++++++++++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 ++ compiler/rustc_codegen_ssa/src/back/write.rs | 9 ++++++ .../rustc_codegen_ssa/src/traits/write.rs | 1 + .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 14 +++++++- compiler/rustc_session/src/config.rs | 24 +++++++++++--- 9 files changed, 85 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index fce4690f97dc9..394c810176ab2 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -200,7 +200,7 @@ fn produce_final_output_artifacts( // to get rid of it. for output_type in crate_output.outputs.keys() { match *output_type { - OutputType::Bitcode => { + OutputType::Bitcode | OutputType::ThinLinkBitcode => { // Cranelift doesn't have bitcode // user_wants_bitcode = true; // // Copy to .bc, but always keep the .0.bc. There is a later diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 3f2fadce9e4d5..d786d5116ce73 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -335,6 +335,10 @@ impl ThinBufferMethods for ThinBuffer { fn data(&self) -> &[u8] { unimplemented!(); } + + fn thin_link_data(&self) -> &[u8] { + unimplemented!(); + } } pub struct GccContext { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index e61af863dc079..740939eb6bbdb 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -687,6 +687,14 @@ impl ThinBufferMethods for ThinBuffer { slice::from_raw_parts(ptr, len) } } + + fn thin_link_data(&self) -> &[u8] { + unsafe { + let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _; + let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0); + slice::from_raw_parts(ptr, len) + } + } } impl Drop for ThinBuffer { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 49f9d7ddab65f..de12ae4ecc8f1 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -708,6 +708,8 @@ pub(crate) unsafe fn codegen( // asm from LLVM and use `gcc` to create the object file. let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + let bc_index_out = + cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); if config.bitcode_needed() { @@ -716,6 +718,7 @@ pub(crate) unsafe fn codegen( .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name); let thin = ThinBuffer::new(llmod, config.emit_thin_lto); let data = thin.data(); + let index_data = thin.thin_link_data(); if let Some(bitcode_filename) = bc_out.file_name() { cgcx.prof.artifact_size( @@ -725,12 +728,31 @@ pub(crate) unsafe fn codegen( ); } + if let Some(thin_link_bitcode_filename) = bc_index_out.file_name() { + cgcx.prof.artifact_size( + "llvm_bitcode_summary", + thin_link_bitcode_filename.to_string_lossy(), + index_data.len() as u64, + ); + + let _timer = cgcx.prof.generic_activity_with_arg( + "LLVM_module_codegen_emit_bitcode_index", + &*module.name, + ); + if let Err(err) = fs::write(&bc_index_out, index_data) { + dcx.emit_err(WriteBytecode { path: &bc_index_out, err }); + } + } + if config.emit_bc || config.emit_obj == EmitObj::Bitcode { - let _timer = cgcx - .prof - .generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name); - if let Err(err) = fs::write(&bc_out, data) { - dcx.emit_err(WriteBytecode { path: &bc_out, err }); + { + let _timer = cgcx.prof.generic_activity_with_arg( + "LLVM_module_codegen_emit_bitcode", + &*module.name, + ); + if let Err(err) = fs::write(&bc_out, data) { + dcx.emit_err(WriteBytecode { path: &bc_out, err }); + } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7a34e21628dc6..648e7f128900b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2354,6 +2354,8 @@ extern "C" { pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char; pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t; + pub fn LLVMRustThinLTOBufferThinLinkDataPtr(M: &ThinLTOBuffer) -> *const c_char; + pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t; pub fn LLVMRustCreateThinLTOData( Modules: *const ThinLTOModule, NumModules: c_uint, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 53ba0da7d0490..cee177d5eec2d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -107,6 +107,7 @@ pub struct ModuleConfig { pub emit_asm: bool, pub emit_obj: EmitObj, pub emit_thin_lto: bool, + pub emit_thin_lto_index: bool, pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line @@ -231,6 +232,10 @@ impl ModuleConfig { ), emit_obj, emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto, + emit_thin_lto_index: if_regular!( + sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode), + false + ), bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(), verify_llvm_ir: sess.verify_llvm_ir(), @@ -282,6 +287,7 @@ impl ModuleConfig { pub fn bitcode_needed(&self) -> bool { self.emit_bc + || self.emit_thin_lto_index || self.emit_obj == EmitObj::Bitcode || self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) } @@ -629,6 +635,9 @@ fn produce_final_output_artifacts( // them for making an rlib. copy_if_one_unit(OutputType::Bitcode, true); } + OutputType::ThinLinkBitcode => { + copy_if_one_unit(OutputType::ThinLinkBitcode, false); + } OutputType::LlvmAssembly => { copy_if_one_unit(OutputType::LlvmAssembly, false); } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 048540894ac9b..b4b23812d4dcb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -62,6 +62,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { pub trait ThinBufferMethods: Send + Sync { fn data(&self) -> &[u8]; + fn thin_link_data(&self) -> &[u8]; } pub trait ModuleBufferMethods: Send + Sync { diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 067374c026107..c210d2531e76a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1488,6 +1488,7 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, // a ThinLTO summary attached. struct LLVMRustThinLTOBuffer { std::string data; + std::string thin_link_data; }; extern "C" LLVMRustThinLTOBuffer* @@ -1495,6 +1496,7 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { auto Ret = std::make_unique(); { auto OS = raw_string_ostream(Ret->data); + auto ThinLinkOS = raw_string_ostream(Ret->thin_link_data); { if (is_thin) { PassBuilder PB; @@ -1508,7 +1510,7 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); ModulePassManager MPM; - MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr)); + MPM.addPass(ThinLTOBitcodeWriterPass(OS, &ThinLinkOS)); MPM.run(*unwrap(M), MAM); } else { WriteBitcodeToFile(*unwrap(M), OS); @@ -1533,6 +1535,16 @@ LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) { return Buffer->data.length(); } +extern "C" const void* +LLVMRustThinLTOBufferThinLinkDataPtr(const LLVMRustThinLTOBuffer *Buffer) { + return Buffer->thin_link_data.data(); +} + +extern "C" size_t +LLVMRustThinLTOBufferThinLinkDataLen(const LLVMRustThinLTOBuffer *Buffer) { + return Buffer->thin_link_data.length(); +} + // This is what we used to parse upstream bitcode for actual ThinLTO // processing. We'll call this once per module optimized through ThinLTO, and // it'll be called concurrently on many threads. diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7dd9fdf60f934..5ac4d194e8721 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -465,6 +465,7 @@ impl FromStr for SplitDwarfKind { #[derive(Encodable, Decodable)] pub enum OutputType { Bitcode, + ThinLinkBitcode, Assembly, LlvmAssembly, Mir, @@ -492,6 +493,7 @@ impl OutputType { match *self { OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true, OutputType::Bitcode + | OutputType::ThinLinkBitcode | OutputType::Assembly | OutputType::LlvmAssembly | OutputType::Mir @@ -502,6 +504,7 @@ impl OutputType { pub fn shorthand(&self) -> &'static str { match *self { OutputType::Bitcode => "llvm-bc", + OutputType::ThinLinkBitcode => "thin-link-bitcode", OutputType::Assembly => "asm", OutputType::LlvmAssembly => "llvm-ir", OutputType::Mir => "mir", @@ -518,6 +521,7 @@ impl OutputType { "llvm-ir" => OutputType::LlvmAssembly, "mir" => OutputType::Mir, "llvm-bc" => OutputType::Bitcode, + "thin-link-bitcode" => OutputType::ThinLinkBitcode, "obj" => OutputType::Object, "metadata" => OutputType::Metadata, "link" => OutputType::Exe, @@ -528,8 +532,9 @@ impl OutputType { fn shorthands_display() -> String { format!( - "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`", + "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`", OutputType::Bitcode.shorthand(), + OutputType::ThinLinkBitcode.shorthand(), OutputType::Assembly.shorthand(), OutputType::LlvmAssembly.shorthand(), OutputType::Mir.shorthand(), @@ -543,6 +548,7 @@ impl OutputType { pub fn extension(&self) -> &'static str { match *self { OutputType::Bitcode => "bc", + OutputType::ThinLinkBitcode => "indexing.o", OutputType::Assembly => "s", OutputType::LlvmAssembly => "ll", OutputType::Mir => "mir", @@ -559,9 +565,11 @@ impl OutputType { | OutputType::LlvmAssembly | OutputType::Mir | OutputType::DepInfo => true, - OutputType::Bitcode | OutputType::Object | OutputType::Metadata | OutputType::Exe => { - false - } + OutputType::Bitcode + | OutputType::ThinLinkBitcode + | OutputType::Object + | OutputType::Metadata + | OutputType::Exe => false, } } } @@ -644,6 +652,7 @@ impl OutputTypes { pub fn should_codegen(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode + | OutputType::ThinLinkBitcode | OutputType::Assembly | OutputType::LlvmAssembly | OutputType::Mir @@ -657,6 +666,7 @@ impl OutputTypes { pub fn should_link(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode + | OutputType::ThinLinkBitcode | OutputType::Assembly | OutputType::LlvmAssembly | OutputType::Mir @@ -1769,6 +1779,12 @@ fn parse_output_types( display = OutputType::shorthands_display(), )) }); + if output_type == OutputType::ThinLinkBitcode && !unstable_opts.unstable_options { + early_dcx.early_fatal(format!( + "{} requested but -Zunstable-options not specified", + OutputType::ThinLinkBitcode.shorthand() + )); + } output_types.insert(output_type, path); } } From 03d5556ced2d8ce84b9f5da702ac755aa98f7603 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Wed, 22 May 2024 12:41:17 -0400 Subject: [PATCH 2/6] cleanup: remove leftover extra block This was needed in an older version of this patch, but never got edited out when it became obsolete. --- compiler/rustc_codegen_llvm/src/back/write.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index de12ae4ecc8f1..4a24bba2bb7a1 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -745,7 +745,6 @@ pub(crate) unsafe fn codegen( } if config.emit_bc || config.emit_obj == EmitObj::Bitcode { - { let _timer = cgcx.prof.generic_activity_with_arg( "LLVM_module_codegen_emit_bitcode", &*module.name, @@ -753,7 +752,6 @@ pub(crate) unsafe fn codegen( if let Err(err) = fs::write(&bc_out, data) { dcx.emit_err(WriteBytecode { path: &bc_out, err }); } - } } if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) { From de8200c5a441079cfaadd383a8b6897155bfa2c6 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 23 May 2024 14:58:30 -0400 Subject: [PATCH 3/6] thinlto: only build summary file if needed If we don't do this, some versions of LLVM (at least 17, experimentally) will double-emit some error messages, which is how I noticed this. Given that it seems to be costing some extra work, let's only request the summary bitcode production if we'll actually bother writing it down, otherwise skip it. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/back/write.rs | 6 +++--- compiler/rustc_codegen_llvm/src/lib.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/write.rs | 2 +- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 7 +++++-- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 740939eb6bbdb..0dc91524f8417 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -229,9 +229,9 @@ pub(crate) fn run_thin( thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) } -pub(crate) fn prepare_thin(module: ModuleCodegen) -> (String, ThinBuffer) { +pub(crate) fn prepare_thin(module: ModuleCodegen, emit_summary: bool) -> (String, ThinBuffer) { let name = module.name; - let buffer = ThinBuffer::new(module.module_llvm.llmod(), true); + let buffer = ThinBuffer::new(module.module_llvm.llmod(), true, emit_summary); (name, buffer) } @@ -671,9 +671,9 @@ unsafe impl Send for ThinBuffer {} unsafe impl Sync for ThinBuffer {} impl ThinBuffer { - pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer { + pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer { unsafe { - let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin); + let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary); ThinBuffer(buffer) } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 4a24bba2bb7a1..a0fb110d02947 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -716,9 +716,8 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name); - let thin = ThinBuffer::new(llmod, config.emit_thin_lto); + let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_index); let data = thin.data(); - let index_data = thin.thin_link_data(); if let Some(bitcode_filename) = bc_out.file_name() { cgcx.prof.artifact_size( @@ -728,7 +727,8 @@ pub(crate) unsafe fn codegen( ); } - if let Some(thin_link_bitcode_filename) = bc_index_out.file_name() { + if config.emit_thin_lto_index && let Some(thin_link_bitcode_filename) = bc_index_out.file_name() { + let index_data = thin.thin_link_data(); cgcx.prof.artifact_size( "llvm_bitcode_summary", thin_link_bitcode_filename.to_string_lossy(), diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1cecf682e5db6..4a9502fa897ca 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -240,8 +240,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result { back::write::codegen(cgcx, dcx, module, config) } - fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer) { - back::lto::prepare_thin(module) + fn prepare_thin(module: ModuleCodegen, emit_summary: bool) -> (String, Self::ThinBuffer) { + back::lto::prepare_thin(module, emit_summary) } fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer) { (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 648e7f128900b..1e84c2be3c671 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2350,7 +2350,7 @@ extern "C" { #[allow(improper_ctypes)] pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString); - pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer; + pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool, emit_summary: bool) -> &'static mut ThinLTOBuffer; pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char; pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index cee177d5eec2d..0432659d371ee 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -891,7 +891,7 @@ fn execute_optimize_work_item( match lto_type { ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config), ComputedLtoType::Thin => { - let (name, thin_buffer) = B::prepare_thin(module); + let (name, thin_buffer) = B::prepare_thin(module, false); if let Some(path) = bitcode { fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index b4b23812d4dcb..21efca53a4780 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -56,7 +56,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { module: ModuleCodegen, config: &ModuleConfig, ) -> Result; - fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer); + fn prepare_thin(module: ModuleCodegen, want_summary: bool) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index c210d2531e76a..3fcf3aca8afee 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1492,7 +1492,7 @@ struct LLVMRustThinLTOBuffer { }; extern "C" LLVMRustThinLTOBuffer* -LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { +LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) { auto Ret = std::make_unique(); { auto OS = raw_string_ostream(Ret->data); @@ -1510,7 +1510,10 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) { PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); ModulePassManager MPM; - MPM.addPass(ThinLTOBitcodeWriterPass(OS, &ThinLinkOS)); + // We only pass ThinLinkOS to be filled in if we want the summary, + // because otherwise LLVM does extra work and may double-emit some + // errors or warnings. + MPM.addPass(ThinLTOBitcodeWriterPass(OS, emit_summary ? &ThinLinkOS : nullptr)); MPM.run(*unwrap(M), MAM); } else { WriteBitcodeToFile(*unwrap(M), OS); From 3ea494190f0df0e6d1454b160419c9a72cfca5ba Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 23 May 2024 15:07:43 -0400 Subject: [PATCH 4/6] cleanup: standardize on summary over index in names I did this in the user-facing logic, but I noticed while fixing a minor defect that I had missed it in a few places in the internal details. --- compiler/rustc_codegen_llvm/src/back/write.rs | 16 ++++++++-------- compiler/rustc_codegen_ssa/src/back/write.rs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a0fb110d02947..daefac8480bdc 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -708,7 +708,7 @@ pub(crate) unsafe fn codegen( // asm from LLVM and use `gcc` to create the object file. let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); - let bc_index_out = + let bc_summary_out = cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); @@ -716,7 +716,7 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name); - let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_index); + let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_summary); let data = thin.data(); if let Some(bitcode_filename) = bc_out.file_name() { @@ -727,20 +727,20 @@ pub(crate) unsafe fn codegen( ); } - if config.emit_thin_lto_index && let Some(thin_link_bitcode_filename) = bc_index_out.file_name() { - let index_data = thin.thin_link_data(); + if config.emit_thin_lto_summary && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() { + let summary_data = thin.thin_link_data(); cgcx.prof.artifact_size( "llvm_bitcode_summary", thin_link_bitcode_filename.to_string_lossy(), - index_data.len() as u64, + summary_data.len() as u64, ); let _timer = cgcx.prof.generic_activity_with_arg( - "LLVM_module_codegen_emit_bitcode_index", + "LLVM_module_codegen_emit_bitcode_summary", &*module.name, ); - if let Err(err) = fs::write(&bc_index_out, index_data) { - dcx.emit_err(WriteBytecode { path: &bc_index_out, err }); + if let Err(err) = fs::write(&bc_summary_out, summary_data) { + dcx.emit_err(WriteBytecode { path: &bc_summary_out, err }); } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0432659d371ee..f112cea6c82b5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -107,7 +107,7 @@ pub struct ModuleConfig { pub emit_asm: bool, pub emit_obj: EmitObj, pub emit_thin_lto: bool, - pub emit_thin_lto_index: bool, + pub emit_thin_lto_summary: bool, pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line @@ -232,7 +232,7 @@ impl ModuleConfig { ), emit_obj, emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto, - emit_thin_lto_index: if_regular!( + emit_thin_lto_summary: if_regular!( sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode), false ), @@ -287,7 +287,7 @@ impl ModuleConfig { pub fn bitcode_needed(&self) -> bool { self.emit_bc - || self.emit_thin_lto_index + || self.emit_thin_lto_summary || self.emit_obj == EmitObj::Bitcode || self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) } From a0581b5b7fe6b9add5c1f0fe90a9f2cc8249b01e Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 23 May 2024 15:10:04 -0400 Subject: [PATCH 5/6] cleanup: run rustfmt --- compiler/rustc_codegen_llvm/src/back/lto.rs | 5 ++++- compiler/rustc_codegen_llvm/src/back/write.rs | 17 +++++++++-------- compiler/rustc_codegen_llvm/src/lib.rs | 5 ++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 +++++- compiler/rustc_codegen_ssa/src/traits/write.rs | 5 ++++- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 0dc91524f8417..c4bcf16bef30f 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -229,7 +229,10 @@ pub(crate) fn run_thin( thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) } -pub(crate) fn prepare_thin(module: ModuleCodegen, emit_summary: bool) -> (String, ThinBuffer) { +pub(crate) fn prepare_thin( + module: ModuleCodegen, + emit_summary: bool, +) -> (String, ThinBuffer) { let name = module.name; let buffer = ThinBuffer::new(module.module_llvm.llmod(), true, emit_summary); (name, buffer) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index daefac8480bdc..08cfda9e8ce00 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -727,7 +727,9 @@ pub(crate) unsafe fn codegen( ); } - if config.emit_thin_lto_summary && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() { + if config.emit_thin_lto_summary + && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() + { let summary_data = thin.thin_link_data(); cgcx.prof.artifact_size( "llvm_bitcode_summary", @@ -745,13 +747,12 @@ pub(crate) unsafe fn codegen( } if config.emit_bc || config.emit_obj == EmitObj::Bitcode { - let _timer = cgcx.prof.generic_activity_with_arg( - "LLVM_module_codegen_emit_bitcode", - &*module.name, - ); - if let Err(err) = fs::write(&bc_out, data) { - dcx.emit_err(WriteBytecode { path: &bc_out, err }); - } + let _timer = cgcx + .prof + .generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name); + if let Err(err) = fs::write(&bc_out, data) { + dcx.emit_err(WriteBytecode { path: &bc_out, err }); + } } if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4a9502fa897ca..1e4f4c01b1c76 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -240,7 +240,10 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result { back::write::codegen(cgcx, dcx, module, config) } - fn prepare_thin(module: ModuleCodegen, emit_summary: bool) -> (String, Self::ThinBuffer) { + fn prepare_thin( + module: ModuleCodegen, + emit_summary: bool, + ) -> (String, Self::ThinBuffer) { back::lto::prepare_thin(module, emit_summary) } fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer) { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1e84c2be3c671..132e1f9e8fd93 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2350,7 +2350,11 @@ extern "C" { #[allow(improper_ctypes)] pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString); - pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool, emit_summary: bool) -> &'static mut ThinLTOBuffer; + pub fn LLVMRustThinLTOBufferCreate( + M: &Module, + is_thin: bool, + emit_summary: bool, + ) -> &'static mut ThinLTOBuffer; pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char; pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t; diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 21efca53a4780..f83e34ab01bc2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -56,7 +56,10 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { module: ModuleCodegen, config: &ModuleConfig, ) -> Result; - fn prepare_thin(module: ModuleCodegen, want_summary: bool) -> (String, Self::ThinBuffer); + fn prepare_thin( + module: ModuleCodegen, + want_summary: bool, + ) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); } From cfe3f77f9dd83bceb35e9685c4690b7b1a5be1b0 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 23 May 2024 15:23:21 -0400 Subject: [PATCH 6/6] rustc_codegen_gcc: fix changed method signature --- compiler/rustc_codegen_gcc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index d786d5116ce73..b1785e150adc5 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -418,7 +418,7 @@ impl WriteBackendMethods for GccCodegenBackend { back::write::codegen(cgcx, dcx, module, config) } - fn prepare_thin(_module: ModuleCodegen) -> (String, Self::ThinBuffer) { + fn prepare_thin(_module: ModuleCodegen, _emit_summary: bool) -> (String, Self::ThinBuffer) { unimplemented!(); }