diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1559,7 +1559,7 @@ return; auto AddStream = [&](size_t Task) { - return std::make_unique(std::move(OS)); + return std::make_unique(std::move(OS)); }; lto::Config Conf; if (CGOpts.SaveTempsFilePrefix != "") { diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -164,7 +164,7 @@ // The /lldltocache option specifies the path to a directory in which to cache // native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. - NativeObjectCache cache; + FileCache cache; if (!config->ltoCache.empty()) cache = check(localCache("ThinLTO", "Thin", config->ltoCache, @@ -174,7 +174,7 @@ checkError(ltoObj->run( [&](size_t task) { - return std::make_unique( + return std::make_unique( std::make_unique(buf[task])); }, cache)); diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -304,7 +304,7 @@ // The --thinlto-cache-dir option specifies the path to a directory in which // to cache native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. - NativeObjectCache cache; + FileCache cache; if (!config->thinLTOCacheDir.empty()) cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir, @@ -315,7 +315,7 @@ if (!bitcodeFiles.empty()) checkError(ltoObj->run( [&](size_t task) { - return std::make_unique( + return std::make_unique( std::make_unique(buf[task])); }, cache)); diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -105,7 +105,7 @@ // The -cache_path_lto option specifies the path to a directory in which // to cache native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. - NativeObjectCache cache; + FileCache cache; if (!config->thinLTOCacheDir.empty()) cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir, @@ -115,7 +115,7 @@ checkError(ltoObj->run( [&](size_t task) { - return std::make_unique( + return std::make_unique( std::make_unique(buf[task])); }, cache)); diff --git a/lld/wasm/LTO.cpp b/lld/wasm/LTO.cpp --- a/lld/wasm/LTO.cpp +++ b/lld/wasm/LTO.cpp @@ -127,7 +127,7 @@ // The --thinlto-cache-dir option specifies the path to a directory in which // to cache native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. - NativeObjectCache cache; + FileCache cache; if (!config->thinLTOCacheDir.empty()) cache = check(localCache("ThinLTO", "Thin", config->thinLTOCacheDir, @@ -137,7 +137,7 @@ checkError(ltoObj->run( [&](size_t task) { - return std::make_unique( + return std::make_unique( std::make_unique(buf[task])); }, cache)); diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -194,7 +194,7 @@ using ThinBackend = std::function( const Config &C, ModuleSummaryIndex &CombinedIndex, StringMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, NativeObjectCache Cache)>; + AddStreamFn AddStream, FileCache Cache)>; /// This ThinBackend runs the individual backend jobs in-process. /// The default value means to use one job per hardware core (not hyper-thread). @@ -267,7 +267,7 @@ /// /// The client will receive at most one callback (via either AddStream or /// Cache) for each task identifier. - Error run(AddStreamFn AddStream, NativeObjectCache Cache = nullptr); + Error run(AddStreamFn AddStream, FileCache Cache = nullptr); /// Static method that returns a list of libcall symbols that can be generated /// by LTO but might not be visible from bitcode symbol table. @@ -399,7 +399,7 @@ const SymbolResolution *&ResI, const SymbolResolution *ResE); Error runRegularLTO(AddStreamFn AddStream); - Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, + Error runThinLTO(AddStreamFn AddStream, FileCache Cache, const DenseSet &GUIDPreservedSymbols); Error checkPartiallySplit(); diff --git a/llvm/include/llvm/Support/Caching.h b/llvm/include/llvm/Support/Caching.h --- a/llvm/include/llvm/Support/Caching.h +++ b/llvm/include/llvm/Support/Caching.h @@ -1,4 +1,4 @@ -//===- Caching.h - LLVM File Cache Handling Configuration -------*- C++ -*-===// +//===- Caching.h - LLVM Local File Cache ------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,9 @@ // //===----------------------------------------------------------------------===// // -// This file defines the localCache function, which allows clients to add a -// filesystem cache. This is used by ThinLTO. +// This file defines the CachedFileStream and the localCache function, which +// simplifies caching files on the local filesystem in a directory whose +// contents are managed by a CachePruningPolicy. // //===----------------------------------------------------------------------===// @@ -15,48 +16,43 @@ #define LLVM_SUPPORT_CACHING_H #include "llvm/Support/Error.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/thread.h" namespace llvm { -/// This class wraps an output stream for a native object. Most clients should -/// just be able to return an instance of this base class from the stream -/// callback, but if a client needs to perform some action after the stream is -/// written to, that can be done by deriving from this class and overriding the -/// destructor. -class NativeObjectStream { +class MemoryBuffer; + +/// This class wraps an output stream for a file. Most clients should just be +/// able to return an instance of this base class from the stream callback, but +/// if a client needs to perform some action after the stream is written to, +/// that can be done by deriving from this class and overriding the destructor. +class CachedFileStream { public: - NativeObjectStream(std::unique_ptr OS) - : OS(std::move(OS)) {} + CachedFileStream(std::unique_ptr OS) : OS(std::move(OS)) {} std::unique_ptr OS; - virtual ~NativeObjectStream() = default; + virtual ~CachedFileStream() = default; }; -/// This type defines the callback to add a native object that is generated on -/// the fly. +/// This type defines the callback to add a file that is generated on the fly. /// /// Stream callbacks must be thread safe. using AddStreamFn = - std::function(unsigned Task)>; + std::function>(unsigned Task)>; -/// This is the type of a native object cache. To request an item from the -/// cache, pass a unique string as the Key. For hits, the cached file will be -/// added to the link and this function will return AddStreamFn(). For misses, -/// the cache will return a stream callback which must be called at most once to -/// produce content for the stream. The native object stream produced by the -/// stream callback will add the file to the link after the stream is written -/// to. +/// This is the type of a file cache. To request an item from the cache, pass a +/// unique string as the Key. For hits, the cached file will be added to the +/// link and this function will return AddStreamFn(). For misses, the cache will +/// return a stream callback which must be called at most once to produce +/// content for the stream. The file stream produced by the stream callback will +/// add the file to the link after the stream is written to. /// /// Clients generally look like this: /// /// if (AddStreamFn AddStream = Cache(Task, Key)) /// ProduceContent(AddStream); -using NativeObjectCache = - std::function; +using FileCache = + std::function(unsigned Task, StringRef Key)>; -/// This type defines the callback to add a pre-existing native object file -/// (e.g. in a cache). +/// This type defines the callback to add a pre-existing file (e.g. in a cache). /// /// Buffer callbacks must be thread safe. using AddBufferFn = @@ -67,10 +63,9 @@ /// the cache directory if it does not already exist. The cache name appears in /// error messages for errors during caching. The temporary file prefix is used /// in the temporary file naming scheme used when writing files atomically. -Expected localCache(Twine CacheNameRef, - Twine TempFilePrefixRef, - Twine CacheDirectoryPathRef, - AddBufferFn AddBuffer); +Expected localCache(Twine CacheNameRef, Twine TempFilePrefixRef, + Twine CacheDirectoryPathRef, + AddBufferFn AddBuffer); } // namespace llvm #endif diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -997,7 +997,7 @@ return Error::success(); } -Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { +Error LTO::run(AddStreamFn AddStream, FileCache Cache) { // Compute "dead" symbols, we don't want to import/export these! DenseSet GUIDPreservedSymbols; DenseMap GUIDPrevailingResolutions; @@ -1183,7 +1183,7 @@ class InProcessThinBackend : public ThinBackendProc { ThreadPool BackendThreadPool; AddStreamFn AddStream; - NativeObjectCache Cache; + FileCache Cache; std::set CfiFunctionDefs; std::set CfiFunctionDecls; @@ -1195,7 +1195,7 @@ const Config &Conf, ModuleSummaryIndex &CombinedIndex, ThreadPoolStrategy ThinLTOParallelism, const StringMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, NativeObjectCache Cache) + AddStreamFn AddStream, FileCache Cache) : ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries), BackendThreadPool(ThinLTOParallelism), AddStream(std::move(AddStream)), Cache(std::move(Cache)) { @@ -1208,8 +1208,8 @@ } Error runThinLTOBackendThread( - AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task, - BitcodeModule BM, ModuleSummaryIndex &CombinedIndex, + AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM, + ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, @@ -1239,7 +1239,11 @@ computeLTOCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls); - if (AddStreamFn CacheAddStream = Cache(Task, Key)) + Expected CacheAddStreamOrErr = Cache(Task, Key); + if (Error Err = CacheAddStreamOrErr.takeError()) + return Err; + AddStreamFn &CacheAddStream = *CacheAddStreamOrErr; + if (CacheAddStream) return RunThinBackend(CacheAddStream); return Error::success(); @@ -1301,7 +1305,7 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism) { return [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const StringMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, NativeObjectCache Cache) { + AddStreamFn AddStream, FileCache Cache) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, AddStream, Cache); @@ -1395,14 +1399,14 @@ raw_fd_ostream *LinkedObjectsFile, IndexWriteCallback OnWrite) { return [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const StringMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, NativeObjectCache Cache) { + AddStreamFn AddStream, FileCache Cache) { return std::make_unique( Conf, CombinedIndex, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix, ShouldEmitImportsFiles, LinkedObjectsFile, OnWrite); }; } -Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, +Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, const DenseSet &GUIDPreservedSymbols) { timeTraceProfilerBegin("ThinLink", StringRef("")); auto TimeTraceScopeExit = llvm::make_scope_exit([]() { diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -411,7 +411,10 @@ EC.message()); } - auto Stream = AddStream(Task); + Expected> StreamOrErr = AddStream(Task); + if (Error Err = StreamOrErr.takeError()) + report_fatal_error(std::move(Err)); + std::unique_ptr &Stream = *StreamOrErr; legacy::PassManager CodeGenPasses; CodeGenPasses.add( createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex)); diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -245,7 +245,7 @@ // make unique temp output file to put generated code SmallString<128> Filename; - auto AddStream = [&](size_t Task) -> std::unique_ptr { + auto AddStream = [&](size_t Task) -> std::unique_ptr { StringRef Extension(Config.CGFileType == CGFT_AssemblyFile ? "s" : "o"); int FD; @@ -254,7 +254,7 @@ if (EC) emitError(EC.message()); - return std::make_unique( + return std::make_unique( std::make_unique(FD, true)); }; diff --git a/llvm/lib/Support/Caching.cpp b/llvm/lib/Support/Caching.cpp --- a/llvm/lib/Support/Caching.cpp +++ b/llvm/lib/Support/Caching.cpp @@ -1,4 +1,4 @@ -//===-Caching.cpp - LLVM File Cache Handling ------------------------------===// +//===-Caching.cpp - LLVM Local File Cache ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,18 +6,17 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Caching used by ThinLTO. +// This file implements the localCache function, which simplifies creating, +// adding to, and querying a local file system cache. localCache takes care of +// periodically pruning older files from the cache using a CachePruningPolicy. // //===----------------------------------------------------------------------===// #include "llvm/Support/Caching.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" #if !defined(_MSC_VER) && !defined(__MINGW32__) #include @@ -27,10 +26,10 @@ using namespace llvm; -Expected llvm::localCache(Twine CacheNameRef, - Twine TempFilePrefixRef, - Twine CacheDirectoryPathRef, - AddBufferFn AddBuffer) { +Expected llvm::localCache(Twine CacheNameRef, + Twine TempFilePrefixRef, + Twine CacheDirectoryPathRef, + AddBufferFn AddBuffer) { if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPathRef)) return errorCodeToError(EC); @@ -40,7 +39,7 @@ TempFilePrefixRef.toVector(TempFilePrefix); CacheDirectoryPathRef.toVector(CacheDirectoryPath); - return [=](unsigned Task, StringRef Key) -> AddStreamFn { + return [=](unsigned Task, StringRef Key) -> Expected { // This choice of file name allows the cache to be pruned (see pruneCache() // in include/llvm/Support/CachePruning.h). SmallString<64> EntryPath; @@ -72,12 +71,12 @@ // Since the file is probably being deleted we handle it in the same way as // if the file did not exist at all. if (EC != errc::no_such_file_or_directory && EC != errc::permission_denied) - report_fatal_error(Twine("Failed to open cache file ") + EntryPath + - ": " + EC.message() + "\n"); + return createStringError(EC, Twine("Failed to open cache file ") + + EntryPath + ": " + EC.message() + "\n"); - // This native object stream is responsible for commiting the resulting - // file to the cache and calling AddBuffer to add it to the link. - struct CacheStream : NativeObjectStream { + // This file stream is responsible for commiting the resulting file to the + // cache and calling AddBuffer to add it to the link. + struct CacheStream : CachedFileStream { AddBufferFn AddBuffer; sys::fs::TempFile TempFile; std::string EntryPath; @@ -86,11 +85,14 @@ CacheStream(std::unique_ptr OS, AddBufferFn AddBuffer, sys::fs::TempFile TempFile, std::string EntryPath, unsigned Task) - : NativeObjectStream(std::move(OS)), AddBuffer(std::move(AddBuffer)), + : CachedFileStream(std::move(OS)), AddBuffer(std::move(AddBuffer)), TempFile(std::move(TempFile)), EntryPath(std::move(EntryPath)), Task(Task) {} ~CacheStream() { + // TODO: Manually commit rather than using non-trivial destructor, + // allowing to replace report_fatal_errors with a return Error. + // Make sure the stream is closed before committing it. OS.reset(); @@ -138,17 +140,17 @@ } }; - return [=](size_t Task) -> std::unique_ptr { + return [=](size_t Task) -> Expected> { // Write to a temporary to avoid race condition SmallString<64> TempFilenameModel; sys::path::append(TempFilenameModel, CacheDirectoryPath, TempFilePrefix + "-%%%%%%.tmp.o"); Expected Temp = sys::fs::TempFile::create( TempFilenameModel, sys::fs::owner_read | sys::fs::owner_write); - if (!Temp) { - errs() << "Error: " << toString(Temp.takeError()) << "\n"; - report_fatal_error(CacheName + ": Can't get a temporary file"); - } + if (!Temp) + return createStringError(errc::io_error, + toString(Temp.takeError()) + ": " + CacheName + + ": Can't get a temporary file"); // This CacheStream will move the temporary file into the cache when done. return std::make_unique( diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -1081,11 +1081,11 @@ size_t MaxTasks = Lto->getMaxTasks(); std::vector, bool>> Files(MaxTasks); - auto AddStream = [&](size_t Task) -> std::unique_ptr { + auto AddStream = [&](size_t Task) -> std::unique_ptr { Files[Task].second = !SaveTemps; int FD = getOutputFileName(Filename, /* TempOutFile */ !SaveTemps, Files[Task].first, Task); - return std::make_unique( + return std::make_unique( std::make_unique(FD, true)); }; @@ -1093,7 +1093,7 @@ *AddStream(Task)->OS << MB->getBuffer(); }; - NativeObjectCache Cache; + FileCache Cache; if (!options::cache_dir.empty()) Cache = check(localCache("ThinLTO", "Thin", options::cache_dir, AddBuffer)); diff --git a/llvm/tools/llvm-lto/llvm-lto.cpp b/llvm/tools/llvm-lto/llvm-lto.cpp --- a/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/llvm/tools/llvm-lto/llvm-lto.cpp @@ -1097,7 +1097,7 @@ error("writing merged module failed."); } - auto AddStream = [&](size_t Task) -> std::unique_ptr { + auto AddStream = [&](size_t Task) -> std::unique_ptr { std::string PartFilename = OutputFilename; if (Parallelism != 1) PartFilename += "." + utostr(Task); @@ -1107,7 +1107,7 @@ std::make_unique(PartFilename, EC, sys::fs::OF_None); if (EC) error("error opening the file '" + PartFilename + "': " + EC.message()); - return std::make_unique(std::move(S)); + return std::make_unique(std::move(S)); }; if (!CodeGen.compileOptimized(AddStream, Parallelism)) diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -362,20 +362,20 @@ if (HasErrors) return 1; - auto AddStream = [&](size_t Task) -> std::unique_ptr { + auto AddStream = [&](size_t Task) -> std::unique_ptr { std::string Path = OutputFilename + "." + utostr(Task); std::error_code EC; auto S = std::make_unique(Path, EC, sys::fs::OF_None); check(EC, Path); - return std::make_unique(std::move(S)); + return std::make_unique(std::move(S)); }; auto AddBuffer = [&](size_t Task, std::unique_ptr MB) { *AddStream(Task)->OS << MB->getBuffer(); }; - NativeObjectCache Cache; + FileCache Cache; if (!CacheDir.empty()) Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer), "failed to create cache");