From 63ec1bb2553bfd00601a37c877188f4bc19952cc Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Thu, 7 Aug 2025 16:05:09 -0700 Subject: [PATCH 1/7] Builtins world prototype - Preserve all libc symbols in LTO - Disable libfuncs that aren't present in the module This is overly-disably: - Libfuncs not in bitcode are disabled too - Libfuncs defined in other ThinLTO modules are disabled unless they are imported into the module. Not sure when importing happens; maybe that means this disables all libfuncs for ThinLTO entirely? --- llvm/lib/LTO/LTOBackend.cpp | 12 ++++++++++++ llvm/lib/Object/CMakeLists.txt | 1 + llvm/lib/Object/IRSymtab.cpp | 8 +++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 93118becedbac..db7c449cca75c 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -281,6 +281,18 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, new TargetLibraryInfoImpl(TM->getTargetTriple())); if (Conf.Freestanding) TLII->disableAllFunctions(); + + TargetLibraryInfo TLI(*TLII); + for (unsigned I = 0, E = static_cast(LibFunc::NumLibFuncs); + I != E; ++I) { + LibFunc F = static_cast(I); + GlobalValue *Val = Mod.getNamedValue(TLI.getName(F)); + // TODO: Non-lto functions should not be disabled, nor should functions that + // are somewhere in a ThinLTO link (just not imported in this module). + if (!Val || Val->isDeclaration()) + TLII->setUnavailable(F); + } + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); // Parse a custom AA pipeline if asked to. diff --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt index 0f6d2f7c59a5c..c48d251249488 100644 --- a/llvm/lib/Object/CMakeLists.txt +++ b/llvm/lib/Object/CMakeLists.txt @@ -51,6 +51,7 @@ add_llvm_component_library(LLVMObject BinaryFormat MCParser Support + Target TargetParser TextAPI ) diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp index a45b34eb2e706..92ed072a80267 100644 --- a/llvm/lib/Object/IRSymtab.cpp +++ b/llvm/lib/Object/IRSymtab.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Comdat.h" @@ -75,12 +76,14 @@ struct Builder { Builder(SmallVector &Symtab, StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc, const Triple &TT) : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT), - Libcalls(TT) {} + TLII(TT), TLI(TLII), Libcalls(TT) {} DenseMap ComdatMap; Mangler Mang; const Triple &TT; + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI; // FIXME: This shouldn't be here. RTLIB::RuntimeLibcallsInfo Libcalls; @@ -95,6 +98,9 @@ struct Builder { std::vector DependentLibraries; bool isPreservedName(StringRef Name) { + LibFunc F; + if (TLI.getLibFunc(Name, F) && TLI.has(F)) + return true; return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported; } From 148a1a71efb5722d8b5941a435bac90741a3148b Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Mon, 20 Oct 2025 15:41:29 -0700 Subject: [PATCH 2/7] Add an LTO interface for querying all libfunc names --- llvm/include/llvm/LTO/LTO.h | 8 ++++++++ llvm/lib/LTO/LTO.cpp | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 3a4dc5a3dfcf8..2e98b2a304174 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -420,6 +420,14 @@ class LTO { LLVM_ABI static SmallVector getRuntimeLibcallSymbols(const Triple &TT); + /// Static method that returns a list of library function symbols that can be + /// generated by LTO but might not be visible from bitcode symbol table. + /// Unlike the runtime libcalls, the linker can report to the code generator + /// which of these are actually available in the link, and the code generator + /// can then only reference that set of symbols. + LLVM_ABI static SmallVector + getLibFuncSymbols(const Triple &TT, llvm::StringSaver &Saver); + private: Config Conf; diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index fefc733fa7697..1d38120c6e642 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1406,6 +1406,21 @@ SmallVector LTO::getRuntimeLibcallSymbols(const Triple &TT) { return LibcallSymbols; } +SmallVector LTO::getLibFuncSymbols(const Triple &TT, + StringSaver &Saver) { + auto TLII = std::make_unique(TT); + TargetLibraryInfo TLI(*TLII); + SmallVector LibFuncSymbols; + LibFuncSymbols.reserve(LibFunc::NumLibFuncs); + for (unsigned I = 0, E = static_cast(LibFunc::NumLibFuncs); I != E; + ++I) { + LibFunc F = static_cast(I); + if (TLI.has(F)) + LibFuncSymbols.push_back(Saver.save(TLI.getName(F)).data()); + } + return LibFuncSymbols; +} + Error ThinBackendProc::emitFiles( const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath, const std::string &NewModulePath) const { From ebf8576efc25fe73ed8c08e1f102e1f43a2988df Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Tue, 21 Oct 2025 14:47:17 -0700 Subject: [PATCH 3/7] Collect bitcode libfuncs --- lld/ELF/Driver.cpp | 14 +++++++++++++- lld/ELF/LTO.cpp | 5 ++++- lld/ELF/LTO.h | 3 ++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 8647752be31fe..b48e9f29d7b54 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2709,7 +2709,19 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) { if (!ctx.bitcodeFiles.empty()) markBuffersAsDontNeed(ctx, skipLinkedOutput); - ltoObjectFiles = lto->compile(); + llvm::Triple tt(ctx.bitcodeFiles.front()->obj->getTargetTriple()); + llvm::BumpPtrAllocator alloc; + llvm::StringSaver saver(alloc); + SmallVector bitcodeLibFuncs; + for (const char *libFunc : lto::LTO::getLibFuncSymbols(tt, saver)) { + Symbol *sym = ctx.symtab->find(libFunc); + if (!sym) + continue; + if (isa(sym->file)) + bitcodeLibFuncs.push_back(libFunc); + } + + ltoObjectFiles = lto->compile(bitcodeLibFuncs); for (auto &file : ltoObjectFiles) { auto *obj = cast>(file.get()); obj->parse(/*ignoreComdats=*/true); diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 80c6d2482f9fa..06af36a117d7e 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -235,6 +235,8 @@ void BitcodeCompiler::add(BitcodeFile &f) { const lto::InputFile::Symbol &objSym = objSyms[i]; lto::SymbolResolution &r = resols[i]; + dbgs() << sym-> + // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. @@ -311,7 +313,8 @@ static void thinLTOCreateEmptyIndexFiles(Ctx &ctx) { // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). -SmallVector, 0> BitcodeCompiler::compile() { +SmallVector, 0> +BitcodeCompiler::compile(const SmallVector &bitcodeLibfuncs) { unsigned maxTasks = ltoObj->getMaxTasks(); buf.resize(maxTasks); files.resize(maxTasks); diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h index acf3bcff7f2f1..6f568d13a3182 100644 --- a/lld/ELF/LTO.h +++ b/lld/ELF/LTO.h @@ -42,7 +42,8 @@ class BitcodeCompiler { ~BitcodeCompiler(); void add(BitcodeFile &f); - SmallVector, 0> compile(); + SmallVector, 0> + compile(const SmallVector &bitcodeLibfuncs); private: Ctx &ctx; From b52feaaa0c66211f5693e30c90b84013413f560f Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Tue, 21 Oct 2025 14:48:52 -0700 Subject: [PATCH 4/7] Remove hax --- lld/ELF/LTO.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 06af36a117d7e..e25b57a1c4166 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -235,8 +235,6 @@ void BitcodeCompiler::add(BitcodeFile &f) { const lto::InputFile::Symbol &objSym = objSyms[i]; lto::SymbolResolution &r = resols[i]; - dbgs() << sym-> - // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. From 0434173b4dbd51596f96f65f864c05817805a565 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Tue, 21 Oct 2025 14:53:13 -0700 Subject: [PATCH 5/7] Pass through to LTO --- lld/ELF/LTO.cpp | 4 ++- lld/ELF/LTO.h | 2 +- llvm/include/llvm/LTO/LTO.h | 12 ++++++-- llvm/include/llvm/LTO/LTOBackend.h | 7 +++-- llvm/lib/LTO/LTO.cpp | 44 +++++++++++++++++++----------- llvm/lib/LTO/LTOBackend.cpp | 14 ++++++---- llvm/lib/LTO/LTOCodeGenerator.cpp | 4 +-- 7 files changed, 57 insertions(+), 30 deletions(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index e25b57a1c4166..c661780302a43 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -312,7 +312,9 @@ static void thinLTOCreateEmptyIndexFiles(Ctx &ctx) { // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). SmallVector, 0> -BitcodeCompiler::compile(const SmallVector &bitcodeLibfuncs) { +BitcodeCompiler::compile(const SmallVector &bitcodeLibFuncs) { + ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs); + unsigned maxTasks = ltoObj->getMaxTasks(); buf.resize(maxTasks); files.resize(maxTasks); diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h index 6f568d13a3182..99a61f8279c6a 100644 --- a/lld/ELF/LTO.h +++ b/lld/ELF/LTO.h @@ -43,7 +43,7 @@ class BitcodeCompiler { void add(BitcodeFile &f); SmallVector, 0> - compile(const SmallVector &bitcodeLibfuncs); + compile(const SmallVector &bitcodeLibFuncs); private: Ctx &ctx; diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 2e98b2a304174..346ff9817737f 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -264,7 +264,8 @@ class ThinBackendProc { using ThinBackendFunction = std::function( const Config &C, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache)>; + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs)>; /// This type defines the behavior following the thin-link phase during ThinLTO. /// It encapsulates a backend function and a strategy for thread pool @@ -279,10 +280,11 @@ struct ThinBackend { std::unique_ptr operator()( const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { assert(isValid() && "Invalid backend function"); return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries, - std::move(AddStream), std::move(Cache)); + std::move(AddStream), std::move(Cache), BitcodeLibFuncs); } ThreadPoolStrategy getParallelism() const { return Parallelism; } bool isValid() const { return static_cast(Func); } @@ -400,6 +402,8 @@ class LTO { LLVM_ABI Error add(std::unique_ptr Obj, ArrayRef Res); + LLVM_ABI void setBitcodeLibFuncs(const SmallVector &BitcodeLibFuncs); + /// Returns an upper bound on the number of tasks that the client may expect. /// This may only be called after all IR object files have been added. For a /// full description of tasks see LTOBackend.h. @@ -599,6 +603,8 @@ class LTO { // Diagnostic optimization remarks file LLVMRemarkFileHandle DiagnosticOutputFile; + + const SmallVector *BitcodeLibFuncs; }; /// The resolution for a symbol. The linker must provide a SymbolResolution for diff --git a/llvm/include/llvm/LTO/LTOBackend.h b/llvm/include/llvm/LTO/LTOBackend.h index 48ad5aa64f61f..26bff22819d91 100644 --- a/llvm/include/llvm/LTO/LTOBackend.h +++ b/llvm/include/llvm/LTO/LTOBackend.h @@ -39,13 +39,15 @@ LLVM_ABI bool opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary, - const std::vector &CmdArgs); + const std::vector &CmdArgs, + const SmallVector& BitcodeLibFuncs); /// Runs a regular LTO backend. The regular LTO backend can also act as the /// regular LTO phase of ThinLTO, which may need to access the combined index. LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, Module &M, - ModuleSummaryIndex &CombinedIndex); + ModuleSummaryIndex &CombinedIndex, + const SmallVector &BitcodeLibFuncs); /// Runs a ThinLTO backend. /// If \p ModuleMap is not nullptr, all the module files to be imported have @@ -62,6 +64,7 @@ thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector *ModuleMap, bool CodeGenOnly, + const SmallVector &BitcodeLibFuncs, AddStreamFn IRAddStream = nullptr, const std::vector &CmdArgs = std::vector()); diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 1d38120c6e642..95f06103689c1 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -762,6 +762,10 @@ Error LTO::add(std::unique_ptr Input, return Error::success(); } +void LTO::setBitcodeLibFuncs(const SmallVector &BitcodeLibFuncs) { + this->BitcodeLibFuncs = &BitcodeLibFuncs; +} + Expected> LTO::addModule(InputFile &Input, ArrayRef InputRes, unsigned ModI, ArrayRef Res) { @@ -1386,7 +1390,8 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) { if (Error Err = backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, - *RegularLTO.CombinedModule, ThinLTO.CombinedIndex)) + *RegularLTO.CombinedModule, ThinLTO.CombinedIndex, + *BitcodeLibFuncs)) return Err; } @@ -1498,6 +1503,7 @@ class CGThinBackend : public ThinBackendProc { class InProcessThinBackend : public CGThinBackend { protected: FileCache Cache; + const SmallVector &BitcodeLibFuncs; public: InProcessThinBackend( @@ -1505,11 +1511,12 @@ class InProcessThinBackend : public CGThinBackend { ThreadPoolStrategy ThinLTOParallelism, const DenseMap &ModuleToDefinedGVSummaries, AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite, - bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles) + bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles, + const SmallVector &BitcodeLibFuncs) : CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries, AddStream, OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles, ThinLTOParallelism), - Cache(std::move(Cache)) {} + Cache(std::move(Cache)), BitcodeLibFuncs(BitcodeLibFuncs) {} virtual Error runThinLTOBackendThread( AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM, @@ -1530,7 +1537,7 @@ class InProcessThinBackend : public CGThinBackend { return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap, - Conf.CodeGenOnly); + Conf.CodeGenOnly, BitcodeLibFuncs); }; if (ShouldEmitIndexFiles) { if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str())) @@ -1615,13 +1622,14 @@ class FirstRoundThinBackend : public InProcessThinBackend { const Config &Conf, ModuleSummaryIndex &CombinedIndex, ThreadPoolStrategy ThinLTOParallelism, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn CGAddStream, FileCache CGCache, AddStreamFn IRAddStream, + AddStreamFn CGAddStream, FileCache CGCache, + const SmallVector &BitcodeLibFuncs, AddStreamFn IRAddStream, FileCache IRCache) : InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism, ModuleToDefinedGVSummaries, std::move(CGAddStream), std::move(CGCache), /*OnWrite=*/nullptr, /*ShouldEmitIndexFiles=*/false, - /*ShouldEmitImportsFiles=*/false), + /*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs), IRAddStream(std::move(IRAddStream)), IRCache(std::move(IRCache)) {} Error runThinLTOBackendThread( @@ -1644,7 +1652,7 @@ class FirstRoundThinBackend : public InProcessThinBackend { return thinBackend(Conf, Task, CGAddStream, **MOrErr, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap, - Conf.CodeGenOnly, IRAddStream); + Conf.CodeGenOnly, BitcodeLibFuncs, IRAddStream); }; // Like InProcessThinBackend, we produce index files as needed for // FirstRoundThinBackend. However, these files are not generated for @@ -1711,6 +1719,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { ThreadPoolStrategy ThinLTOParallelism, const DenseMap &ModuleToDefinedGVSummaries, AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs, std::unique_ptr> IRFiles, stable_hash CombinedCGDataHash) : InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism, @@ -1718,7 +1727,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { std::move(Cache), /*OnWrite=*/nullptr, /*ShouldEmitIndexFiles=*/false, - /*ShouldEmitImportsFiles=*/false), + /*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs), IRFiles(std::move(IRFiles)), CombinedCGDataHash(CombinedCGDataHash) {} Error runThinLTOBackendThread( @@ -1739,7 +1748,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { return thinBackend(Conf, Task, AddStream, *LoadedModule, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap, - /*CodeGenOnly=*/true); + /*CodeGenOnly=*/true, BitcodeLibFuncs); }; if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) || all_of(CombinedIndex.getModuleHash(ModuleID), @@ -1778,11 +1787,12 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism, auto Func = [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, AddStream, Cache, OnWrite, ShouldEmitIndexFiles, - ShouldEmitImportsFiles); + ShouldEmitImportsFiles, BitcodeLibFuncs); }; return ThinBackend(Func, Parallelism); } @@ -1899,7 +1909,8 @@ ThinBackend lto::createWriteIndexesThinBackend( auto Func = [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles, @@ -2117,7 +2128,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, if (!CodeGenDataThinLTOTwoRounds) { std::unique_ptr BackendProc = ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, - AddStream, Cache); + AddStream, Cache, *BitcodeLibFuncs); return RunBackends(BackendProc.get()); } @@ -2140,7 +2151,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n"); auto FirstRoundLTO = std::make_unique( Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, - CG.AddStream, CG.Cache, IR.AddStream, IR.Cache); + CG.AddStream, CG.Cache, *BitcodeLibFuncs, IR.AddStream, IR.Cache); if (Error E = RunBackends(FirstRoundLTO.get())) return E; @@ -2156,7 +2167,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n"); auto SecondRoundLTO = std::make_unique( Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, - AddStream, Cache, IR.getResult(), CombinedHash); + AddStream, Cache, *BitcodeLibFuncs, IR.getResult(), CombinedHash); return RunBackends(SecondRoundLTO.get()); } @@ -2540,7 +2551,8 @@ ThinBackend lto::createOutOfProcessThinBackend( auto Func = [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache /*Cache*/) { + AddStreamFn AddStream, FileCache /*Cache*/, + const SmallVector &BitcodeLibFuncs) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, AddStream, OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles, diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index db7c449cca75c..38486d755f906 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -376,7 +376,8 @@ static bool isEmptyModule(const Module &Mod) { bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary, - const std::vector &CmdArgs) { + const std::vector &CmdArgs, + const SmallVector &BitcodeLibFuncs) { llvm::TimeTraceScope timeScope("opt"); if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) { // FIXME: the motivation for capturing post-merge bitcode and command line @@ -564,7 +565,8 @@ Error lto::finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile) { Error lto::backend(const Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, Module &Mod, - ModuleSummaryIndex &CombinedIndex) { + ModuleSummaryIndex &CombinedIndex, + const SmallVector &BitcodeLibFuncs) { llvm::TimeTraceScope timeScope("LTO backend"); Expected TOrErr = initAndLookupTarget(C, Mod); if (!TOrErr) @@ -576,7 +578,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream, if (!C.CodeGenOnly) { if (!opt(C, TM.get(), 0, Mod, /*IsThinLTO=*/false, /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, - /*CmdArgs*/ std::vector())) + /*CmdArgs*/ std::vector(), BitcodeLibFuncs)) return Error::success(); } @@ -616,7 +618,9 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector *ModuleMap, - bool CodeGenOnly, AddStreamFn IRAddStream, + bool CodeGenOnly, + const SmallVector &BitcodeLibFuncs, + AddStreamFn IRAddStream, const std::vector &CmdArgs) { llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier()); Expected TOrErr = initAndLookupTarget(Conf, Mod); @@ -655,7 +659,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, // Perform optimization and code generation for ThinLTO. if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true, /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex, - CmdArgs)) + CmdArgs, BitcodeLibFuncs)) return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); // Save the current module before the first codegen round. diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index 8aa404da15286..599c5c2eb5f84 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -614,7 +614,7 @@ bool LTOCodeGenerator::optimize() { TargetMach = createTargetMachine(); if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false, /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, - /*CmdArgs*/ std::vector())) { + /*CmdArgs*/ std::vector(), {})) { emitError("LTO middle-end optimizations failed"); return false; } @@ -639,7 +639,7 @@ bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream, Config.CodeGenOnly = true; Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule, - CombinedIndex); + CombinedIndex, {}); assert(!Err && "unexpected code-generation failure"); (void)Err; From 33aa80b6751187fbaedc83a7bf3ef22322c5a295 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Sat, 25 Oct 2025 15:48:00 -0700 Subject: [PATCH 6/7] Actually use the passed in bitcode libfuncs --- llvm/lib/LTO/LTOBackend.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 38486d755f906..0f4151dda3a91 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -239,7 +239,8 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, unsigned OptLevel, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, - const ModuleSummaryIndex *ImportSummary) { + const ModuleSummaryIndex *ImportSummary, + const DenseSet &BitcodeLibFuncs) { std::optional PGOOpt; if (!Conf.SampleProfile.empty()) PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping, @@ -283,14 +284,23 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, TLII->disableAllFunctions(); TargetLibraryInfo TLI(*TLII); - for (unsigned I = 0, E = static_cast(LibFunc::NumLibFuncs); - I != E; ++I) { + for (unsigned I = 0, E = static_cast(LibFunc::NumLibFuncs); I != E; + ++I) { LibFunc F = static_cast(I); - GlobalValue *Val = Mod.getNamedValue(TLI.getName(F)); + StringRef Name = TLI.getName(F); + GlobalValue *Val = Mod.getNamedValue(Name); + + // LibFuncs present in the current TU can always be referenced. + if (Val && !Val->isDeclaration()) + continue; + + // LibFuncs not implemented in bitcode can always be referenced. + if (!BitcodeLibFuncs.contains(Name)) + continue; + // TODO: Non-lto functions should not be disabled, nor should functions that // are somewhere in a ThinLTO link (just not imported in this module). - if (!Val || Val->isDeclaration()) - TLII->setUnavailable(F); + TLII->setUnavailable(F); } FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); @@ -402,9 +412,12 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, // analysis in the case of a ThinLTO build where this might be an empty // regular LTO combined module, with a large combined index from ThinLTO. if (!isEmptyModule(Mod)) { + DenseSet BitcodeLibFuncsSet; + for (const char *F : BitcodeLibFuncs) + BitcodeLibFuncsSet.insert(F); // FIXME: Plumb the combined index into the new pass manager. runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary, - ImportSummary); + ImportSummary, BitcodeLibFuncsSet); } return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } From 4388d283cb2628e94bf87f169962bec94ee2bee8 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Thu, 13 Nov 2025 15:43:57 -0800 Subject: [PATCH 7/7] Fix wild pointer issue --- llvm/include/llvm/LTO/LTO.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 346ff9817737f..d0a447df69bf3 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -604,7 +604,8 @@ class LTO { // Diagnostic optimization remarks file LLVMRemarkFileHandle DiagnosticOutputFile; - const SmallVector *BitcodeLibFuncs; + const SmallVector *BitcodeLibFuncs = &EmptyBitcodeLibFuncs; + SmallVector EmptyBitcodeLibFuncs; }; /// The resolution for a symbol. The linker must provide a SymbolResolution for