[lld] [llvm] [DRAFT] "Builtins world" for LTO (PR #164916)
Daniel Thornburgh via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 4 15:59:54 PST 2025
https://github.com/mysterymath updated https://github.com/llvm/llvm-project/pull/164916
>From cd8397b9e159ffa6c47228ed5efd89e7acbf8be4 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 7 Aug 2025 16:05:09 -0700
Subject: [PATCH 01/16] 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<unsigned>(LibFunc::NumLibFuncs);
+ I != E; ++I) {
+ LibFunc F = static_cast<LibFunc>(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<char, 0> &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<const Comdat *, int> 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<storage::Str> DependentLibraries;
bool isPreservedName(StringRef Name) {
+ LibFunc F;
+ if (TLI.getLibFunc(Name, F) && TLI.has(F))
+ return true;
return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported;
}
>From 22514275618a436da99ac8dd0437e729a1cd3670 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 20 Oct 2025 15:41:29 -0700
Subject: [PATCH 02/16] 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<const char *>
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<const char *>
+ 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 a02af59600c44..df49143b50027 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -1407,6 +1407,21 @@ SmallVector<const char *> LTO::getRuntimeLibcallSymbols(const Triple &TT) {
return LibcallSymbols;
}
+SmallVector<const char *> LTO::getLibFuncSymbols(const Triple &TT,
+ StringSaver &Saver) {
+ auto TLII = std::make_unique<TargetLibraryInfoImpl>(TT);
+ TargetLibraryInfo TLI(*TLII);
+ SmallVector<const char *> LibFuncSymbols;
+ LibFuncSymbols.reserve(LibFunc::NumLibFuncs);
+ for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E;
+ ++I) {
+ LibFunc F = static_cast<LibFunc>(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 46677819ac1ab36698e4382d3821eca413f8910c Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 21 Oct 2025 14:47:17 -0700
Subject: [PATCH 03/16] 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<const char *> bitcodeLibFuncs;
+ for (const char *libFunc : lto::LTO::getLibFuncSymbols(tt, saver)) {
+ Symbol *sym = ctx.symtab->find(libFunc);
+ if (!sym)
+ continue;
+ if (isa<BitcodeFile>(sym->file))
+ bitcodeLibFuncs.push_back(libFunc);
+ }
+
+ ltoObjectFiles = lto->compile(bitcodeLibFuncs);
for (auto &file : ltoObjectFiles) {
auto *obj = cast<ObjFile<ELFT>>(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<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {
+SmallVector<std::unique_ptr<InputFile>, 0>
+BitcodeCompiler::compile(const SmallVector<const char *> &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<std::unique_ptr<InputFile>, 0> compile();
+ SmallVector<std::unique_ptr<InputFile>, 0>
+ compile(const SmallVector<const char *> &bitcodeLibfuncs);
private:
Ctx &ctx;
>From 8458d1b322c4c9e5e06927822e422dc11dc67a19 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 21 Oct 2025 14:48:52 -0700
Subject: [PATCH 04/16] 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 d5448afcdcd1d4ae76c748c37f7c52c1835fced8 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 21 Oct 2025 14:53:13 -0700
Subject: [PATCH 05/16] 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<std::unique_ptr<InputFile>, 0>
-BitcodeCompiler::compile(const SmallVector<const char *> &bitcodeLibfuncs) {
+BitcodeCompiler::compile(const SmallVector<const char *> &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<std::unique_ptr<InputFile>, 0>
- compile(const SmallVector<const char *> &bitcodeLibfuncs);
+ compile(const SmallVector<const char *> &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<std::unique_ptr<ThinBackendProc>(
const Config &C, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddStreamFn AddStream, FileCache Cache)>;
+ AddStreamFn AddStream, FileCache Cache,
+ const SmallVector<const char *> &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<ThinBackendProc> operator()(
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddStreamFn AddStream, FileCache Cache) {
+ AddStreamFn AddStream, FileCache Cache,
+ const SmallVector<const char *> &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<bool>(Func); }
@@ -400,6 +402,8 @@ class LTO {
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
ArrayRef<SymbolResolution> Res);
+ LLVM_ABI void setBitcodeLibFuncs(const SmallVector<const char *> &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<const char *> *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<uint8_t> &CmdArgs);
+ const std::vector<uint8_t> &CmdArgs,
+ const SmallVector<const char*>& 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<const char *> &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<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
+ const SmallVector<const char *> &BitcodeLibFuncs,
AddStreamFn IRAddStream = nullptr,
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index df49143b50027..f34234210a208 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -763,6 +763,10 @@ Error LTO::add(std::unique_ptr<InputFile> Input,
return Error::success();
}
+void LTO::setBitcodeLibFuncs(const SmallVector<const char *> &BitcodeLibFuncs) {
+ this->BitcodeLibFuncs = &BitcodeLibFuncs;
+}
+
Expected<ArrayRef<SymbolResolution>>
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
unsigned ModI, ArrayRef<SymbolResolution> Res) {
@@ -1387,7 +1391,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;
}
@@ -1499,6 +1504,7 @@ class CGThinBackend : public ThinBackendProc {
class InProcessThinBackend : public CGThinBackend {
protected:
FileCache Cache;
+ const SmallVector<const char*> &BitcodeLibFuncs;
public:
InProcessThinBackend(
@@ -1506,11 +1512,12 @@ class InProcessThinBackend : public CGThinBackend {
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite,
- bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles)
+ bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
+ const SmallVector<const char *> &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,
@@ -1531,7 +1538,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()))
@@ -1616,13 +1623,14 @@ class FirstRoundThinBackend : public InProcessThinBackend {
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddStreamFn CGAddStream, FileCache CGCache, AddStreamFn IRAddStream,
+ AddStreamFn CGAddStream, FileCache CGCache,
+ const SmallVector<const char *> &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(
@@ -1645,7 +1653,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
@@ -1712,6 +1720,7 @@ class SecondRoundThinBackend : public InProcessThinBackend {
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
+ const SmallVector<const char *> &BitcodeLibFuncs,
std::unique_ptr<SmallVector<StringRef>> IRFiles,
stable_hash CombinedCGDataHash)
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
@@ -1719,7 +1728,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(
@@ -1740,7 +1749,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),
@@ -1779,11 +1788,12 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddStreamFn AddStream, FileCache Cache) {
+ AddStreamFn AddStream, FileCache Cache,
+ const SmallVector<const char *> &BitcodeLibFuncs) {
return std::make_unique<InProcessThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
- ShouldEmitImportsFiles);
+ ShouldEmitImportsFiles, BitcodeLibFuncs);
};
return ThinBackend(Func, Parallelism);
}
@@ -1900,7 +1910,8 @@ ThinBackend lto::createWriteIndexesThinBackend(
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddStreamFn AddStream, FileCache Cache) {
+ AddStreamFn AddStream, FileCache Cache,
+ const SmallVector<const char *> &BitcodeLibFuncs) {
return std::make_unique<WriteIndexesThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
@@ -2118,7 +2129,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
if (!CodeGenDataThinLTOTwoRounds) {
std::unique_ptr<ThinBackendProc> BackendProc =
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
- AddStream, Cache);
+ AddStream, Cache, *BitcodeLibFuncs);
return RunBackends(BackendProc.get());
}
@@ -2141,7 +2152,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n");
auto FirstRoundLTO = std::make_unique<FirstRoundThinBackend>(
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;
@@ -2157,7 +2168,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n");
auto SecondRoundLTO = std::make_unique<SecondRoundThinBackend>(
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
- AddStream, Cache, IR.getResult(), CombinedHash);
+ AddStream, Cache, *BitcodeLibFuncs, IR.getResult(), CombinedHash);
return RunBackends(SecondRoundLTO.get());
}
@@ -2635,7 +2646,8 @@ ThinBackend lto::createOutOfProcessThinBackend(
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddStreamFn AddStream, FileCache Cache) {
+ AddStreamFn AddStream, FileCache Cache,
+ const SmallVector<const char *> &BitcodeLibFuncs) {
return std::make_unique<OutOfProcessThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
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<uint8_t> &CmdArgs) {
+ const std::vector<uint8_t> &CmdArgs,
+ const SmallVector<const char *> &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<const char *> &BitcodeLibFuncs) {
llvm::TimeTraceScope timeScope("LTO backend");
Expected<const Target *> 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<uint8_t>()))
+ /*CmdArgs*/ std::vector<uint8_t>(), 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<StringRef, BitcodeModule> *ModuleMap,
- bool CodeGenOnly, AddStreamFn IRAddStream,
+ bool CodeGenOnly,
+ const SmallVector<const char *> &BitcodeLibFuncs,
+ AddStreamFn IRAddStream,
const std::vector<uint8_t> &CmdArgs) {
llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier());
Expected<const Target *> 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<uint8_t>())) {
+ /*CmdArgs*/ std::vector<uint8_t>(), {})) {
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 3f4f20a4265a2f64553323f656df980fbb21f667 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <mysterymath at gmail.com>
Date: Sat, 25 Oct 2025 15:48:00 -0700
Subject: [PATCH 06/16] 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<StringRef> &BitcodeLibFuncs) {
std::optional<PGOOptions> 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<unsigned>(LibFunc::NumLibFuncs);
- I != E; ++I) {
+ for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E;
+ ++I) {
LibFunc F = static_cast<LibFunc>(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<StringRef> 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 5cb566b6ca685ed7a12168230bf03241e4086f7f Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <mysterymath at gmail.com>
Date: Thu, 13 Nov 2025 15:43:57 -0800
Subject: [PATCH 07/16] 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<const char *> *BitcodeLibFuncs;
+ const SmallVector<const char *> *BitcodeLibFuncs = &EmptyBitcodeLibFuncs;
+ SmallVector<const char *> EmptyBitcodeLibFuncs;
};
/// The resolution for a symbol. The linker must provide a SymbolResolution for
>From 6bc88041acea89a02ea42a6294c3554b7affd7ac Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 3 Dec 2025 14:57:29 -0800
Subject: [PATCH 08/16] TODO->FIXME
---
llvm/lib/LTO/LTOBackend.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index 0f4151dda3a91..8c9e7e63c0654 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -298,8 +298,8 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
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).
+ // FIXME: Non-lto functions should not be disabled, nor should functions
+ // that are somewhere in a ThinLTO link (just not imported in this module).
TLII->setUnavailable(F);
}
>From 4237433dd86f3193e23ea03b9dc247c8ce30d98f Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 3 Dec 2025 15:03:48 -0800
Subject: [PATCH 09/16] Add Paul's test case
---
llvm/test/LTO/Resolution/X86/bcmp-libcall.ll | 34 ++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
diff --git a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll b/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
new file mode 100644
index 0000000000000..415001eb5dd9d
--- /dev/null
+++ b/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
@@ -0,0 +1,34 @@
+;; This test comes from a real world scenario in LTO, where the
+;; definition of bcmp is deleted because it has no uses, but later instcombine
+;; re-introduces a call to bcmp() as part of SimplifyLibCalls.
+
+; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl
+; RUN: llvm-lto2 run -o %t2 \
+; RUN: -r %t,foo,plx \
+; RUN: -r %t,memcmp,x \
+; RUN: -r %t,bcmp,pl %t -save-temps
+; RUN: llvm-dis %t2.1.2.internalize.bc -o - | FileCheck %s
+
+define i1 @foo(ptr %0, [2 x i32] %1) {
+ ; CHECK-LABEL: define{{.*}}i1 @foo
+ ; CHECK-NEXT: %size = extractvalue [2 x i32] %1, 1
+ ; CHECK-NEXT: %cmp = {{.*}}call i32 @memcmp
+ ; CHECK-NEXT: %eq = icmp eq i32 %cmp, 0
+ ; CHECK-NEXT: ret i1 %eq
+
+ %size = extractvalue [2 x i32] %1, 1
+ %cmp = call i32 @memcmp(ptr %0, ptr null, i32 %size)
+ %eq = icmp eq i32 %cmp, 0
+ ret i1 %eq
+}
+
+; CHECK: declare i32 @memcmp(ptr, ptr, i32)
+declare i32 @memcmp(ptr, ptr, i32)
+
+;; Ensure bcmp is removed from module. Follow up patches can address this.
+; CHECK-NOT: declare{{.*}}i32 @bcmp
+; CHECK-NOT: define{{.*}}i32 @bcmp
+define i32 @bcmp(ptr %0, ptr %1, i32 %2) {
+ ret i32 0
+}
+
>From cd64d1aa452107195991155b03b8fca0d023c6a4 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 3 Dec 2025 15:06:45 -0800
Subject: [PATCH 10/16] Make the test case work
---
llvm/test/LTO/Resolution/X86/bcmp-libcall.ll | 36 ++++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll b/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
index 415001eb5dd9d..2d47f2bd95201 100644
--- a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
+++ b/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
@@ -1,34 +1,34 @@
-;; This test comes from a real world scenario in LTO, where the
-;; definition of bcmp is deleted because it has no uses, but later instcombine
-;; re-introduces a call to bcmp() as part of SimplifyLibCalls.
+;; This test comes from a real world scenario in LTO, where the definition of
+;; bcmp was deleted because it has no uses, but later instcombine re-introduced
+;; a call to bcmp() as part of SimplifyLibCalls. Such deletions must not be
+;; allowed.
; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl
; RUN: llvm-lto2 run -o %t2 \
; RUN: -r %t,foo,plx \
; RUN: -r %t,memcmp,x \
-; RUN: -r %t,bcmp,pl %t -save-temps
-; RUN: llvm-dis %t2.1.2.internalize.bc -o - | FileCheck %s
+; RUN: -r %t,bcmp,pl \
+; RUN: -r %t,bcmp_impl,x %t -save-temps
+; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s
-define i1 @foo(ptr %0, [2 x i32] %1) {
+define i1 @foo(ptr %0, ptr %1, i64 %2) {
; CHECK-LABEL: define{{.*}}i1 @foo
- ; CHECK-NEXT: %size = extractvalue [2 x i32] %1, 1
- ; CHECK-NEXT: %cmp = {{.*}}call i32 @memcmp
- ; CHECK-NEXT: %eq = icmp eq i32 %cmp, 0
+ ; CHECK-NEXT: %bcmp = {{.*}}call i32 @bcmp
+ ; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0
; CHECK-NEXT: ret i1 %eq
- %size = extractvalue [2 x i32] %1, 1
- %cmp = call i32 @memcmp(ptr %0, ptr null, i32 %size)
+ %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
%eq = icmp eq i32 %cmp, 0
ret i1 %eq
}
-; CHECK: declare i32 @memcmp(ptr, ptr, i32)
-declare i32 @memcmp(ptr, ptr, i32)
+declare i32 @memcmp(ptr, ptr, i64)
+declare i32 @bcmp_impl(ptr, ptr, i64);
-;; Ensure bcmp is removed from module. Follow up patches can address this.
-; CHECK-NOT: declare{{.*}}i32 @bcmp
-; CHECK-NOT: define{{.*}}i32 @bcmp
-define i32 @bcmp(ptr %0, ptr %1, i32 %2) {
- ret i32 0
+;; Ensure bcmp is not removed from module.
+; CHECK: define{{.*}}i32 @bcmp
+define i32 @bcmp(ptr %0, ptr %1, i64 %2) noinline {
+ %r = call i32 @bcmp_impl(ptr %0, ptr %1, i64 %2)
+ ret i32 %r
}
>From 165cd3bca159ca284e5244134a529757e550de70 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 3 Dec 2025 15:34:42 -0800
Subject: [PATCH 11/16] Test for externality
---
llvm/test/LTO/Resolution/X86/bcmp-libcall.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll b/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
index 2d47f2bd95201..e07db605d5870 100644
--- a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
+++ b/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
@@ -25,8 +25,8 @@ define i1 @foo(ptr %0, ptr %1, i64 %2) {
declare i32 @memcmp(ptr, ptr, i64)
declare i32 @bcmp_impl(ptr, ptr, i64);
-;; Ensure bcmp is not removed from module.
-; CHECK: define{{.*}}i32 @bcmp
+;; Ensure bcmp is not removed from module because it is external.
+; CHECK: define dso_local i32 @bcmp
define i32 @bcmp(ptr %0, ptr %1, i64 %2) noinline {
%r = call i32 @bcmp_impl(ptr %0, ptr %1, i64 %2)
ret i32 %r
>From 0cde1523ee0b9b018c0c459b85bf05679b7f072d Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 3 Dec 2025 15:37:38 -0800
Subject: [PATCH 12/16] Test for external non-bitcode libcall
---
.../X86/libcall-external-not-bitcode.ll | 20 +++++++++++++++++++
.../X86/{bcmp-libcall.ll => libcall-in-tu.ll} | 2 +-
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll
rename llvm/test/LTO/Resolution/X86/{bcmp-libcall.ll => libcall-in-tu.ll} (96%)
diff --git a/llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll b/llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll
new file mode 100644
index 0000000000000..2e6cc798d22cd
--- /dev/null
+++ b/llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll
@@ -0,0 +1,20 @@
+; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl
+; RUN: llvm-lto2 run -o %t2 \
+; RUN: -r %t,foo,plx \
+; RUN: -r %t,memcmp,x \
+; RUN: -r %t,bcmp,pl %t -save-temps
+; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s
+
+define i1 @foo(ptr %0, ptr %1, i64 %2) {
+ ; CHECK-LABEL: define{{.*}}i1 @foo
+ ; CHECK-NEXT: %bcmp = {{.*}}call i32 @bcmp
+ ; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0
+ ; CHECK-NEXT: ret i1 %eq
+
+ %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
+ %eq = icmp eq i32 %cmp, 0
+ ret i1 %eq
+}
+
+declare i32 @memcmp(ptr, ptr, i64)
+declare i32 @bcmp(ptr, ptr, i64)
diff --git a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll b/llvm/test/LTO/Resolution/X86/libcall-in-tu.ll
similarity index 96%
rename from llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
rename to llvm/test/LTO/Resolution/X86/libcall-in-tu.ll
index e07db605d5870..948f21a6536ca 100644
--- a/llvm/test/LTO/Resolution/X86/bcmp-libcall.ll
+++ b/llvm/test/LTO/Resolution/X86/libcall-in-tu.ll
@@ -23,7 +23,7 @@ define i1 @foo(ptr %0, ptr %1, i64 %2) {
}
declare i32 @memcmp(ptr, ptr, i64)
-declare i32 @bcmp_impl(ptr, ptr, i64);
+declare i32 @bcmp_impl(ptr, ptr, i64)
;; Ensure bcmp is not removed from module because it is external.
; CHECK: define dso_local i32 @bcmp
>From b6ad9d7df40854cbc7ad3660ba761b94b44c3eb0 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 3 Dec 2025 15:42:57 -0800
Subject: [PATCH 13/16] Add bitcodelibfuncs flag to lto2 (not hooked up)
---
.../X86/libcall-external-bitcode.ll | 20 +++++++++++++++++++
llvm/tools/llvm-lto2/llvm-lto2.cpp | 4 ++++
2 files changed, 24 insertions(+)
create mode 100644 llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll
diff --git a/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll b/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll
new file mode 100644
index 0000000000000..bf530208e5d09
--- /dev/null
+++ b/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll
@@ -0,0 +1,20 @@
+; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl
+; RUN: llvm-lto2 run -o %t2 \
+; RUN: -r %t,foo,plx \
+; RUN: -r %t,memcmp,x \
+; RUN: -r %t,bcmp,pl --bitcode-libfuncs=bcmp %t -save-temps
+; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s
+
+define i1 @foo(ptr %0, ptr %1, i64 %2) {
+ ; CHECK-LABEL: define{{.*}}i1 @foo
+ ; CHECK-NEXT: %cmp = {{.*}}call i32 @memcmp
+ ; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0
+ ; CHECK-NEXT: ret i1 %eq
+
+ %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
+ %eq = icmp eq i32 %cmp, 0
+ ret i1 %eq
+}
+
+declare i32 @memcmp(ptr, ptr, i64)
+declare i32 @bcmp(ptr, ptr, i64)
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index 399306f39daeb..ac6c62ee6e8db 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -232,6 +232,10 @@ static cl::opt<bool>
AllVtablesHaveTypeInfos("all-vtables-have-type-infos", cl::Hidden,
cl::desc("All vtables have type infos"));
+static cl::list<std::string>
+ BitcodeLibFuncs("bitcode-libfuncs", cl::Hidden,
+ cl::desc("set of libfuncs implemented in bitcode"));
+
static void check(Error E, std::string Msg) {
if (!E)
return;
>From a2b7a49a2e9b984c39c0406457e0f62972f4b0ec Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 4 Dec 2025 14:53:09 -0800
Subject: [PATCH 14/16] Pass through bitcode libfuncs
---
llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll | 2 +-
llvm/tools/llvm-lto2/llvm-lto2.cpp | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll b/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll
index bf530208e5d09..95a599fe75e8b 100644
--- a/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll
+++ b/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll
@@ -8,7 +8,7 @@
define i1 @foo(ptr %0, ptr %1, i64 %2) {
; CHECK-LABEL: define{{.*}}i1 @foo
; CHECK-NEXT: %cmp = {{.*}}call i32 @memcmp
- ; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0
+ ; CHECK-NEXT: %eq = icmp eq i32 %cmp, 0
; CHECK-NEXT: ret i1 %eq
%cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index ac6c62ee6e8db..7f08ef8af2371 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -472,6 +472,11 @@ static int run(int argc, char **argv) {
if (HasErrors)
return 1;
+ SmallVector<const char *> CBitcodeLibFuncs;
+ for (const std::string &S : BitcodeLibFuncs)
+ CBitcodeLibFuncs.push_back(S.c_str());
+ Lto.setBitcodeLibFuncs(CBitcodeLibFuncs);
+
auto AddStream =
[&](size_t Task,
const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
>From e05bcf9f4e08db15cb2b1af8d9a4588298cfdd33 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 4 Dec 2025 15:27:37 -0800
Subject: [PATCH 15/16] Move to an owned vector of stringref
---
lld/ELF/Driver.cpp | 4 ++--
lld/ELF/LTO.cpp | 2 +-
lld/ELF/LTO.h | 2 +-
llvm/include/llvm/LTO/LTO.h | 11 +++++-----
llvm/include/llvm/LTO/LTOBackend.h | 6 +++---
llvm/lib/LTO/LTO.cpp | 32 +++++++++++++++---------------
llvm/lib/LTO/LTOBackend.cpp | 11 +++++-----
llvm/tools/llvm-lto2/llvm-lto2.cpp | 6 ++----
8 files changed, 35 insertions(+), 39 deletions(-)
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index b48e9f29d7b54..c7a2047af5ca6 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2712,8 +2712,8 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
llvm::Triple tt(ctx.bitcodeFiles.front()->obj->getTargetTriple());
llvm::BumpPtrAllocator alloc;
llvm::StringSaver saver(alloc);
- SmallVector<const char *> bitcodeLibFuncs;
- for (const char *libFunc : lto::LTO::getLibFuncSymbols(tt, saver)) {
+ SmallVector<StringRef> bitcodeLibFuncs;
+ for (StringRef libFunc : lto::LTO::getLibFuncSymbols(tt, saver)) {
Symbol *sym = ctx.symtab->find(libFunc);
if (!sym)
continue;
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index c661780302a43..839eed9956d3a 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -312,7 +312,7 @@ static void thinLTOCreateEmptyIndexFiles(Ctx &ctx) {
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting ObjectFile(s).
SmallVector<std::unique_ptr<InputFile>, 0>
-BitcodeCompiler::compile(const SmallVector<const char *> &bitcodeLibFuncs) {
+BitcodeCompiler::compile(const SmallVector<StringRef> &bitcodeLibFuncs) {
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
unsigned maxTasks = ltoObj->getMaxTasks();
diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h
index 99a61f8279c6a..8207e91460785 100644
--- a/lld/ELF/LTO.h
+++ b/lld/ELF/LTO.h
@@ -43,7 +43,7 @@ class BitcodeCompiler {
void add(BitcodeFile &f);
SmallVector<std::unique_ptr<InputFile>, 0>
- compile(const SmallVector<const char *> &bitcodeLibFuncs);
+ compile(const SmallVector<StringRef> &bitcodeLibFuncs);
private:
Ctx &ctx;
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index d0a447df69bf3..85586c8bf5195 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -265,7 +265,7 @@ using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
const Config &C, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
- const SmallVector<const char *> &BitcodeLibFuncs)>;
+ const SmallVector<StringRef> &BitcodeLibFuncs)>;
/// This type defines the behavior following the thin-link phase during ThinLTO.
/// It encapsulates a backend function and a strategy for thread pool
@@ -281,7 +281,7 @@ struct ThinBackend {
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
- const SmallVector<const char *> &BitcodeLibFuncs) {
+ const SmallVector<StringRef> &BitcodeLibFuncs) {
assert(isValid() && "Invalid backend function");
return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
std::move(AddStream), std::move(Cache), BitcodeLibFuncs);
@@ -402,7 +402,7 @@ class LTO {
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
ArrayRef<SymbolResolution> Res);
- LLVM_ABI void setBitcodeLibFuncs(const SmallVector<const char *> &BitcodeLibFuncs);
+ LLVM_ABI void setBitcodeLibFuncs(const SmallVector<StringRef> &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
@@ -429,7 +429,7 @@ class LTO {
/// 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<const char *>
+ LLVM_ABI static SmallVector<StringRef>
getLibFuncSymbols(const Triple &TT, llvm::StringSaver &Saver);
private:
@@ -604,8 +604,7 @@ class LTO {
// Diagnostic optimization remarks file
LLVMRemarkFileHandle DiagnosticOutputFile;
- const SmallVector<const char *> *BitcodeLibFuncs = &EmptyBitcodeLibFuncs;
- SmallVector<const char *> EmptyBitcodeLibFuncs;
+ SmallVector<StringRef> 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 26bff22819d91..6a7d7e0d87ac9 100644
--- a/llvm/include/llvm/LTO/LTOBackend.h
+++ b/llvm/include/llvm/LTO/LTOBackend.h
@@ -40,14 +40,14 @@ LLVM_ABI bool opt(const Config &Conf, TargetMachine *TM, unsigned Task,
ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary,
const std::vector<uint8_t> &CmdArgs,
- const SmallVector<const char*>& BitcodeLibFuncs);
+ const SmallVector<StringRef> &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,
- const SmallVector<const char *> &BitcodeLibFuncs);
+ const SmallVector<StringRef> &BitcodeLibFuncs);
/// Runs a ThinLTO backend.
/// If \p ModuleMap is not nullptr, all the module files to be imported have
@@ -64,7 +64,7 @@ thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
- const SmallVector<const char *> &BitcodeLibFuncs,
+ const SmallVector<StringRef> &BitcodeLibFuncs,
AddStreamFn IRAddStream = nullptr,
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index f34234210a208..e4312b4827f97 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -763,8 +763,8 @@ Error LTO::add(std::unique_ptr<InputFile> Input,
return Error::success();
}
-void LTO::setBitcodeLibFuncs(const SmallVector<const char *> &BitcodeLibFuncs) {
- this->BitcodeLibFuncs = &BitcodeLibFuncs;
+void LTO::setBitcodeLibFuncs(const SmallVector<StringRef> &BitcodeLibFuncs) {
+ this->BitcodeLibFuncs = BitcodeLibFuncs;
}
Expected<ArrayRef<SymbolResolution>>
@@ -1392,7 +1392,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
if (Error Err =
backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex,
- *BitcodeLibFuncs))
+ BitcodeLibFuncs))
return Err;
}
@@ -1412,11 +1412,11 @@ SmallVector<const char *> LTO::getRuntimeLibcallSymbols(const Triple &TT) {
return LibcallSymbols;
}
-SmallVector<const char *> LTO::getLibFuncSymbols(const Triple &TT,
- StringSaver &Saver) {
+SmallVector<StringRef> LTO::getLibFuncSymbols(const Triple &TT,
+ StringSaver &Saver) {
auto TLII = std::make_unique<TargetLibraryInfoImpl>(TT);
TargetLibraryInfo TLI(*TLII);
- SmallVector<const char *> LibFuncSymbols;
+ SmallVector<StringRef> LibFuncSymbols;
LibFuncSymbols.reserve(LibFunc::NumLibFuncs);
for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E;
++I) {
@@ -1504,7 +1504,7 @@ class CGThinBackend : public ThinBackendProc {
class InProcessThinBackend : public CGThinBackend {
protected:
FileCache Cache;
- const SmallVector<const char*> &BitcodeLibFuncs;
+ const SmallVector<StringRef> &BitcodeLibFuncs;
public:
InProcessThinBackend(
@@ -1513,7 +1513,7 @@ class InProcessThinBackend : public CGThinBackend {
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite,
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
- const SmallVector<const char *> &BitcodeLibFuncs)
+ const SmallVector<StringRef> &BitcodeLibFuncs)
: CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
AddStream, OnWrite, ShouldEmitIndexFiles,
ShouldEmitImportsFiles, ThinLTOParallelism),
@@ -1624,7 +1624,7 @@ class FirstRoundThinBackend : public InProcessThinBackend {
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn CGAddStream, FileCache CGCache,
- const SmallVector<const char *> &BitcodeLibFuncs, AddStreamFn IRAddStream,
+ const SmallVector<StringRef> &BitcodeLibFuncs, AddStreamFn IRAddStream,
FileCache IRCache)
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
ModuleToDefinedGVSummaries, std::move(CGAddStream),
@@ -1720,7 +1720,7 @@ class SecondRoundThinBackend : public InProcessThinBackend {
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
- const SmallVector<const char *> &BitcodeLibFuncs,
+ const SmallVector<StringRef> &BitcodeLibFuncs,
std::unique_ptr<SmallVector<StringRef>> IRFiles,
stable_hash CombinedCGDataHash)
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
@@ -1789,7 +1789,7 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
- const SmallVector<const char *> &BitcodeLibFuncs) {
+ const SmallVector<StringRef> &BitcodeLibFuncs) {
return std::make_unique<InProcessThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
@@ -1911,7 +1911,7 @@ ThinBackend lto::createWriteIndexesThinBackend(
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
- const SmallVector<const char *> &BitcodeLibFuncs) {
+ const SmallVector<StringRef> &BitcodeLibFuncs) {
return std::make_unique<WriteIndexesThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
@@ -2129,7 +2129,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
if (!CodeGenDataThinLTOTwoRounds) {
std::unique_ptr<ThinBackendProc> BackendProc =
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
- AddStream, Cache, *BitcodeLibFuncs);
+ AddStream, Cache, BitcodeLibFuncs);
return RunBackends(BackendProc.get());
}
@@ -2152,7 +2152,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n");
auto FirstRoundLTO = std::make_unique<FirstRoundThinBackend>(
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
- CG.AddStream, CG.Cache, *BitcodeLibFuncs, IR.AddStream, IR.Cache);
+ CG.AddStream, CG.Cache, BitcodeLibFuncs, IR.AddStream, IR.Cache);
if (Error E = RunBackends(FirstRoundLTO.get()))
return E;
@@ -2168,7 +2168,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n");
auto SecondRoundLTO = std::make_unique<SecondRoundThinBackend>(
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
- AddStream, Cache, *BitcodeLibFuncs, IR.getResult(), CombinedHash);
+ AddStream, Cache, BitcodeLibFuncs, IR.getResult(), CombinedHash);
return RunBackends(SecondRoundLTO.get());
}
@@ -2647,7 +2647,7 @@ ThinBackend lto::createOutOfProcessThinBackend(
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
- const SmallVector<const char *> &BitcodeLibFuncs) {
+ const SmallVector<StringRef> &BitcodeLibFuncs) {
return std::make_unique<OutOfProcessThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index 8c9e7e63c0654..f621b922d4515 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -387,7 +387,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary,
const std::vector<uint8_t> &CmdArgs,
- const SmallVector<const char *> &BitcodeLibFuncs) {
+ const SmallVector<StringRef> &BitcodeLibFuncs) {
llvm::TimeTraceScope timeScope("opt");
if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) {
// FIXME: the motivation for capturing post-merge bitcode and command line
@@ -412,9 +412,8 @@ 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<StringRef> BitcodeLibFuncsSet;
- for (const char *F : BitcodeLibFuncs)
- BitcodeLibFuncsSet.insert(F);
+ DenseSet<StringRef> BitcodeLibFuncsSet(BitcodeLibFuncs.begin(),
+ BitcodeLibFuncs.end());
// FIXME: Plumb the combined index into the new pass manager.
runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary,
ImportSummary, BitcodeLibFuncsSet);
@@ -579,7 +578,7 @@ Error lto::finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile) {
Error lto::backend(const Config &C, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel, Module &Mod,
ModuleSummaryIndex &CombinedIndex,
- const SmallVector<const char *> &BitcodeLibFuncs) {
+ const SmallVector<StringRef> &BitcodeLibFuncs) {
llvm::TimeTraceScope timeScope("LTO backend");
Expected<const Target *> TOrErr = initAndLookupTarget(C, Mod);
if (!TOrErr)
@@ -632,7 +631,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> *ModuleMap,
bool CodeGenOnly,
- const SmallVector<const char *> &BitcodeLibFuncs,
+ const SmallVector<StringRef> &BitcodeLibFuncs,
AddStreamFn IRAddStream,
const std::vector<uint8_t> &CmdArgs) {
llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier());
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index 7f08ef8af2371..fbac9700db04f 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -472,10 +472,8 @@ static int run(int argc, char **argv) {
if (HasErrors)
return 1;
- SmallVector<const char *> CBitcodeLibFuncs;
- for (const std::string &S : BitcodeLibFuncs)
- CBitcodeLibFuncs.push_back(S.c_str());
- Lto.setBitcodeLibFuncs(CBitcodeLibFuncs);
+ Lto.setBitcodeLibFuncs(
+ SmallVector<StringRef>(BitcodeLibFuncs.begin(), BitcodeLibFuncs.end()));
auto AddStream =
[&](size_t Task,
>From aed8c7620d274c5b51394a9c60865ff0d56789a7 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 4 Dec 2025 15:55:03 -0800
Subject: [PATCH 16/16] Add some doc comments
---
llvm/include/llvm/LTO/LTO.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index 85586c8bf5195..055c9996c3a72 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -402,6 +402,9 @@ class LTO {
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
ArrayRef<SymbolResolution> Res);
+ /// Set the list of functions implemented in bitcode across the link, whether
+ /// extracted or not. Such functions may not be referenced if they were not
+ /// extracted by the time LTO occurs.
LLVM_ABI void setBitcodeLibFuncs(const SmallVector<StringRef> &BitcodeLibFuncs);
/// Returns an upper bound on the number of tasks that the client may expect.
More information about the llvm-commits
mailing list