Skip to content

Commit

Permalink
[ThinLTO][NFC] Refactor ThinBackend (llvm#110461)
Browse files Browse the repository at this point in the history
This is a prep for llvm#90933.
 
 - Change `ThinBackend` from a function to a type.
 - Store the parallelism level in the type, which will be used when creating two-codegen round backends that inherit this value.
 - `ThinBackendProc` is hoisted to `LTO.h` from `LTO.cpp` to provide its body for `ThinBackend`. However, `emitFiles()` is still implemented separately in `LTO.cpp`, distinct from its parent class.
  • Loading branch information
kyulee-com authored Oct 8, 2024
1 parent 1ad3180 commit 1b53aae
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 81 deletions.
91 changes: 83 additions & 8 deletions llvm/include/llvm/LTO/LTO.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "llvm/Support/Caching.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/thread.h"
#include "llvm/Transforms/IPO/FunctionAttrs.h"
#include "llvm/Transforms/IPO/FunctionImport.h"
Expand Down Expand Up @@ -105,7 +106,6 @@ void updateMemProfAttributes(Module &Mod, const ModuleSummaryIndex &Index);

class LTO;
struct SymbolResolution;
class ThinBackendProc;

/// An input file. This is a symbol table wrapper that only exposes the
/// information that an LTO client should need in order to do symbol resolution.
Expand Down Expand Up @@ -194,14 +194,90 @@ class InputFile {
}
};

/// A ThinBackend defines what happens after the thin-link phase during ThinLTO.
/// The details of this type definition aren't important; clients can only
/// create a ThinBackend using one of the create*ThinBackend() functions below.
using ThinBackend = std::function<std::unique_ptr<ThinBackendProc>(
using IndexWriteCallback = std::function<void(const std::string &)>;

/// This class defines the interface to the ThinLTO backend.
class ThinBackendProc {
protected:
const Config &Conf;
ModuleSummaryIndex &CombinedIndex;
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries;
IndexWriteCallback OnWrite;
bool ShouldEmitImportsFiles;
DefaultThreadPool BackendThreadPool;
std::optional<Error> Err;
std::mutex ErrMu;

public:
ThinBackendProc(
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
lto::IndexWriteCallback OnWrite, bool ShouldEmitImportsFiles,
ThreadPoolStrategy ThinLTOParallelism)
: Conf(Conf), CombinedIndex(CombinedIndex),
ModuleToDefinedGVSummaries(ModuleToDefinedGVSummaries),
OnWrite(OnWrite), ShouldEmitImportsFiles(ShouldEmitImportsFiles),
BackendThreadPool(ThinLTOParallelism) {}

virtual ~ThinBackendProc() = default;
virtual Error start(
unsigned Task, BitcodeModule BM,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
MapVector<StringRef, BitcodeModule> &ModuleMap) = 0;
Error wait() {
BackendThreadPool.wait();
if (Err)
return std::move(*Err);
return Error::success();
}
unsigned getThreadCount() { return BackendThreadPool.getMaxConcurrency(); }
virtual bool isSensitiveToInputOrder() { return false; }

// Write sharded indices and (optionally) imports to disk
Error emitFiles(const FunctionImporter::ImportMapTy &ImportList,
llvm::StringRef ModulePath,
const std::string &NewModulePath) const;
};

/// This callable defines the behavior of a ThinLTO backend after the thin-link
/// phase. It accepts a configuration \p C, a combined module summary index
/// \p CombinedIndex, a map of module identifiers to global variable summaries
/// \p ModuleToDefinedGVSummaries, a function to add output streams \p
/// AddStream, and a file cache \p Cache. It returns a unique pointer to a
/// ThinBackendProc, which can be used to launch backends in parallel.
using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
const Config &C, ModuleSummaryIndex &CombinedIndex,
DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache)>;

/// This type defines the behavior following the thin-link phase during ThinLTO.
/// It encapsulates a backend function and a strategy for thread pool
/// parallelism. Clients should use one of the provided create*ThinBackend()
/// functions to instantiate a ThinBackend. Parallelism defines the thread pool
/// strategy to be used for processing.
struct ThinBackend {
ThinBackend(ThinBackendFunction Func, ThreadPoolStrategy Parallelism)
: Func(std::move(Func)), Parallelism(std::move(Parallelism)) {}
ThinBackend() = default;

std::unique_ptr<ThinBackendProc> operator()(
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache) {
assert(isValid() && "Invalid backend function");
return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
std::move(AddStream), std::move(Cache));
}
ThreadPoolStrategy getParallelism() const { return Parallelism; }
bool isValid() const { return static_cast<bool>(Func); }

private:
ThinBackendFunction Func = nullptr;
ThreadPoolStrategy Parallelism;
};

