[lld] lld: Add initial support for GNU LTO format (PR #157175)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 5 14:02:31 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Tulio Magno Quites Machado Filho (tuliom)
<details>
<summary>Changes</summary>
This is not feature complete yet, but is able to link simple executables.
The feature is disabled by default and can be enable via
`-DLLD_LINK_GPL3:BOOL=ON -DLLD_ENABLE_GNU_LTO:BOOL=ON`.
This implementation reuses GCC's plugin `liblto_plugin.so`, loading it at
runtime, when necessary.
---
Patch is 29.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/157175.diff
18 Files Affected:
- (modified) lld/CMakeLists.txt (+8)
- (modified) lld/ELF/CMakeLists.txt (+9)
- (modified) lld/ELF/Config.h (+6-1)
- (modified) lld/ELF/Driver.cpp (+69-5)
- (modified) lld/ELF/InputFiles.cpp (+3-3)
- (modified) lld/ELF/InputFiles.h (+16-5)
- (modified) lld/ELF/LTO.cpp (+241-5)
- (modified) lld/ELF/LTO.h (+69-6)
- (modified) lld/ELF/Options.td (+4-4)
- (added) lld/cmake/modules/FindGNULTO.cmake (+38)
- (added) lld/include/lld/config.h.cmake (+16)
- (added) lld/test/ELF/Inputs/plugin.so ()
- (added) lld/test/ELF/gnu-lto/hello.test (+28)
- (removed) lld/test/ELF/ignore-plugin.test (-2)
- (modified) lld/test/ELF/lto-plugin-ignore.s (-1)
- (added) lld/test/ELF/plugin.test (+21)
- (modified) lld/test/lit.cfg.py (+20)
- (modified) lld/test/lit.site.cfg.py.in (+2)
``````````diff
diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt
index 80e25204a65ee..9481d71b0ca57 100644
--- a/lld/CMakeLists.txt
+++ b/lld/CMakeLists.txt
@@ -177,6 +177,14 @@ if (LLD_DEFAULT_LD_LLD_IS_MINGW)
add_definitions("-DLLD_DEFAULT_LD_LLD_IS_MINGW=1")
endif()
+option(LLD_LINK_GPL3 "Allow LLD to link to GPLv3-licensed files")
+option(LLD_ENABLE_GNU_LTO "Enable support for GNU LTO plugin")
+if(!LLD_LINK_GPL3)
+ # Support for GNU LTO require linking to liblto_plugin.so from GCC which is
+ # licensed as GPLv3.
+ set(LLD_ENABLE_GNU_LTO FALSE)
+endif()
+
if (MSVC)
add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.'
add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header.
diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt
index ec3f6382282b1..82121cb6b2422 100644
--- a/lld/ELF/CMakeLists.txt
+++ b/lld/ELF/CMakeLists.txt
@@ -18,6 +18,15 @@ if(LLVM_ENABLE_ZSTD)
list(APPEND imported_libs ${zstd_target})
endif()
+set(GNULTO_INCLUDE_DIR "" CACHE PATH "Additional directory, where CMake should search for plugin-api.h")
+if(LLD_ENABLE_GNU_LTO)
+ find_package(GNULTO REQUIRED)
+endif()
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/lld/config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/../include/lld/config.h)
+
add_lld_library(lldELF
AArch64ErrataFix.cpp
Arch/AArch64.cpp
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index a83a4c1176f6f..bb9638387a15f 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -54,6 +54,7 @@ class TargetInfo;
struct Ctx;
struct Partition;
struct PhdrEntry;
+class IRCompiler;
class BssSection;
class GdbIndexSection;
@@ -191,6 +192,7 @@ class LinkerDriver {
void inferMachineType();
template <class ELFT> void link(llvm::opt::InputArgList &args);
template <class ELFT> void compileBitcodeFiles(bool skipLinkedOutput);
+ template <class ELFT> void compileGccIRFiles(bool skipLinkedOutput);
bool tryAddFatLTOFile(MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy);
// True if we are in --whole-archive and --no-whole-archive.
@@ -199,7 +201,7 @@ class LinkerDriver {
// True if we are in --start-lib and --end-lib.
bool inLib = false;
- std::unique_ptr<BitcodeCompiler> lto;
+ std::unique_ptr<IRCompiler> lto;
SmallVector<std::unique_ptr<InputFile>, 0> files, ltoObjectFiles;
public:
@@ -241,9 +243,12 @@ struct Config {
llvm::StringRef optRemarksPasses;
llvm::StringRef optRemarksFormat;
llvm::StringRef optStatsFilename;
+ llvm::StringRef plugin;
+ llvm::SmallVector<std::string, 0> pluginOpt;
llvm::StringRef progName;
llvm::StringRef printArchiveStats;
llvm::StringRef printSymbolOrder;
+ llvm::StringRef resolutionFile;
llvm::StringRef soName;
llvm::StringRef sysroot;
llvm::StringRef thinLTOCacheDir;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6c2f318ffe469..e0510edd59861 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1786,6 +1786,14 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
cl::ResetAllOptionOccurrences();
+ // Ignore -plugin=LLVMgold.so because we don't need to load it.
+ StringRef v = args.getLastArgValue(OPT_plugin);
+ if (!v.empty() && !v.ends_with("LLVMgold.so"))
+ if (!llvm::sys::fs::exists(v))
+ ErrAlways(ctx) << "Cannot find plugin " << v;
+ else
+ ctx.arg.plugin = v;
+
// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
parseClangOption(ctx, ctx.saver.save("-mcpu=" + StringRef(arg->getValue())),
@@ -1796,14 +1804,31 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
arg->getSpelling());
// GCC collect2 passes -plugin-opt=path/to/lto-wrapper with an absolute or
- // relative path. Just ignore. If not ended with "lto-wrapper" (or
- // "lto-wrapper.exe" for GCC cross-compiled for Windows), consider it an
- // unsupported LLVMgold.so option and error.
+ // relative path. If not ended with "lto-wrapper" (or "lto-wrapper.exe" for
+ // GCC cross-compiled for Windows), consider it an unsupported LLVMgold.so
+ // option and error.
for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq)) {
StringRef v(arg->getValue());
if (!v.ends_with("lto-wrapper") && !v.ends_with("lto-wrapper.exe"))
ErrAlways(ctx) << arg->getSpelling() << ": unknown plugin option '"
<< arg->getValue() << "'";
+ else if (!ctx.arg.plugin.empty())
+#if LLD_ENABLE_GNU_LTO
+ ctx.arg.pluginOpt.push_back(v.str());
+#else
+ ErrAlways(ctx) << arg->getSpelling() << " : support for GNU LTO is disabled";
+#endif
+ }
+
+ // Parse GCC collect2 options.
+ if (!ctx.arg.plugin.empty()) {
+#if LLD_ENABLE_GNU_LTO
+ StringRef v = args.getLastArgValue(OPT_plugin_opt_fresolution);
+ if (!v.empty()) {
+ ctx.arg.resolutionFile = v;
+ ctx.arg.pluginOpt.push_back(std::string("-fresolution=" + v.str()));
+ }
+#endif
}
ctx.arg.passPlugins = args::getStrings(args, OPT_load_pass_plugins);
@@ -2683,7 +2708,7 @@ static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) {
}
// This function is where all the optimizations of link-time
-// optimization takes place. When LTO is in use, some input files are
+// optimization takes place. When LLVM LTO is in use, some input files are
// not in native object file format but in the LLVM bitcode format.
// This function compiles bitcode files into a few big native files
// using LLVM functions and replaces bitcode symbols with the results.
@@ -2732,6 +2757,39 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
}
}
+#if LLD_ENABLE_GNU_LTO
+template <class ELFT>
+void LinkerDriver::compileGccIRFiles(bool skipLinkedOutput) {
+ llvm::TimeTraceScope timeScope("LTO");
+ // Compile files and replace symbols.
+ GccIRCompiler *c = GccIRCompiler::getInstance(ctx);
+ lto.reset(c);
+
+ for (ELFFileBase *file : ctx.objectFiles)
+ c->add(*file);
+
+ ltoObjectFiles = c->compile();
+ for (auto &file : ltoObjectFiles) {
+ auto *obj = cast<ObjFile<ELFT>>(file.get());
+ obj->parse(/*ignoreComdats=*/true);
+
+ // For defined symbols in non-relocatable output,
+ // compute isExported and parse '@'.
+ if (!ctx.arg.relocatable)
+ for (Symbol *sym : obj->getGlobalSymbols()) {
+ if (!sym->isDefined())
+ continue;
+ if (ctx.arg.exportDynamic && sym->computeBinding(ctx) != STB_LOCAL)
+ sym->isExported = true;
+ if (sym->hasVersionSuffix)
+ sym->parseSymbolVersion(ctx);
+ }
+ ctx.objectFiles.push_back(obj);
+ }
+ return;
+}
+#endif
+
// The --wrap option is a feature to rename symbols so that you can write
// wrappers for existing functions. If you pass `--wrap=foo`, all
// occurrences of symbol `foo` are resolved to `__wrap_foo` (so, you are
@@ -3289,7 +3347,13 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// except a few linker-synthesized ones will be added to the symbol table.
const size_t numObjsBeforeLTO = ctx.objectFiles.size();
const size_t numInputFilesBeforeLTO = ctx.driver.files.size();
- compileBitcodeFiles<ELFT>(skipLinkedOutput);
+ if (ctx.arg.plugin.empty()) {
+ compileBitcodeFiles<ELFT>(skipLinkedOutput);
+#if LLD_ENABLE_GNU_LTO
+ } else {
+ compileGccIRFiles<ELFT>(skipLinkedOutput);
+#endif
+ }
// Symbol resolution finished. Report backward reference problems,
// --print-archive-stats=, and --why-extract=.
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index a5921feb18299..8b9b55c4a5d47 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -1845,8 +1845,8 @@ static bool dtltoAdjustMemberPathIfThinArchive(Ctx &ctx, StringRef archivePath,
return true;
}
-BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive, bool lazy)
+IRFile::IRFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
+ uint64_t offsetInArchive, bool lazy)
: InputFile(ctx, BitcodeKind, mb) {
this->archiveName = archiveName;
this->lazy = lazy;
@@ -1958,7 +1958,7 @@ void BitcodeFile::parse() {
addDependentLibrary(ctx, l, this);
}
-void BitcodeFile::parseLazy() {
+void IRFile::parseLazy() {
numSymbols = obj->symbols().size();
symbols = std::make_unique<Symbol *[]>(numSymbols);
for (auto [i, irSym] : llvm::enumerate(obj->symbols())) {
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index ba844ad18f637..551fbb85cb84f 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -16,6 +16,7 @@
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Threading.h"
@@ -321,15 +322,25 @@ template <class ELFT> class ObjFile : public ELFFileBase {
ArrayRef<Elf_Word> shndxTable;
};
-class BitcodeFile : public InputFile {
+class IRFile : public InputFile {
public:
- BitcodeFile(Ctx &, MemoryBufferRef m, StringRef archiveName,
- uint64_t offsetInArchive, bool lazy);
+ IRFile(Ctx &ctx, MemoryBufferRef m, StringRef archiveName, uint64_t offsetInArchive,
+ bool lazy);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
- void parse();
+ virtual void parse() = 0;
void parseLazy();
- void postParse();
+ virtual void postParse() = 0;
std::unique_ptr<llvm::lto::InputFile> obj;
+};
+
+class BitcodeFile : public IRFile {
+public:
+ BitcodeFile(Ctx &ctx, MemoryBufferRef m, StringRef archiveName,
+ uint64_t offsetInArchive, bool lazy)
+ : IRFile(ctx, m, archiveName, offsetInArchive, lazy) {};
+ static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
+ void parse() override;
+ void postParse() override;
std::vector<bool> keptComdats;
};
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 8d4a6c9e3a81e..dde63aa754975 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -26,6 +26,8 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include <cstddef>
+#include <cstring>
+#include <dlfcn.h>
#include <memory>
#include <string>
#include <system_error>
@@ -165,7 +167,7 @@ static lto::Config createConfig(Ctx &ctx) {
return c;
}
-BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) {
+BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : IRCompiler(ctx) {
// Initialize indexFile.
if (!ctx.arg.thinLTOIndexOnlyArg.empty())
indexFile = openFile(ctx.arg.thinLTOIndexOnlyArg);
@@ -215,9 +217,7 @@ BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) {
}
}
-BitcodeCompiler::~BitcodeCompiler() = default;
-
-void BitcodeCompiler::add(BitcodeFile &f) {
+void IRCompiler::add(IRFile &f) {
lto::InputFile &obj = *f.obj;
bool isExec = !ctx.arg.shared && !ctx.arg.relocatable;
@@ -278,7 +278,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// their values are still not final.
r.LinkerRedefined = sym->scriptDefined;
}
- checkError(ctx.e, ltoObj->add(std::move(f.obj), resols));
+ addObject(f, resols);
}
// If LazyObjFile has not been added to link, emit empty index files.
@@ -421,3 +421,239 @@ SmallVector<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {
}
return ret;
}
+
+void BitcodeCompiler::addObject(IRFile &f,
+ std::vector<llvm::lto::SymbolResolution> &r) {
+ checkError(ctx.e, ltoObj->add(std::move(f.obj), r));
+}
+
+#if LLD_ENABLE_GNU_LTO
+GccIRCompiler *GccIRCompiler::singleton = nullptr;
+
+ GccIRCompiler *GccIRCompiler::getInstance() {
+ assert(singleton != nullptr);
+ return singleton;
+}
+
+GccIRCompiler *GccIRCompiler::getInstance(Ctx &ctx) {
+ if (singleton == nullptr) {
+ singleton = new GccIRCompiler(ctx);
+ singleton->loadPlugin();
+ }
+
+ return singleton;
+}
+
+GccIRCompiler::GccIRCompiler(Ctx &ctx) : IRCompiler(ctx) {
+ singleton = nullptr;
+
+ // TODO: Properly find the right size.
+ int tvsz = 100;
+ tv = new ld_plugin_tv[tvsz];
+ initializeTv();
+}
+
+GccIRCompiler::~GccIRCompiler() {
+ singleton = nullptr;
+ delete[] tv;
+}
+
+void GccIRCompiler::loadPlugin() {
+ plugin = dlopen(ctx.arg.plugin.data(), RTLD_NOW);
+ if (plugin == NULL) {
+ error(dlerror());
+ return;
+ }
+ void *tmp = dlsym(plugin, "onload");
+ if (tmp == NULL) {
+ error("Plugin does not provide onload()");
+ return;
+ }
+
+ ld_plugin_onload onload;
+ // Ensure source and destination types have the same size.
+ assert(sizeof(ld_plugin_onload) == sizeof(void *));
+ std::memcpy(&onload, &tmp, sizeof(ld_plugin_onload));
+
+ (*onload)(tv);
+}
+
+enum ld_plugin_status regClaimFile(ld_plugin_claim_file_handler handler) {
+ GccIRCompiler *c = GccIRCompiler::getInstance();
+ return c->registerClaimFile(handler);
+}
+
+enum ld_plugin_status
+GccIRCompiler::registerClaimFile(ld_plugin_claim_file_handler handler) {
+ claimFileHandler = handler;
+ return LDPS_OK;
+}
+
+#if HAVE_LDPT_REGISTER_CLAIM_FILE_HOOK_V2
+enum ld_plugin_status regClaimFileV2(ld_plugin_claim_file_handler handler) {
+ GccIRCompiler *c = GccIRCompiler::getInstance();
+ return c->registerClaimFileV2(handler);
+}
+
+enum ld_plugin_status
+GccIRCompiler::registerClaimFileV2(ld_plugin_claim_file_handler_v2 handler) {
+ claimFileHandlerV2 = handler;
+ return LDPS_OK;
+}
+#endif
+
+enum ld_plugin_status regAllSymbolsRead(ld_plugin_all_symbols_read_handler handler) {
+ GccIRCompiler *c = GccIRCompiler::getInstance();
+ return c->registerAllSymbolsRead(handler);
+}
+
+enum ld_plugin_status
+GccIRCompiler::registerAllSymbolsRead(ld_plugin_all_symbols_read_handler handler) {
+ allSymbolsReadHandler = handler;
+ return LDPS_OK;
+}
+
+static enum ld_plugin_status addSymbols(void *handle, int nsyms,
+ const struct ld_plugin_symbol *syms) {
+ ELFFileBase *f = (ELFFileBase *) handle;
+ if(f == NULL)
+ return LDPS_ERR;
+
+ for (int i = 0; i < nsyms; i++) {
+ // TODO: Add symbols.
+ // TODO: Convert these symbosl into ArrayRef<lto::InputFile::Symbol> and
+ // ArrayRef<Symbol *> ?
+ }
+
+ return LDPS_OK;
+}
+
+static enum ld_plugin_status getSymbols(const void *handle, int nsyms,
+ struct ld_plugin_symbol *syms) {
+ for (int i = 0; i < nsyms; i++) {
+ syms[i].resolution = LDPR_UNDEF;
+ // TODO: Implement other scenarios.
+ }
+ return LDPS_OK;
+}
+
+ld_plugin_status addInputFile(const char *pathname) {
+ GccIRCompiler *c = GccIRCompiler::getInstance();
+
+ if (c->addCompiledFile(StringRef(pathname)))
+ return LDPS_OK;
+ else
+ return LDPS_ERR;
+}
+
+void GccIRCompiler::initializeTv() {
+ int i = 0;
+
+#define TVU_SETTAG(t, f, v) \
+ { \
+ tv[i].tv_tag = t; \
+ tv[i].tv_u.tv_##f = v; \
+ i++; \
+ }
+
+ TVU_SETTAG(LDPT_MESSAGE, message, message);
+ TVU_SETTAG(LDPT_API_VERSION, val, LD_PLUGIN_API_VERSION);
+ for (std::string &s : ctx.arg.pluginOpt) {
+ TVU_SETTAG(LDPT_OPTION, string, s.c_str());
+ }
+ ld_plugin_output_file_type o;
+ if (ctx.arg.pie)
+ o = LDPO_PIE;
+ else if (ctx.arg.relocatable)
+ o = LDPO_REL;
+ else if (ctx.arg.shared)
+ o = LDPO_DYN;
+ else
+ o = LDPO_EXEC;
+ TVU_SETTAG(LDPT_LINKER_OUTPUT, val, o);
+ TVU_SETTAG(LDPT_OUTPUT_NAME, string, ctx.arg.outputFile.data());
+ // Share the address of a C wrapper that is API-compatible with
+ // plugin-api.h.
+ TVU_SETTAG(LDPT_REGISTER_CLAIM_FILE_HOOK, register_claim_file, regClaimFile);
+#if HAVE_LDPT_REGISTER_CLAIM_FILE_HOOK_V2
+ TVU_SETTAG(LDPT_REGISTER_CLAIM_FILE_HOOK_V2, register_claim_file_v2,
+ regClaimFileV2);
+#endif
+
+ TVU_SETTAG(LDPT_ADD_SYMBOLS, add_symbols, addSymbols);
+ TVU_SETTAG(LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK, register_all_symbols_read,
+ regAllSymbolsRead);
+ TVU_SETTAG(LDPT_GET_SYMBOLS, get_symbols, getSymbols);
+ TVU_SETTAG(LDPT_ADD_INPUT_FILE, add_input_file, addInputFile);
+}
+
+void GccIRCompiler::add(ELFFileBase &f) {
+ struct ld_plugin_input_file file;
+
+ std::string name = f.getName().str();
+ file.name = f.getName().data();
+ file.handle = const_cast<void *>(reinterpret_cast<const void *>(&f));
+
+ std::error_code ec = sys::fs::openFileForRead(name, file.fd);
+ if (ec) {
+ error("Cannot open file " + name + ": " + ec.message());
+ return;
+ }
+ file.offset = 0;
+ uint64_t size;
+ ec = sys::fs::file_size(name, size);
+ if (ec) {
+ error("Cannot get the size of file " + name + ": " + ec.message());
+ sys::fs::closeFile(file.fd);
+ return;
+ }
+ if (size > 0 && size <= INT_MAX)
+ file.filesize = size;
+
+ int claimed;
+#if HAVE_LDPT_REGISTER_CLAIM_FILE_HOOK_V2
+ ld_plugin_status status = claimFileHandler(&file, &claimed, 1);
+#else
+ ld_plugin_status status = claimFileHandler(&file, &claimed);
+#endif
+
+ if (status != LDPS_OK)
+ error("liblto returned " + std::to_string(status));
+
+ ec = sys::fs::closeFile(file.fd);
+ if (ec) {
+ error(ec.message());
+ }
+}
+
+SmallVector<std::unique_ptr<InputFile>, 0> GccIRCompiler::compile() {
+ SmallVector<std::unique_ptr<InputFile>, 0> ret;
+ ld_plugin_status status = allSymbolsReadHandler();
+ if (status != LDPS_OK)
+ error("The plugin returned an error after all symbols were read.");
+
+ for (auto& m : files) {
+ ret.push_back(createObjFile(ctx, m->getMemBufferRef()));
+ }
+ return ret;
+}
+
+void GccIRCompiler::addObject(IRFile &f,
+ std::vector<llvm::lto::SymbolResolution> &r) {
+ // TODO: Implement this.
+}
+
+enum ld_plugin_status GccIRCompiler::message(int level, const char *format,
+ ...) {
+ // TODO: Implement this function.
+ return LDPS_OK;
+}
+
+bool GccIRCompiler::addCompiledFile(StringRef path) {
+ std::optional<MemoryBufferRef> mbref = readFile(ctx, path);
+ if (!mbref)
+ return false;
+ files.push_back(std::move(MemoryBuffer::getMemBuffer(*mbref)));
+ return true;
+}
+#endif
diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h
index acf3bcff7f2f1..3dac2eddfd532 100644
--- a/lld/ELF/LTO.h
+++ b/lld/ELF/LTO.h
@@ -21,40 +21,103 @@
#define LLD_ELF_LTO_H
#include "lld/Common/LLVM.h"
+#include "lld/config.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <plugin-api.h>
#include <vector>
namespace llvm::lto {
class LTO;
+class SymbolResolution;
}
namespace lld::elf {
struct Ctx;
class BitcodeFile;
+class ELFFileBase;
class InputFile;
+class IRFile;
+class BinaryFile;
+
+class IRCompiler {
+protected:
+ Ctx &ctx;
+ llvm::DenseSet<StringRef> thinIndices;
+ llvm::DenseSet<StringRef> usedStartStop;
+ virtual void addObject(IRFile &f,
+ std::vector<llvm::lto::SymbolResolution> &r) = 0;
+
+public:
+ IRCompiler(Ctx &ctx) : ctx(ctx) {}
+ void add(IRFile &f);
+ virtual SmallVector<std::unique_ptr<InputFile>, 0> compile() = 0;
+};
+
+class BitcodeCompiler : public IRCompiler {
+protected:
+ void addObject(IRFile &f,
+ std::vector<llvm::lto::SymbolResolution> &r) override;
-class BitcodeCompiler {
public:
BitcodeCompiler(Ctx &ctx);
~BitcodeCompiler();
- void add(BitcodeFile &f);
- SmallVector<std::unique_ptr<InputFile>, 0> compile();
+ void add(BinaryFile &f);
+ SmallVector<std::unique_ptr<InputFile>, 0> compile() override;
private:
- Ctx &ctx;
std::unique_ptr<llvm::lto::LTO> ltoObj;
// An array of (module name, native relocatable file content) pairs.
SmallVector<std::pair<std::string, SmallString<0>>, 0> buf;
std::vector<std::unique_ptr<MemoryBuffer>> files;
SmallVector<std::string, 0> filenames;
- llvm::DenseSet<StringRef> usedStartStop;
std::unique_ptr<llvm::raw_fd_ostream> indexFile;
- llvm::DenseSet<StringRef> thinIndices;
};
+
+#if LLD_ENABLE_GNU_LTO
+class GccIRCompiler : public IRCompiler {
+protected:
+ void addObject(IR...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/157175
More information about the llvm-commits
mailing list