summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/LTO/ThinLTOCodeGenerator.cpp96
1 files changed, 95 insertions, 1 deletions
diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
index 7c4e74e9c2b..26a3e35e04f 100644
--- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
@@ -29,6 +29,9 @@
#include "llvm/Linker/Linker.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SHA1.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/ThreadPool.h"
@@ -286,6 +289,72 @@ std::unique_ptr<MemoryBuffer> codegenModule(Module &TheModule,
return make_unique<ObjectMemoryBuffer>(std::move(OutputBuffer));
}
+/// Manage caching for a single Module.
+class ModuleCacheEntry {
+ SmallString<128> EntryPath;
+
+public:
+ // Create a cache entry. This compute a unique hash for the Module considering
+ // the current list of export/import, and offer an interface to query to
+ // access the content in the cache.
+ ModuleCacheEntry(StringRef CachePath, const ModuleSummaryIndex &Index,
+ StringRef ModuleID,
+ const FunctionImporter::ImportMapTy &ImportList,
+ const FunctionImporter::ExportSetTy &ExportList) {
+ if (CachePath.empty())
+ return;
+
+ // Compute the unique hash for this entry
+ // This is based on the module itself, the export list, and the hash for
+ // every single module in the import list
+
+ SHA1 Hasher;
+ // Include the hash for the current module
+ auto ModHash = Index.getModuleHash(ModuleID);
+ Hasher.update(ArrayRef<uint8_t>((uint8_t *)&ModHash[0], sizeof(ModHash)));
+ for (auto F : ExportList)
+ // The export list can impact the internalization, be conservative here
+ Hasher.update(ArrayRef<uint8_t>((uint8_t *)&F, sizeof(F)));
+
+ // Include the hash for every module we import functions from
+ for (auto &Entry : ImportList) {
+ auto ModHash = Index.getModuleHash(Entry.first());
+ Hasher.update(ArrayRef<uint8_t>((uint8_t *)&ModHash[0], sizeof(ModHash)));
+ }
+
+ sys::path::append(EntryPath, CachePath, toHex(Hasher.result()));
+ }
+
+ // Try loading the buffer for this cache entry.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> tryLoadingBuffer() {
+ if (EntryPath.empty())
+ return std::error_code();
+ return MemoryBuffer::getFile(EntryPath);
+ }
+
+ // Cache the Produced object file
+ void write(MemoryBufferRef OutputBuffer) {
+ if (EntryPath.empty())
+ return;
+
+ // Write to a temporary to avoid race condition
+ SmallString<128> TempFilename;
+ 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");
+ }
+ {
+ raw_fd_ostream OS(TempFD, /* ShouldClose */ true);
+ OS << OutputBuffer.getBuffer();
+ }
+ // Rename to final destination (hopefully race condition won't matter here)
+ sys::fs::rename(TempFilename, EntryPath);
+ }
+};
+
static std::unique_ptr<MemoryBuffer>
ProcessThinLTOModule(Module &TheModule, const ModuleSummaryIndex &Index,
StringMap<MemoryBufferRef> &ModuleMap, TargetMachine &TM,
@@ -528,6 +597,21 @@ void ThinLTOCodeGenerator::run() {
int count = 0;
for (auto &ModuleBuffer : Modules) {
Pool.async([&](int count) {
+ // The module may be cached, this helps handling it.
+ ModuleCacheEntry CacheEntry(
+ CacheOptions.Path, *Index, ModuleBuffer.getBufferIdentifier(),
+ ImportLists[ModuleBuffer.getBufferIdentifier()],
+ ExportLists[ModuleBuffer.getBufferIdentifier()]);
+
+ {
+ auto ErrOrBuffer = CacheEntry.tryLoadingBuffer();
+ if (ErrOrBuffer) {
+ // Cache Hit!
+ ProducedBinaries[count] = std::move(ErrOrBuffer.get());
+ return;
+ }
+ }
+
LLVMContext Context;
Context.setDiscardValueNames(LTODiscardValueNames);
@@ -540,14 +624,24 @@ void ThinLTOCodeGenerator::run() {
}
auto &ImportList = ImportLists[TheModule->getModuleIdentifier()];
- ProducedBinaries[count] = ProcessThinLTOModule(
+
+ auto OutputBuffer = ProcessThinLTOModule(
*TheModule, *Index, ModuleMap, *TMBuilder.create(), ImportList,
CacheOptions, DisableCodeGen, SaveTempsDir, count);
+
+ CacheEntry.write(*OutputBuffer);
+ ProducedBinaries[count] = std::move(OutputBuffer);
}, count);
count++;
}
}
+ CachePruning(CacheOptions.Path)
+ .setPruningInterval(CacheOptions.PruningInterval)
+ .setEntryExpiration(CacheOptions.Expiration)
+ .setMaxSize(CacheOptions.MaxPercentageOfAvailableSpace)
+ .prune();
+
// If statistics were requested, print them out now.
if (llvm::AreStatisticsEnabled())
llvm::PrintStatistics();
OpenPOWER on IntegriCloud