/// This ThinBackend runs the individual backend jobs in-process.
/// The default value means to use one job per hardware core (not hyper-thread).
/// OnWrite is callback which receives module identifier and notifies LTO user
Expand All @@ -210,7 +286,6 @@ using ThinBackend = std::function<std::unique_ptr<ThinBackendProc>(
/// to the same path as the input module, with suffix ".thinlto.bc"
/// ShouldEmitImportsFiles is true it also writes a list of imported files to a
/// similar path with ".imports" appended instead.
using IndexWriteCallback = std::function<void(const std::string &)>;
ThinBackend createInProcessThinBackend(ThreadPoolStrategy Parallelism,
IndexWriteCallback OnWrite = nullptr,
bool ShouldEmitIndexFiles = false,
Expand Down Expand Up @@ -276,7 +351,7 @@ class LTO {
/// this constructor.
/// FIXME: We do currently require the DiagHandler field to be set in Conf.
/// Until that is fixed, a Config argument is required.
LTO(Config Conf, ThinBackend Backend = nullptr,
LTO(Config Conf, ThinBackend Backend = {},
unsigned ParallelCodeGenParallelismLevel = 1,
LTOKind LTOMode = LTOK_Default);
~LTO();
Expand Down
106 changes: 33 additions & 73 deletions llvm/lib/LTO/LTO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,10 +578,10 @@ LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel,
CombinedModule->IsNewDbgInfoFormat = UseNewDbgInfoFormat;
}

LTO::ThinLTOState::ThinLTOState(ThinBackend Backend)
: Backend(Backend), CombinedIndex(/*HaveGVs*/ false) {
if (!Backend)
this->Backend =
LTO::ThinLTOState::ThinLTOState(ThinBackend BackendParam)
: Backend(std::move(BackendParam)), CombinedIndex(/*HaveGVs*/ false) {
if (!Backend.isValid())
Backend =
createInProcessThinBackend(llvm::heavyweight_hardware_concurrency());
}

Expand Down Expand Up @@ -1368,75 +1368,33 @@ SmallVector<const char *> LTO::getRuntimeLibcallSymbols(const Triple &TT) {
return LibcallSymbols;
}

/// This class defines the interface to the ThinLTO backend.
class lto::ThinBackendProc {
protected:
const Config &Conf;
ModuleSummaryIndex &CombinedIndex;
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries;
lto::IndexWriteCallback OnWrite;
bool ShouldEmitImportsFiles;
DefaultThreadPool BackendThreadPool;
std::optional<Error> Err;
std::mutex ErrMu;
Error ThinBackendProc::emitFiles(
const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath,
const std::string &NewModulePath) const {
ModuleToSummariesForIndexTy ModuleToSummariesForIndex;
GVSummaryPtrSet DeclarationSummaries;

public:
ThinBackendProc(
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
lto::IndexWriteCallback OnWrite, bool ShouldEmitImportsFiles,
ThreadPoolStrategy ThinLTOParallelism)
: Conf(Conf), CombinedIndex(CombinedIndex),
ModuleToDefinedGVSummaries(ModuleToDefinedGVSummaries),
OnWrite(OnWrite), ShouldEmitImportsFiles(ShouldEmitImportsFiles),
BackendThreadPool(ThinLTOParallelism) {}

virtual ~ThinBackendProc() = default;
virtual Error start(
unsigned Task, BitcodeModule BM,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
MapVector<StringRef, BitcodeModule> &ModuleMap) = 0;
Error wait() {
BackendThreadPool.wait();
if (Err)
return std::move(*Err);
return Error::success();
}
unsigned getThreadCount() { return BackendThreadPool.getMaxConcurrency(); }
virtual bool isSensitiveToInputOrder() { return false; }

// Write sharded indices and (optionally) imports to disk
Error emitFiles(const FunctionImporter::ImportMapTy &ImportList,
llvm::StringRef ModulePath,
const std::string &NewModulePath) const {
ModuleToSummariesForIndexTy ModuleToSummariesForIndex;
GVSummaryPtrSet DeclarationSummaries;

std::error_code EC;
gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries,
ImportList, ModuleToSummariesForIndex,
DeclarationSummaries);

raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC,
sys::fs::OpenFlags::OF_None);
if (EC)
return createFileError("cannot open " + NewModulePath + ".thinlto.bc",
EC);

writeIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex,
&DeclarationSummaries);

if (ShouldEmitImportsFiles) {
Error ImportFilesError = EmitImportsFiles(
ModulePath, NewModulePath + ".imports", ModuleToSummariesForIndex);
if (ImportFilesError)
return ImportFilesError;
}
return Error::success();
std::error_code EC;
gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries,
ImportList, ModuleToSummariesForIndex,
DeclarationSummaries);

raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC,
sys::fs::OpenFlags::OF_None);
if (EC)
return createFileError("cannot open " + NewModulePath + ".thinlto.bc", EC);

writeIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex,
&DeclarationSummaries);

if (ShouldEmitImportsFiles) {
Error ImportFilesError = EmitImportsFiles(
ModulePath, NewModulePath + ".imports", ModuleToSummariesForIndex);
if (ImportFilesError)
return ImportFilesError;
}
};
return Error::success();
}

namespace {
class InProcessThinBackend : public ThinBackendProc {
Expand Down Expand Up @@ -1561,7 +1519,7 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
lto::IndexWriteCallback OnWrite,
bool ShouldEmitIndexFiles,
bool ShouldEmitImportsFiles) {
return
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache) {
Expand All @@ -1570,6 +1528,7 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
ShouldEmitImportsFiles);
};
return ThinBackend(Func, Parallelism);
}

StringLiteral lto::getThinLTODefaultCPU(const Triple &TheTriple) {
Expand Down Expand Up @@ -1681,7 +1640,7 @@ ThinBackend lto::createWriteIndexesThinBackend(
std::string NewPrefix, std::string NativeObjectPrefix,
bool ShouldEmitImportsFiles, raw_fd_ostream *LinkedObjectsFile,
IndexWriteCallback OnWrite) {
return
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache) {
Expand All @@ -1690,6 +1649,7 @@ ThinBackend lto::createWriteIndexesThinBackend(
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
LinkedObjectsFile, OnWrite);
};
return ThinBackend(Func, Parallelism);
}

Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
Expand Down

0 comments on commit 1b53aae

Please sign in to comment.