Index: cfe/trunk/docs/ThinLTO.rst =================================================================== --- cfe/trunk/docs/ThinLTO.rst +++ cfe/trunk/docs/ThinLTO.rst @@ -119,23 +119,27 @@ ThinLTO supports fast incremental builds through the use of a cache, 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`` - ld64 (support in clang 3.9 and Xcode 8): ``-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`` +- COFF lld (as of LLVM 6.0): + ``/lldltocache:/path/to/cache`` Cache Pruning ------------- 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 -ELF lld allows you to control the policy with a policy string. The cache -policy must be specified with a linker option. +pruning. Cache pruning is supported with ld64 and ELF and COFF lld, but +currently only ELF and COFF lld allow you to control the policy with a +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`` +- COFF lld (as of LLVM 6.0): + ``/lldltocachepolicy:POLICY`` A policy string is a series of key-value pairs separated by ``:`` characters. Possible key-value pairs are: Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/CachePruning.h" #include #include #include @@ -123,6 +124,11 @@ // Used for /opt:lldltopartitions=N 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) std::map Merge; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -877,6 +877,16 @@ if (Args.hasArg(OPT_lldsavetemps)) 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 for (auto *Arg : Args.filtered(OPT_failifmismatch)) checkFailIfMismatch(Arg->getValue()); Index: lld/trunk/COFF/LTO.h =================================================================== --- lld/trunk/COFF/LTO.h +++ lld/trunk/COFF/LTO.h @@ -49,6 +49,7 @@ private: std::unique_ptr LTOObj; std::vector> Buff; + std::vector> Files; }; } } Index: lld/trunk/COFF/LTO.cpp =================================================================== --- lld/trunk/COFF/LTO.cpp +++ lld/trunk/COFF/LTO.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/SymbolicFile.h" @@ -118,11 +119,27 @@ std::vector BitcodeCompiler::compile() { unsigned MaxTasks = LTOObj->getMaxTasks(); Buff.resize(MaxTasks); + Files.resize(MaxTasks); - checkError(LTOObj->run([&](size_t Task) { - return llvm::make_unique( - llvm::make_unique(Buff[Task])); - })); + // 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. + lto::NativeObjectCache Cache; + if (!Config->LTOCache.empty()) + Cache = check( + lto::localCache(Config->LTOCache, + [&](size_t Task, std::unique_ptr MB, + StringRef Path) { Files[Task] = std::move(MB); })); + + checkError(LTOObj->run( + [&](size_t Task) { + return llvm::make_unique( + llvm::make_unique(Buff[Task])); + }, + Cache)); + + if (!Config->LTOCache.empty()) + pruneCache(Config->LTOCache, Config->LTOCachePolicy); std::vector Ret; for (unsigned I = 0; I != MaxTasks; ++I) { @@ -136,5 +153,10 @@ } Ret.emplace_back(Buff[I].data(), Buff[I].size()); } + + for (std::unique_ptr &File : Files) + if (File) + Ret.push_back(File->getBuffer()); + return Ret; } Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -31,6 +31,8 @@ def implib : P<"implib", "Import library name">; def libpath : P<"libpath", "Additional library search path">; 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">, HelpText<"Save temporary files instead of deleting them">; def machine : P<"machine", "Specify target platform">; Index: lld/trunk/test/COFF/Inputs/lto-cache.ll =================================================================== --- lld/trunk/test/COFF/Inputs/lto-cache.ll +++ lld/trunk/test/COFF/Inputs/lto-cache.ll @@ -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(...) Index: lld/trunk/test/COFF/lto-cache.ll =================================================================== --- lld/trunk/test/COFF/lto-cache.ll +++ lld/trunk/test/COFF/lto-cache.ll @@ -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 +}