diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 5c47c4df7f6a387..66d8ca63a206f6a 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -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" @@ -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. @@ -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( +using IndexWriteCallback = std::function; + +/// This class defines the interface to the ThinLTO backend. +class ThinBackendProc { +protected: + const Config &Conf; + ModuleSummaryIndex &CombinedIndex; + const DenseMap &ModuleToDefinedGVSummaries; + IndexWriteCallback OnWrite; + bool ShouldEmitImportsFiles; + DefaultThreadPool BackendThreadPool; + std::optional Err; + std::mutex ErrMu; + +public: + ThinBackendProc( + const Config &Conf, ModuleSummaryIndex &CombinedIndex, + const DenseMap &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 &ResolvedODR, + MapVector &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( const Config &C, ModuleSummaryIndex &CombinedIndex, - DenseMap &ModuleToDefinedGVSummaries, + const DenseMap &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 operator()( + const Config &Conf, ModuleSummaryIndex &CombinedIndex, + const DenseMap &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(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 @@ -210,7 +286,6 @@ using ThinBackend = std::function( /// 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; ThinBackend createInProcessThinBackend(ThreadPoolStrategy Parallelism, IndexWriteCallback OnWrite = nullptr, bool ShouldEmitIndexFiles = false, @@ -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(); diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index ccf1139c0373532..e1714b29399298a 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -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()); } @@ -1368,75 +1368,33 @@ SmallVector 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 &ModuleToDefinedGVSummaries; - lto::IndexWriteCallback OnWrite; - bool ShouldEmitImportsFiles; - DefaultThreadPool BackendThreadPool; - std::optional 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 &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 &ResolvedODR, - MapVector &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 { @@ -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 &ModuleToDefinedGVSummaries, AddStreamFn AddStream, FileCache Cache) { @@ -1570,6 +1528,7 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism, AddStream, Cache, OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles); }; + return ThinBackend(Func, Parallelism); } StringLiteral lto::getThinLTODefaultCPU(const Triple &TheTriple) { @@ -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 &ModuleToDefinedGVSummaries, AddStreamFn AddStream, FileCache Cache) { @@ -1690,6 +1649,7 @@ ThinBackend lto::createWriteIndexesThinBackend( OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles, LinkedObjectsFile, OnWrite); }; + return ThinBackend(Func, Parallelism); } Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,