From 3c87ab39a36b2811e7a562ede5c9e758247a3e52 Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Thu, 18 Jun 2026 18:28:53 +0000 Subject: [PATCH] rustc_llvm: Emit module summaries when using -Clto=fat Currently, module summaries are only emitted with thin lto. If we would link full/fat lto'd rust code against lto'd c++ code built with CFI (or WPD), those passes would fail during the link step because the participating rust modules are missing module summaries. Rust code does not know at compile-time if it would be participating in some special link which may require module summaries, so this PR ensures module summaries are unconditionally emitted for full/fat lto, just like with thin lto. The WriteBitcodeToFile function just invokes the normal BitcodeWriterPass under the hood, but doesn't provide a way to set the argument for emitting module summaries. So this patch just adds the pass directly and sets that argument. --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 45 +++++++++++++------ tests/run-make/fat-lto-module-summary/foo.rs | 1 + .../run-make/fat-lto-module-summary/rmake.rs | 10 +++++ 3 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 tests/run-make/fat-lto-module-summary/foo.rs create mode 100644 tests/run-make/fat-lto-module-summary/rmake.rs diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 5dcaa5f6f84b8..d6e9c72125597 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -924,7 +924,15 @@ extern "C" LLVMRustResult LLVMRustOptimize( MPM.addPass(ThinLTOBitcodeWriterPass( ThinLTODataOS, ThinLTOSummaryBufferRef ? &ThinLinkDataOS : nullptr)); } else { - MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); + // Force Full LTO summary for embedded bitcode under Fat LTO. + // + // Note the bitcode writer will only emit the full LTO block ID if the "ThinLTO" + // metadata is defined and explicitly set to zero. Otherwise, the thin LTO block + // ID will be emitted. + auto *Zero = ConstantInt::get(Type::getInt32Ty(TheModule->getContext()), 0); + TheModule->addModuleFlag(Module::Error, "ThinLTO", Zero); + MPM.addPass(BitcodeWriterPass(ThinLTODataOS, /*ShouldPreserveUseListOrder=*/false, + /*EmitSummaryIndex=*/true)); } *ThinLTOBufferRef = ThinLTOBuffer.release(); if (ThinLTOSummaryBufferRef) { @@ -1442,23 +1450,32 @@ extern "C" LLVMRustBuffer *LLVMRustModuleSerialize(LLVMModuleRef M, { auto OS = raw_string_ostream(Ret->data); { + PassBuilder PB; + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; if (is_thin) { - PassBuilder PB; - LoopAnalysisManager LAM; - FunctionAnalysisManager FAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - ModulePassManager MPM; MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr)); - MPM.run(*unwrap(M), MAM); } else { - WriteBitcodeToFile(*unwrap(M), OS); + // Force Full LTO summary for embedded bitcode under Fat LTO. + // + // Note the bitcode writer will only emit the full LTO block ID if the "ThinLTO" + // metadata is defined and explicitly set to zero. Otherwise, the thin LTO block + // ID will be emitted. + auto *Zero = ConstantInt::get(Type::getInt32Ty(unwrap(M)->getContext()), 0); + unwrap(M)->addModuleFlag(Module::Error, "ThinLTO", Zero); + MPM.addPass(BitcodeWriterPass(OS, /*ShouldPreserveUseListOrder=*/false, + /*EmitSummaryIndex=*/true)); } + MPM.run(*unwrap(M), MAM); } } return Ret.release(); diff --git a/tests/run-make/fat-lto-module-summary/foo.rs b/tests/run-make/fat-lto-module-summary/foo.rs new file mode 100644 index 0000000000000..b76b4321d62aa --- /dev/null +++ b/tests/run-make/fat-lto-module-summary/foo.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/tests/run-make/fat-lto-module-summary/rmake.rs b/tests/run-make/fat-lto-module-summary/rmake.rs new file mode 100644 index 0000000000000..f04416c68fd96 --- /dev/null +++ b/tests/run-make/fat-lto-module-summary/rmake.rs @@ -0,0 +1,10 @@ +use run_make_support::{llvm_bcanalyzer, rustc}; + +fn main() { + rustc().input("foo.rs").crate_type("lib").arg("-Clto=fat").arg("--emit=llvm-bc").run(); + + llvm_bcanalyzer() + .input("foo.bc") + .run() + .assert_stdout_contains("FULL_LTO_GLOBALVAL_SUMMARY_BLOCK"); +}