//
//===----------------------------------------------------------------------===//
//
-// This file defines the lto::CacheObjectOutput data structure, which allows
-// clients to add a filesystem cache to ThinLTO
+// This file defines the localCache function, which allows clients to add a
+// filesystem cache to ThinLTO.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LTO_CACHING_H
#define LLVM_LTO_CACHING_H
-#include "llvm/ADT/SmallString.h"
-#include "llvm/LTO/Config.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/LTO/LTO.h"
+#include <string>
namespace llvm {
namespace lto {
-/// Type for client-supplied callback when a buffer is loaded from the cache.
-typedef std::function<void(std::string)> AddBufferFn;
-/// Manage caching on the filesystem.
+/// This type defines the callback to add a pre-existing native object file
+/// (e.g. in a cache).
///
-/// The general scheme is the following:
-///
-/// void do_stuff(AddBufferFn CallBack) {
-/// /* ... */
-/// {
-/// /* Create the CacheObjectOutput pointing to a cache directory */
-/// auto Output = CacheObjectOutput("/tmp/cache", CallBack)
-///
-/// /* Call some processing function */
-/// process(Output);
-///
-/// } /* Callback is only called now, on destruction of the Output object */
-/// /* ... */
-/// }
-///
-///
-/// void process(NativeObjectOutput &Output) {
-/// /* check if caching is supported */
-/// if (Output.isCachingEnabled()) {
-/// auto Key = ComputeKeyForEntry(...); // "expensive" call
-/// if (Output.tryLoadFromCache())
-/// return; // Cache hit
-/// }
-///
-/// auto OS = Output.getStream();
-///
-/// OS << ...;
-/// /* Note that the callback is not called here, but only when the caller
-/// destroys Output */
-/// }
-///
-class CacheObjectOutput : public NativeObjectOutput {
- /// Path to the on-disk cache directory
- StringRef CacheDirectoryPath;
- /// Path to this entry in the cache, initialized by tryLoadFromCache().
- SmallString<128> EntryPath;
- /// Path to temporary file used to buffer output that will be committed to the
- /// cache entry when this object is destroyed
- SmallString<128> TempFilename;
- /// User-supplied callback, used to provide path to cache entry
- /// (potentially after creating it).
- AddBufferFn AddBuffer;
-
-public:
- /// The destructor pulls the entry from the cache and calls the AddBuffer
- /// callback, after committing the entry into the cache on miss.
- ~CacheObjectOutput();
-
- /// Create a CacheObjectOutput: the client is supposed to create it in the
- /// callback supplied to LTO::run. The \p CacheDirectoryPath points to the
- /// directory on disk where to store the cache, and \p AddBuffer will be
- /// called when the buffer is ready to be pulled out of the cache
- /// (potentially after creating it).
- CacheObjectOutput(StringRef CacheDirectoryPath, AddBufferFn AddBuffer)
- : CacheDirectoryPath(CacheDirectoryPath), AddBuffer(AddBuffer) {}
-
- /// Return an allocated stream for the output, or null in case of failure.
- std::unique_ptr<raw_pwrite_stream> getStream() override;
-
- /// Set EntryPath, try loading from a possible cache first, return true on
- /// cache hit.
- bool tryLoadFromCache(StringRef Key) override;
+/// File callbacks must be thread safe.
+typedef std::function<void(unsigned Task, StringRef Path)> AddFileFn;
- /// Returns true to signal that this implementation of NativeObjectFile
- /// support caching.
- bool isCachingEnabled() const override { return true; }
-};
+/// Create a local file system cache which uses the given cache directory and
+/// file callback.
+NativeObjectCache localCache(std::string CacheDirectoryPath, AddFileFn AddFile);
} // namespace lto
} // namespace llvm
namespace lto {
-/// Abstract class representing a single Task output to be implemented by the
-/// client of the LTO API.
-///
-/// The general scheme the API is called is the following:
-///
-/// void process(NativeObjectOutput &Output) {
-/// /* check if caching is supported */
-/// if (Output.isCachingEnabled()) {
-/// auto Key = ComputeKeyForEntry(...); // "expensive" call
-/// if (Output.tryLoadFromCache())
-/// return; // Cache hit
-/// }
-///
-/// auto OS = Output.getStream();
-///
-/// OS << ....;
-/// }
-///
-class NativeObjectOutput {
-public:
- // Return an allocated stream for the output, or null in case of failure.
- virtual std::unique_ptr<raw_pwrite_stream> getStream() = 0;
-
- // Try loading from a possible cache first, return true on cache hit.
- virtual bool tryLoadFromCache(StringRef Key) { return false; }
-
- // Returns true if a cache is available
- virtual bool isCachingEnabled() const { return false; }
-
- virtual ~NativeObjectOutput() = default;
-};
-
/// LTO configuration. A linker can configure LTO by setting fields in this data
/// structure and passing it to the lto::LTO constructor.
struct Config {
bool UseInputModulePath = false);
};
-/// This type defines the callback to add a native object that is generated on
-/// the fly.
-///
-/// Output callbacks must be thread safe.
-typedef std::function<std::unique_ptr<NativeObjectOutput>(unsigned Task)>
- AddOutputFn;
-
/// A derived class of LLVMContext that initializes itself according to a given
/// Config object. The purpose of this class is to tie ownership of the
/// diagnostic handler to the context, as opposed to the Config object (which
}
};
+/// 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 {
+public:
+ NativeObjectStream(std::unique_ptr<raw_pwrite_stream> OS) : OS(std::move(OS)) {}
+ std::unique_ptr<raw_pwrite_stream> OS;
+ virtual ~NativeObjectStream() = default;
+};
+
+/// This type defines the callback to add a native object that is generated on
+/// the fly.
+///
+/// Stream callbacks must be thread safe.
+typedef std::function<std::unique_ptr<NativeObjectStream>(unsigned Task)>
+ AddStreamFn;
+
+/// 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.
+///
+/// Clients generally look like this:
+///
+/// if (AddStreamFn AddStream = Cache(Task, Key))
+/// ProduceContent(AddStream);
+typedef std::function<AddStreamFn(unsigned Task, StringRef Key)>
+ NativeObjectCache;
+
/// 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.
typedef std::function<std::unique_ptr<ThinBackendProc>(
Config &C, ModuleSummaryIndex &CombinedIndex,
StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddOutputFn AddOutput)>
+ AddStreamFn AddStream, NativeObjectCache Cache)>
ThinBackend;
/// This ThinBackend runs the individual backend jobs in-process.
/// and pass it and an array of symbol resolutions to the add() function.
/// - Call the getMaxTasks() function to get an upper bound on the number of
/// native object files that LTO may add to the link.
-/// - Call the run() function. This function will use the supplied AddOutput
-/// function to add up to getMaxTasks() native object files to the link.
+/// - Call the run() function. This function will use the supplied AddStream
+/// and Cache functions to add up to getMaxTasks() native object files to
+/// the link.
class LTO {
friend InputFile;
/// full description of tasks see LTOBackend.h.
unsigned getMaxTasks() const;
- /// Runs the LTO pipeline. This function calls the supplied AddOutput function
- /// to add native object files to the link.
- Error run(AddOutputFn AddOutput);
+ /// Runs the LTO pipeline. This function calls the supplied AddStream
+ /// function to add native object files to the link.
+ ///
+ /// The Cache parameter is optional. If supplied, it will be used to cache
+ /// native object files and add them to the link.
+ ///
+ /// The client will receive at most one callback (via either AddStream or
+ /// Cache) for each task identifier.
+ Error run(AddStreamFn AddStream, NativeObjectCache Cache = nullptr);
private:
Config Conf;
Error addThinLTO(std::unique_ptr<InputFile> Input,
ArrayRef<SymbolResolution> Res);
- Error runRegularLTO(AddOutputFn AddOutput);
- Error runThinLTO(AddOutputFn AddOutput, bool HasRegularLTO);
+ Error runRegularLTO(AddStreamFn AddStream);
+ Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
+ bool HasRegularLTO);
mutable bool CalledGetMaxTasks = false;
};
#include "llvm/ADT/MapVector.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/ModuleSummaryIndex.h"
-#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/IPO/FunctionImport.h"
namespace lto {
/// Runs a regular LTO backend.
-Error backend(Config &C, AddOutputFn AddStream,
+Error backend(Config &C, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel,
std::unique_ptr<Module> M);
/// Runs a ThinLTO backend.
-Error thinBackend(Config &C, unsigned Task, AddOutputFn AddStream, Module &M,
+Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
//===----------------------------------------------------------------------===//
#include "llvm/LTO/Caching.h"
-
-#ifdef HAVE_LLVM_REVISION
-#include "LLVMLTORevision.h"
-#endif
-
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
auto EC = sys::fs::rename(TempFilename, EntryPath);
if (EC) {
// Renaming failed, probably not the same filesystem, copy and delete.
+ // FIXME: Avoid needing to do this by creating the temporary file in the
+ // cache directory.
{
auto ReloadedBufferOrErr = MemoryBuffer::getFile(TempFilename);
if (auto EC = ReloadedBufferOrErr.getError())
}
}
-CacheObjectOutput::~CacheObjectOutput() {
- if (EntryPath.empty())
- // The entry was never used by the client (tryLoadFromCache() wasn't called)
- return;
- // TempFilename is only set if getStream() was called, i.e. on cache miss when
- // tryLoadFromCache() returned false. And EntryPath is valid if a Key was
- // submitted, otherwise it has been set to CacheDirectoryPath in
- // tryLoadFromCache.
- if (!TempFilename.empty()) {
- if (EntryPath == CacheDirectoryPath)
- // The Key supplied to tryLoadFromCache was empty, do not commit the temp.
- EntryPath = TempFilename;
- else
- // We commit the tempfile into the cache now, by moving it to EntryPath.
- commitEntry(TempFilename, EntryPath);
- }
- // Supply the cache path to the user.
- AddBuffer(EntryPath.str());
-}
+NativeObjectCache lto::localCache(std::string CacheDirectoryPath,
+ AddFileFn AddFile) {
+ return [=](unsigned Task, StringRef Key) -> AddStreamFn {
+ // First, see if we have a cache hit.
+ SmallString<64> EntryPath;
+ sys::path::append(EntryPath, CacheDirectoryPath, Key);
+ if (sys::fs::exists(EntryPath)) {
+ AddFile(Task, EntryPath);
+ return AddStreamFn();
+ }
-// Return an allocated stream for the output, or null in case of failure.
-std::unique_ptr<raw_pwrite_stream> CacheObjectOutput::getStream() {
- assert(!EntryPath.empty() && "API Violation: client didn't call "
- "tryLoadFromCache() before getStream()");
- // Write to a temporary to avoid race condition
- int TempFD;
- std::error_code EC =
- sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
- if (EC) {
- errs() << "Error: " << EC.message() << "\n";
- report_fatal_error("ThinLTO: Can't get a temporary file");
- }
- return llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true);
-}
+ // This native object stream is responsible for commiting the resulting
+ // file to the cache and calling AddFile to add it to the link.
+ struct CacheStream : NativeObjectStream {
+ AddFileFn AddFile;
+ std::string TempFilename;
+ std::string EntryPath;
+ unsigned Task;
-// Try loading from a possible cache first, return true on cache hit.
-bool CacheObjectOutput::tryLoadFromCache(StringRef Key) {
- assert(!CacheDirectoryPath.empty() &&
- "CacheObjectOutput was initialized without a cache path");
- if (Key.empty()) {
- // Client didn't compute a valid key. EntryPath has been set to
- // CacheDirectoryPath.
- EntryPath = CacheDirectoryPath;
- return false;
- }
- sys::path::append(EntryPath, CacheDirectoryPath, Key);
- return sys::fs::exists(EntryPath);
+ CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddFileFn AddFile,
+ std::string TempFilename, std::string EntryPath,
+ unsigned Task)
+ : NativeObjectStream(std::move(OS)), AddFile(AddFile),
+ TempFilename(TempFilename), EntryPath(EntryPath), Task(Task) {}
+
+ ~CacheStream() {
+ // Make sure the file is closed before committing it.
+ OS.reset();
+ commitEntry(TempFilename, EntryPath);
+ AddFile(Task, EntryPath);
+ }
+ };
+
+ return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> {
+ // Write to a temporary to avoid race condition
+ int TempFD;
+ SmallString<64> TempFilename;
+ std::error_code EC =
+ sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
+ if (EC) {
+ errs() << "Error: " << EC.message() << "\n";
+ report_fatal_error("ThinLTO: Can't get a temporary file");
+ }
+
+ // This CacheStream will move the temporary file into the cache when done.
+ return make_unique<CacheStream>(
+ llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true),
+ AddFile, TempFilename.str(), EntryPath.str(), Task);
+ };
+ };
}
return RegularLTO.ParallelCodeGenParallelismLevel + ThinLTO.ModuleMap.size();
}
-Error LTO::run(AddOutputFn AddOutput) {
+Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
// Save the status of having a regularLTO combined module, as
// this is needed for generating the ThinLTO Task ID, and
// the CombinedModule will be moved at the end of runRegularLTO.
bool HasRegularLTO = RegularLTO.CombinedModule != nullptr;
// Invoke regular LTO if there was a regular LTO module to start with.
if (HasRegularLTO)
- if (auto E = runRegularLTO(AddOutput))
+ if (auto E = runRegularLTO(AddStream))
return E;
- return runThinLTO(AddOutput, HasRegularLTO);
+ return runThinLTO(AddStream, Cache, HasRegularLTO);
}
-Error LTO::runRegularLTO(AddOutputFn AddOutput) {
+Error LTO::runRegularLTO(AddStreamFn AddStream) {
// Make sure commons have the right size/alignment: we kept the largest from
// all the prevailing when adding the inputs, and we apply it here.
const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout();
!Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
return Error();
}
- return backend(Conf, AddOutput, RegularLTO.ParallelCodeGenParallelismLevel,
+ return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
std::move(RegularLTO.CombinedModule));
}
class InProcessThinBackend : public ThinBackendProc {
ThreadPool BackendThreadPool;
- AddOutputFn AddOutput;
+ AddStreamFn AddStream;
+ NativeObjectCache Cache;
Optional<Error> Err;
std::mutex ErrMu;
Config &Conf, ModuleSummaryIndex &CombinedIndex,
unsigned ThinLTOParallelismLevel,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddOutputFn AddOutput)
+ AddStreamFn AddStream, NativeObjectCache Cache)
: ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries),
BackendThreadPool(ThinLTOParallelismLevel),
- AddOutput(std::move(AddOutput)) {}
+ AddStream(std::move(AddStream)), Cache(std::move(Cache)) {}
Error runThinLTOBackendThread(
- AddOutputFn AddOutput, unsigned Task, MemoryBufferRef MBRef,
- ModuleSummaryIndex &CombinedIndex,
+ AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task,
+ MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
+ auto RunThinBackend = [&](AddStreamFn AddStream) {
+ LTOLLVMContext BackendContext(Conf);
+ ErrorOr<std::unique_ptr<Module>> MOrErr =
+ parseBitcodeFile(MBRef, BackendContext);
+ assert(MOrErr && "Unable to load module in thread?");
+
+ return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
+ ImportList, DefinedGlobals, ModuleMap);
+ };
- auto ModuleIdentifier = MBRef.getBufferIdentifier();
- auto Output = AddOutput(Task);
- if (Output->isCachingEnabled()) {
- SmallString<40> Key;
- // The module may be cached, this helps handling it.
- computeCacheKey(Key, CombinedIndex, ModuleIdentifier, ImportList,
- ExportList, ResolvedODR, DefinedGlobals);
- if (Output->tryLoadFromCache(Key))
- return Error();
- }
+ if (!Cache)
+ return RunThinBackend(AddStream);
- LTOLLVMContext BackendContext(Conf);
- ErrorOr<std::unique_ptr<Module>> MOrErr =
- parseBitcodeFile(MBRef, BackendContext);
- assert(MOrErr && "Unable to load module in thread?");
+ SmallString<40> Key;
+ // The module may be cached, this helps handling it.
+ computeCacheKey(Key, CombinedIndex, MBRef.getBufferIdentifier(),
+ ImportList, ExportList, ResolvedODR, DefinedGlobals);
+ if (AddStreamFn CacheAddStream = Cache(Task, Key))
+ return RunThinBackend(CacheAddStream);
- auto AddOutputWrapper = [&](unsigned TaskId) {
- assert(Task == TaskId && "Unexpexted TaskId mismatch");
- return std::move(Output);
- };
- return thinBackend(Conf, Task, AddOutputWrapper, **MOrErr, CombinedIndex,
- ImportList, DefinedGlobals, ModuleMap);
+ return Error();
}
Error start(
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
Error E = runThinLTOBackendThread(
- AddOutput, Task, MBRef, CombinedIndex, ImportList, ExportList,
- ResolvedODR, DefinedGlobals, ModuleMap);
+ AddStream, Cache, Task, MBRef, CombinedIndex, ImportList,
+ ExportList, ResolvedODR, DefinedGlobals, ModuleMap);
if (E) {
std::unique_lock<std::mutex> L(ErrMu);
if (Err)
ThinBackend lto::createInProcessThinBackend(unsigned ParallelismLevel) {
return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddOutputFn AddOutput) {
+ AddStreamFn AddStream, NativeObjectCache Cache) {
return llvm::make_unique<InProcessThinBackend>(
Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries,
- AddOutput);
+ AddStream, Cache);
};
}
std::string LinkedObjectsFile) {
return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
- AddOutputFn AddOutput) {
+ AddStreamFn AddStream, NativeObjectCache Cache) {
return llvm::make_unique<WriteIndexesThinBackend>(
Conf, CombinedIndex, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix,
ShouldEmitImportsFiles, LinkedObjectsFile);
};
}
-Error LTO::runThinLTO(AddOutputFn AddOutput, bool HasRegularLTO) {
+Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
+ bool HasRegularLTO) {
if (ThinLTO.ModuleMap.empty())
return Error();
thinLTOResolveWeakForLinkerInIndex(ThinLTO.CombinedIndex, isPrevailing,
recordNewLinkage);
- std::unique_ptr<ThinBackendProc> BackendProc = ThinLTO.Backend(
- Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, AddOutput);
+ std::unique_ptr<ThinBackendProc> BackendProc =
+ ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
+ AddStream, Cache);
// Partition numbers for ThinLTO jobs start at 1 (see comments for
// GlobalResolution in LTO.h). Task numbers, however, start at
return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
}
-/// Monolithic LTO does not support caching (yet), this is a convenient wrapper
-/// around AddOutput to workaround this.
-static AddOutputFn getUncachedOutputWrapper(AddOutputFn &AddOutput,
- unsigned Task) {
- return [Task, &AddOutput](unsigned TaskId) {
- auto Output = AddOutput(Task);
- if (Output->isCachingEnabled() && Output->tryLoadFromCache(""))
- report_fatal_error("Cache hit without a valid key?");
- assert(Task == TaskId && "Unexpexted TaskId mismatch");
- return Output;
- };
-}
-
-void codegen(Config &Conf, TargetMachine *TM, AddOutputFn AddOutput,
+void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
unsigned Task, Module &Mod) {
if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))
return;
- auto Output = AddOutput(Task);
- std::unique_ptr<raw_pwrite_stream> OS = Output->getStream();
+ auto Stream = AddStream(Task);
legacy::PassManager CodeGenPasses;
- if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
+ if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,
TargetMachine::CGFT_ObjectFile))
report_fatal_error("Failed to setup codegen");
CodeGenPasses.run(Mod);
}
-void splitCodeGen(Config &C, TargetMachine *TM, AddOutputFn AddOutput,
+void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel,
std::unique_ptr<Module> Mod) {
ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
std::unique_ptr<TargetMachine> TM =
createTargetMachine(C, MPartInCtx->getTargetTriple(), T);
- codegen(C, TM.get(),
- getUncachedOutputWrapper(AddOutput, ThreadId), ThreadId,
- *MPartInCtx);
+ codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx);
},
// Pass BC using std::move to ensure that it get moved rather than
// copied into the thread's context.
updateCompilerUsed(Mod, TM, AsmUndefinedRefs);
}
-Error lto::backend(Config &C, AddOutputFn AddOutput,
+Error lto::backend(Config &C, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel,
std::unique_ptr<Module> Mod) {
Expected<const Target *> TOrErr = initAndLookupTarget(C, *Mod);
return Error();
if (ParallelCodeGenParallelismLevel == 1) {
- codegen(C, TM.get(), getUncachedOutputWrapper(AddOutput, 0), 0, *Mod);
+ codegen(C, TM.get(), AddStream, 0, *Mod);
} else {
- splitCodeGen(C, TM.get(), AddOutput, ParallelCodeGenParallelismLevel,
+ splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel,
std::move(Mod));
}
return Error();
}
-Error lto::thinBackend(Config &Conf, unsigned Task, AddOutputFn AddOutput,
+Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,
Module &Mod, ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
handleAsmUndefinedRefs(Mod, *TM);
if (Conf.CodeGenOnly) {
- codegen(Conf, TM.get(), AddOutput, Task, Mod);
+ codegen(Conf, TM.get(), AddStream, Task, Mod);
return Error();
}
if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLto=*/true))
return Error();
- codegen(Conf, TM.get(), AddOutput, Task, Mod);
+ codegen(Conf, TM.get(), AddStream, Task, Mod);
return Error();
}
NewPrefix = Split.second.str();
}
-namespace {
-// Define the LTOOutput handling
-class LTOOutput : public lto::NativeObjectOutput {
- StringRef Path;
-
-public:
- LTOOutput(StringRef Path) : Path(Path) {}
- // Open the filename \p Path and allocate a stream.
- std::unique_ptr<raw_pwrite_stream> getStream() override {
- int FD;
- std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_None);
- if (EC)
- message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
- return llvm::make_unique<llvm::raw_fd_ostream>(FD, true);
- }
-};
-}
-
static std::unique_ptr<LTO> createLTO() {
Config Conf;
ThinBackend Backend;
std::vector<uintptr_t> IsTemporary(MaxTasks);
std::vector<SmallString<128>> Filenames(MaxTasks);
- auto AddOutput =
- [&](size_t Task) -> std::unique_ptr<lto::NativeObjectOutput> {
- auto &OutputName = Filenames[Task];
- getOutputFileName(Filename, /*TempOutFile=*/!SaveTemps, OutputName,
+ auto AddStream =
+ [&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
+ IsTemporary[Task] = !SaveTemps;
+ getOutputFileName(Filename, /*TempOutFile=*/!SaveTemps, Filenames[Task],
MaxTasks > 1 ? Task : -1);
- IsTemporary[Task] = !SaveTemps && options::cache_dir.empty();
- if (options::cache_dir.empty())
- return llvm::make_unique<LTOOutput>(OutputName);
-
- return llvm::make_unique<CacheObjectOutput>(
- options::cache_dir,
- [&OutputName](std::string EntryPath) { OutputName = EntryPath; });
+ int FD;
+ std::error_code EC =
+ sys::fs::openFileForWrite(Filenames[Task], FD, sys::fs::F_None);
+ if (EC)
+ message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<llvm::raw_fd_ostream>(FD, true));
};
- check(Lto->run(AddOutput));
+ auto AddFile = [&](size_t Task, StringRef Path) { Filenames[Task] = Path; };
+
+ NativeObjectCache Cache;
+ if (!options::cache_dir.empty())
+ Cache = localCache(options::cache_dir, AddFile);
+
+ check(Lto->run(AddStream, Cache));
if (options::TheOutputType == options::OT_DISABLE ||
options::TheOutputType == options::OT_BC_ONLY)
return T();
}
-namespace {
-// Define the LTOOutput handling
-class LTOOutput : public lto::NativeObjectOutput {
- std::string Path;
-
-public:
- LTOOutput(std::string Path) : Path(std::move(Path)) {}
- std::unique_ptr<raw_pwrite_stream> getStream() override {
- std::error_code EC;
- auto S = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
- check(EC, Path);
- return std::move(S);
- }
-};
-}
-
int main(int argc, char **argv) {
InitializeAllTargets();
InitializeAllTargetMCs();
if (HasErrors)
return 1;
- auto AddOutput =
- [&](size_t Task) -> std::unique_ptr<lto::NativeObjectOutput> {
+ auto AddStream =
+ [&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
std::string Path = OutputFilename + "." + utostr(Task);
- if (CacheDir.empty())
- return llvm::make_unique<LTOOutput>(std::move(Path));
-
- return llvm::make_unique<CacheObjectOutput>(
- CacheDir, [Path](std::string EntryPath) {
- // Load the entry from the cache now.
- auto ReloadedBufferOrErr = MemoryBuffer::getFile(EntryPath);
- if (auto EC = ReloadedBufferOrErr.getError())
- report_fatal_error(Twine("Can't reload cached file '") + EntryPath +
- "': " + EC.message() + "\n");
-
- *LTOOutput(Path).getStream() << (*ReloadedBufferOrErr)->getBuffer();
- });
+
+ std::error_code EC;
+ auto S = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
+ check(EC, Path);
+ return llvm::make_unique<lto::NativeObjectStream>(std::move(S));
};
- check(Lto.run(AddOutput), "LTO::run failed");
+ auto AddFile = [&](size_t Task, StringRef Path) {
+ auto ReloadedBufferOrErr = MemoryBuffer::getFile(Path);
+ if (auto EC = ReloadedBufferOrErr.getError())
+ report_fatal_error(Twine("Can't reload cached file '") + Path + "': " +
+ EC.message() + "\n");
+
+ *AddStream(Task)->OS << (*ReloadedBufferOrErr)->getBuffer();
+ };
+
+ NativeObjectCache Cache;
+ if (!CacheDir.empty())
+ Cache = localCache(CacheDir, AddFile);
+
+ check(Lto.run(AddStream, Cache), "LTO::run failed");
}