COFF: Implement ThinLTO cache and cache pruning support.

Differential Revision: https://reviews.llvm.org/D37607

llvm-svn: 312770
This commit is contained in:
Peter Collingbourne 2017-09-08 00:50:50 +00:00
parent d63b2f3996
commit 052e855e2b
8 changed files with 86 additions and 10 deletions

View File

@ -119,23 +119,27 @@ Incremental
ThinLTO supports fast incremental builds through the use of a cache, ThinLTO supports fast incremental builds through the use of a cache,
which currently must be enabled through a linker option. which currently must be enabled through a linker option.
- gold (as of LLVM r279883): - gold (as of LLVM 4.0):
``-Wl,-plugin-opt,cache-dir=/path/to/cache`` ``-Wl,-plugin-opt,cache-dir=/path/to/cache``
- ld64 (support in clang 3.9 and Xcode 8): - ld64 (support in clang 3.9 and Xcode 8):
``-Wl,-cache_path_lto,/path/to/cache`` ``-Wl,-cache_path_lto,/path/to/cache``
- lld (as of LLVM r296702): - ELF lld (as of LLVM 5.0):
``-Wl,--thinlto-cache-dir=/path/to/cache`` ``-Wl,--thinlto-cache-dir=/path/to/cache``
- COFF lld (as of LLVM 6.0):
``/lldltocache:/path/to/cache``
Cache Pruning Cache Pruning
------------- -------------
To help keep the size of the cache under control, ThinLTO supports cache To help keep the size of the cache under control, ThinLTO supports cache
pruning. Cache pruning is supported with ld64 and ELF lld, but currently only pruning. Cache pruning is supported with ld64 and ELF and COFF lld, but
ELF lld allows you to control the policy with a policy string. The cache currently only ELF and COFF lld allow you to control the policy with a
policy must be specified with a linker option. policy string. The cache policy must be specified with a linker option.
- ELF lld (as of LLVM r298036): - ELF lld (as of LLVM 5.0):
``-Wl,--thinlto-cache-policy,POLICY`` ``-Wl,--thinlto-cache-policy,POLICY``
- COFF lld (as of LLVM 6.0):
``/lldltocachepolicy:POLICY``
A policy string is a series of key-value pairs separated by ``:`` characters. A policy string is a series of key-value pairs separated by ``:`` characters.
Possible key-value pairs are: Possible key-value pairs are:

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h" #include "llvm/Object/COFF.h"
#include "llvm/Support/CachePruning.h"
#include <cstdint> #include <cstdint>
#include <map> #include <map>
#include <set> #include <set>
@ -123,6 +124,11 @@ struct Configuration {
// Used for /opt:lldltopartitions=N // Used for /opt:lldltopartitions=N
unsigned LTOPartitions = 1; unsigned LTOPartitions = 1;
// Used for /opt:lldltocache=path
StringRef LTOCache;
// Used for /opt:lldltocachepolicy=policy
llvm::CachePruningPolicy LTOCachePolicy;
// Used for /merge:from=to (e.g. /merge:.rdata=.text) // Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge; std::map<StringRef, StringRef> Merge;

View File

@ -877,6 +877,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (Args.hasArg(OPT_lldsavetemps)) if (Args.hasArg(OPT_lldsavetemps))
Config->SaveTemps = true; Config->SaveTemps = true;
// Handle /lldltocache
if (auto *Arg = Args.getLastArg(OPT_lldltocache))
Config->LTOCache = Arg->getValue();
// Handle /lldsavecachepolicy
if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy))
Config->LTOCachePolicy = check(
parseCachePruningPolicy(Arg->getValue()),
Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue());
// Handle /failifmismatch // Handle /failifmismatch
for (auto *Arg : Args.filtered(OPT_failifmismatch)) for (auto *Arg : Args.filtered(OPT_failifmismatch))
checkFailIfMismatch(Arg->getValue()); checkFailIfMismatch(Arg->getValue());

View File

@ -18,6 +18,7 @@
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h" #include "llvm/LTO/Config.h"
#include "llvm/LTO/LTO.h" #include "llvm/LTO/LTO.h"
#include "llvm/Object/SymbolicFile.h" #include "llvm/Object/SymbolicFile.h"
@ -118,11 +119,27 @@ void BitcodeCompiler::add(BitcodeFile &F) {
std::vector<StringRef> BitcodeCompiler::compile() { std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks(); unsigned MaxTasks = LTOObj->getMaxTasks();
Buff.resize(MaxTasks); Buff.resize(MaxTasks);
Files.resize(MaxTasks);
checkError(LTOObj->run([&](size_t Task) { // The /lldltocache option specifies the path to a directory in which to cache
return llvm::make_unique<lto::NativeObjectStream>( // native object files for ThinLTO incremental builds. If a path was
llvm::make_unique<raw_svector_ostream>(Buff[Task])); // specified, configure LTO to use it as the cache directory.
})); lto::NativeObjectCache Cache;
if (!Config->LTOCache.empty())
Cache = check(
lto::localCache(Config->LTOCache,
[&](size_t Task, std::unique_ptr<MemoryBuffer> MB,
StringRef Path) { Files[Task] = std::move(MB); }));
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
},
Cache));
if (!Config->LTOCache.empty())
pruneCache(Config->LTOCache, Config->LTOCachePolicy);
std::vector<StringRef> Ret; std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) { for (unsigned I = 0; I != MaxTasks; ++I) {
@ -136,5 +153,10 @@ std::vector<StringRef> BitcodeCompiler::compile() {
} }
Ret.emplace_back(Buff[I].data(), Buff[I].size()); Ret.emplace_back(Buff[I].data(), Buff[I].size());
} }
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(File->getBuffer());
return Ret; return Ret;
} }

View File

@ -49,6 +49,7 @@ public:
private: private:
std::unique_ptr<llvm::lto::LTO> LTOObj; std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buff; std::vector<SmallString<0>> Buff;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
}; };
} }
} }

View File

@ -31,6 +31,8 @@ def heap : P<"heap", "Size of the heap">;
def implib : P<"implib", "Import library name">; def implib : P<"implib", "Import library name">;
def libpath : P<"libpath", "Additional library search path">; def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">;
def lldltocachepolicy : P<"lldltocachepolicy", "Pruning policy for the ThinLTO cache">;
def lldsavetemps : F<"lldsavetemps">, def lldsavetemps : F<"lldsavetemps">,
HelpText<"Save temporary files instead of deleting them">; HelpText<"Save temporary files instead of deleting them">;
def machine : P<"machine", "Specify target platform">; def machine : P<"machine", "Specify target platform">;

View File

@ -0,0 +1,10 @@
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
define i32 @main() {
entry:
call void (...) @globalfunc()
ret i32 0
}
declare void @globalfunc(...)

View File

@ -0,0 +1,21 @@
; REQUIRES: x86
; RUN: opt -module-hash -module-summary %s -o %t.o
; RUN: opt -module-hash -module-summary %p/Inputs/lto-cache.ll -o %t2.o
; RUN: rm -Rf %t.cache && mkdir %t.cache
; Create two files that would be removed by cache pruning due to age.
; We should only remove files matching the pattern "llvmcache-*".
; RUN: touch -t 197001011200 %t.cache/llvmcache-foo %t.cache/foo
; RUN: lld-link /lldltocache:%t.cache /lldltocachepolicy:prune_after=1h /out:%t3 /entry:main %t2.o %t.o
; Two cached objects, plus a timestamp file and "foo", minus the file we removed.
; RUN: ls %t.cache | count 4
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
define void @globalfunc() #0 {
entry:
ret void
}