[clang] [lld] [llvm] Dtlto cache optimization (PR #193189)

Katya Romanova via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 21 03:51:29 PDT 2026


https://github.com/romanova-ekaterina created https://github.com/llvm/llvm-project/pull/193189

None

>From 6dd52284c7d25fa0d7befef8f65bec394cf00988 Mon Sep 17 00:00:00 2001
From: Romanova <katya.romanova at sony.com>
Date: Wed, 3 Dec 2025 08:33:52 -0800
Subject: [PATCH 1/3] [clang] [doc] Added documentation to intrinsics in
 cpuid.h

---
 clang/lib/Headers/cpuid.h | 94 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h
index 432747ba1f6ad..cd5828d925099 100644
--- a/clang/lib/Headers/cpuid.h
+++ b/clang/lib/Headers/cpuid.h
@@ -278,6 +278,23 @@
         : "0"(__leaf), "2"(__count))
 #endif
 
+/// Queries the processor to determine the highest supported \c CPUID leaf.
+///
+/// \headerfile <cpuid.h>
+///
+/// This intrinsic corresponds to the <c> CPUID </c> instruction.
+///
+/// \param __leaf
+///    \a __leaf can be either 0x0 or 0x8000000. If \a __leaf == 0x0, the
+///    highest supported value for basic \c CPUID information is returned.
+///    If \a __leaf == 0x8000000, the highest supported value for extended
+///    \c CPUID information is returned.
+/// \param __sig
+///    If the \a __sig pointer is non-null, the first four bytes of the
+///    signature (as found in the \c ebx register) are returned in the
+///    location pointed to by \a __sig.
+/// \returns Returns 0 if \c CPUID is supported; otherwise returns the value
+///    that \c CPUID returns in the \c eax register.
 static __inline unsigned int __get_cpuid_max (unsigned int __leaf,
                                               unsigned int *__sig)
 {
@@ -311,6 +328,32 @@ static __inline unsigned int __get_cpuid_max (unsigned int __leaf,
     return __eax;
 }
 
+/// For the requested \c CPUID leaf, queries the processor for information
+/// about the CPU type and CPU features (such as processor vendor, supported
+/// instruction sets, CPU capabilities, cache sizes, CPU model and family, and
+/// other hardware details). This intrinsic is only available on x86 and x64.
+///
+/// \headerfile <cpuid.h>
+///
+/// This intrinsic corresponds to the <c> CPUID </c> instruction.
+///
+/// \param __leaf
+///    An unsigned integer that identifies the level (also called "leaf") at
+///    which the \c CPUID instruction will be executed.
+/// \param __eax
+///    A pointer to an integer that corresponds to the \c eax register where
+///    \c CPUID stores output results.
+/// \param __ebx
+///    A pointer to an integer that corresponds to the \c ebx register where
+///    \c CPUID stores output results.
+/// \param __ecx
+///    A pointer to an integer that corresponds to the \c ecx register where
+///    \c CPUID stores output results.
+/// \param __edx
+///    A pointer to an integer that corresponds to the \c edx register where
+///    \c CPUID stores output results.
+/// \returns Returns 1 if the requested \c CPUID leaf is supported; otherwise
+///    returns 0.
 static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax,
                                  unsigned int *__ebx, unsigned int *__ecx,
                                  unsigned int *__edx)
@@ -324,6 +367,36 @@ static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax,
     return 1;
 }
 
+/// For the requested \c CPUID leaf and subleaf, queries the processor for
+/// information about the CPU type and CPU features (such as processor vendor,
+/// supported instruction sets, CPU capabilities, cache sizes, CPU model and
+/// family, and other hardware details). This intrinsic is only available on
+/// x86 and x64.
+///
+/// \headerfile <cpuid.h>
+///
+/// This intrinsic corresponds to the <c> CPUID </c> instruction.
+///
+/// \param __leaf
+///    An unsigned integer that identifies the level (also called "leaf") at
+///    which the \c CPUID instruction will be executed.
+/// \param __subleaf
+///    An unsigned integer that identifies the sublevel (also called
+///    "subleaf") at which the \c CPUID instruction will be executed.
+/// \param __eax
+///    A pointer to an integer that corresponds to the \c eax register where
+///    \c CPUID stores output results.
+/// \param __ebx
+///    A pointer to an integer that corresponds to the \c ebx register where
+///    \c CPUID stores output results.
+/// \param __ecx
+///    A pointer to an integer that corresponds to the \c ecx register where
+///    \c CPUID stores output results.
+/// \param __edx
+///    A pointer to an integer that corresponds to the \c edx register where
+///    \c CPUID stores output results.
+/// \returns Returns 1 if the requested \c CPUID leaf is supported; otherwise
+///    returns 0.
 static __inline int __get_cpuid_count (unsigned int __leaf,
                                        unsigned int __subleaf,
                                        unsigned int *__eax, unsigned int *__ebx,
@@ -345,6 +418,27 @@ static __inline int __get_cpuid_count (unsigned int __leaf,
 // builtin. Given __has_builtin does not detect builtins on aux triples, we need
 // to explicitly check for some offloading cases.
 #if !defined(__NVPTX__) && !defined(__AMDGPU__) && !defined(__SPIRV__)
+/// Executes the \c CPUID instruction with the specified leaf and subleaf
+/// values, and returns the results from the CPU's registers.
+///
+/// \headerfile <cpuid.h>
+///
+/// This intrinsic corresponds to the <c> CPUID </c> instruction.
+///
+/// \param __cpu_info
+///    An output array of four integers:
+///    <ul>
+///    <li>\a __cpuInfo[0] receives the value of the \c eax register.</li>
+///    <li>\a__cpuInfo[1] receives the value of the \c ebx register.</li>
+///    <li>\a__cpuInfo[2] receives the value of the \c ecx register.</li>
+///    <li>\a__cpuInfo[3] receives the value of the \c edx register.</li>
+///    </ul>
+/// \param __leaf
+///    An unsigned integer that identifies the level (also called the "leaf")
+///    at which the \c CPUID instruction will be executed.
+/// \param __subleaf
+///    An unsigned integer that identifies the sublevel (also called the
+///    "subleaf") at which the \c CPUID instruction will be executed.
 static __inline void __cpuidex(int __cpu_info[4], int __leaf, int __subleaf) {
   __cpuid_count(__leaf, __subleaf, __cpu_info[0], __cpu_info[1], __cpu_info[2],
                 __cpu_info[3]);

>From f29da145ad063d03a55b14eeadbd441501147c3c Mon Sep 17 00:00:00 2001
From: Romanova <katya.romanova at sony.com>
Date: Fri, 5 Dec 2025 07:21:11 -0800
Subject: [PATCH 2/3] Responded to code review comments to intrinsics
 documentation in cpuid.h

---
 clang/lib/Headers/cpuid.h | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h
index cd5828d925099..156425c7561bb 100644
--- a/clang/lib/Headers/cpuid.h
+++ b/clang/lib/Headers/cpuid.h
@@ -279,6 +279,7 @@
 #endif
 
 /// Queries the processor to determine the highest supported \c CPUID leaf.
+/// This intrinsic is only available on x86 and x64.
 ///
 /// \headerfile <cpuid.h>
 ///
@@ -291,10 +292,10 @@
 ///    \c CPUID information is returned.
 /// \param __sig
 ///    If the \a __sig pointer is non-null, the first four bytes of the
-///    signature (as found in the \c ebx register) are returned in the
+///    signature (as found in the \c EBX register) are returned in the
 ///    location pointed to by \a __sig.
 /// \returns Returns 0 if \c CPUID is supported; otherwise returns the value
-///    that \c CPUID returns in the \c eax register.
+///    that \c CPUID returns in the \c EAX register.
 static __inline unsigned int __get_cpuid_max (unsigned int __leaf,
                                               unsigned int *__sig)
 {
@@ -341,16 +342,16 @@ static __inline unsigned int __get_cpuid_max (unsigned int __leaf,
 ///    An unsigned integer that identifies the level (also called "leaf") at
 ///    which the \c CPUID instruction will be executed.
 /// \param __eax
-///    A pointer to an integer that corresponds to the \c eax register where
+///    A pointer to an integer that corresponds to the \c EAX register where
 ///    \c CPUID stores output results.
 /// \param __ebx
-///    A pointer to an integer that corresponds to the \c ebx register where
+///    A pointer to an integer that corresponds to the \c EBX register where
 ///    \c CPUID stores output results.
 /// \param __ecx
-///    A pointer to an integer that corresponds to the \c ecx register where
+///    A pointer to an integer that corresponds to the \c ECX register where
 ///    \c CPUID stores output results.
 /// \param __edx
-///    A pointer to an integer that corresponds to the \c edx register where
+///    A pointer to an integer that corresponds to the \c EDX register where
 ///    \c CPUID stores output results.
 /// \returns Returns 1 if the requested \c CPUID leaf is supported; otherwise
 ///    returns 0.
@@ -384,16 +385,16 @@ static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax,
 ///    An unsigned integer that identifies the sublevel (also called
 ///    "subleaf") at which the \c CPUID instruction will be executed.
 /// \param __eax
-///    A pointer to an integer that corresponds to the \c eax register where
+///    A pointer to an integer that corresponds to the \c EAX register where
 ///    \c CPUID stores output results.
 /// \param __ebx
-///    A pointer to an integer that corresponds to the \c ebx register where
+///    A pointer to an integer that corresponds to the \c EBX register where
 ///    \c CPUID stores output results.
 /// \param __ecx
-///    A pointer to an integer that corresponds to the \c ecx register where
+///    A pointer to an integer that corresponds to the \c ECX register where
 ///    \c CPUID stores output results.
 /// \param __edx
-///    A pointer to an integer that corresponds to the \c edx register where
+///    A pointer to an integer that corresponds to the \c EDX register where
 ///    \c CPUID stores output results.
 /// \returns Returns 1 if the requested \c CPUID leaf is supported; otherwise
 ///    returns 0.
@@ -419,7 +420,8 @@ static __inline int __get_cpuid_count (unsigned int __leaf,
 // to explicitly check for some offloading cases.
 #if !defined(__NVPTX__) && !defined(__AMDGPU__) && !defined(__SPIRV__)
 /// Executes the \c CPUID instruction with the specified leaf and subleaf
-/// values, and returns the results from the CPU's registers.
+/// values, and returns the results from the CPU's registers. This intrinsic
+/// is only available on x86 and x64.
 ///
 /// \headerfile <cpuid.h>
 ///
@@ -428,10 +430,10 @@ static __inline int __get_cpuid_count (unsigned int __leaf,
 /// \param __cpu_info
 ///    An output array of four integers:
 ///    <ul>
-///    <li>\a __cpuInfo[0] receives the value of the \c eax register.</li>
-///    <li>\a__cpuInfo[1] receives the value of the \c ebx register.</li>
-///    <li>\a__cpuInfo[2] receives the value of the \c ecx register.</li>
-///    <li>\a__cpuInfo[3] receives the value of the \c edx register.</li>
+///    <li>\a __cpuInfo[0] receives the value of the \c EAX register.</li>
+///    <li>\a __cpuInfo[1] receives the value of the \c EBX register.</li>
+///    <li>\a __cpuInfo[2] receives the value of the \c ECX register.</li>
+///    <li>\a __cpuInfo[3] receives the value of the \c EDX register.</li>
 ///    </ul>
 /// \param __leaf
 ///    An unsigned integer that identifies the level (also called the "leaf")

>From 8625a54a02c5f3e0acefbad2b351fc04d544baf9 Mon Sep 17 00:00:00 2001
From: Romanova <katya.romanova at sony.com>
Date: Tue, 21 Apr 2026 03:49:41 -0700
Subject: [PATCH 3/3] DTLTO Cache optimization

---
 lld/COFF/LTO.cpp                              | 17 +++--
 lld/ELF/LTO.cpp                               | 17 +++--
 llvm/include/llvm/Support/Caching.h           | 15 ++--
 llvm/lib/LTO/LTO.cpp                          | 11 ++-
 llvm/lib/Support/Caching.cpp                  | 42 ++++++++++-
 .../dtlto/dtlto-cache-rename-optimization.ll  | 73 +++++++++++++++++++
 llvm/tools/llvm-lto2/llvm-lto2.cpp            |  3 +-
 7 files changed, 156 insertions(+), 22 deletions(-)
 create mode 100644 llvm/test/ThinLTO/X86/dtlto/dtlto-cache-rename-optimization.ll

diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index b1efb28347f74..67dc1f41c5f73 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -38,6 +38,16 @@ using namespace llvm::object;
 using namespace lld;
 using namespace lld::coff;
 
+static AddBufferFn
+createAddBufferFn(std::vector<std::unique_ptr<MemoryBuffer>> &files,
+                  std::vector<std::string> &filenames) {
+  return [&files, &filenames](unsigned task, const Twine &moduleName,
+                              std::unique_ptr<MemoryBuffer> mb) {
+    files[task] = std::move(mb);
+    filenames[task] = moduleName.str();
+  };
+}
+
 std::string BitcodeCompiler::getThinLTOOutputFile(StringRef path) {
   return lto::getThinLTOOutputFile(path, ctx.config.thinLTOPrefixReplaceOld,
                                    ctx.config.thinLTOPrefixReplaceNew);
@@ -189,11 +199,8 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
   FileCache cache;
   if (!ctx.config.ltoCache.empty())
     cache = check(localCache("ThinLTO", "Thin", ctx.config.ltoCache,
-                             [&](size_t task, const Twine &moduleName,
-                                 std::unique_ptr<MemoryBuffer> mb) {
-                               files[task] = std::move(mb);
-                               file_names[task] = moduleName.str();
-                             }));
+                             createAddBufferFn(files, file_names),
+                             !ctx.config.dtltoDistributor.empty()));
 
   checkError(ltoObj->run(
       [&](size_t task, const Twine &moduleName) {
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 80c6d2482f9fa..bbe1064344193 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -37,6 +37,16 @@ using namespace llvm::ELF;
 using namespace lld;
 using namespace lld::elf;
 
+static AddBufferFn
+createAddBufferFn(std::vector<std::unique_ptr<MemoryBuffer>> &files,
+                  SmallVectorImpl<std::string> &filenames) {
+  return [&files, &filenames](unsigned task, const Twine &moduleName,
+                              std::unique_ptr<MemoryBuffer> mb) {
+    files[task] = std::move(mb);
+    filenames[task] = moduleName.str();
+  };
+}
+
 static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) {
   return lto::getThinLTOOutputFile(modulePath, ctx.arg.thinLTOPrefixReplaceOld,
                                    ctx.arg.thinLTOPrefixReplaceNew);
@@ -323,11 +333,8 @@ SmallVector<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {
   FileCache cache;
   if (!ctx.arg.thinLTOCacheDir.empty())
     cache = check(localCache("ThinLTO", "Thin", ctx.arg.thinLTOCacheDir,
-                             [&](size_t task, const Twine &moduleName,
-                                 std::unique_ptr<MemoryBuffer> mb) {
-                               files[task] = std::move(mb);
-                               filenames[task] = moduleName.str();
-                             }));
+                             createAddBufferFn(files, filenames),
+                             !ctx.arg.dtltoDistributor.empty()));
 
   if (!ctx.bitcodeFiles.empty())
     checkError(ctx.e, ltoObj->run(
diff --git a/llvm/include/llvm/Support/Caching.h b/llvm/include/llvm/Support/Caching.h
index cebf071b0188f..4f3852bd310f7 100644
--- a/llvm/include/llvm/Support/Caching.h
+++ b/llvm/include/llvm/Support/Caching.h
@@ -20,6 +20,11 @@
 #include "llvm/Support/MemoryBuffer.h"
 
 namespace llvm {
+/// This type defines the callback to add a pre-existing file (e.g. in a cache).
+///
+/// Buffer callbacks must be thread safe.
+using AddBufferFn = std::function<void(unsigned Task, const Twine &ModuleName,
+                                       std::unique_ptr<MemoryBuffer> MB)>;
 
 /// 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
@@ -50,6 +55,7 @@ class CachedFileStream {
     if (!Committed)
       report_fatal_error("CachedFileStream was not committed.\n");
   }
+  virtual AddBufferFn GetAddBuffer() { return AddBufferFn(); }
 };
 
 /// This type defines the callback to add a file that is generated on the fly.
@@ -101,12 +107,6 @@ struct FileCache {
   std::string CacheDirectoryPath;
 };
 
-/// This type defines the callback to add a pre-existing file (e.g. in a cache).
-///
-/// Buffer callbacks must be thread safe.
-using AddBufferFn = std::function<void(unsigned Task, const Twine &ModuleName,
-                                       std::unique_ptr<MemoryBuffer> MB)>;
-
 /// Create a local file system cache which uses the given cache name, temporary
 /// file prefix, cache directory and file callback.  This function does not
 /// immediately create the cache directory if it does not yet exist; this is
@@ -117,7 +117,8 @@ LLVM_ABI Expected<FileCache> localCache(
     const Twine &CacheNameRef, const Twine &TempFilePrefixRef,
     const Twine &CacheDirectoryPathRef,
     AddBufferFn AddBuffer = [](size_t Task, const Twine &ModuleName,
-                               std::unique_ptr<MemoryBuffer> MB) {});
+                               std::unique_ptr<MemoryBuffer> MB) {},
+    bool CacheFileRename = false);
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index a02af59600c44..04cfb5b637bd3 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -2590,11 +2590,16 @@ class OutOfProcessThinBackend : public CGThinBackend {
               createStringError(inconvertibleErrorCode(),
                                 "Cannot get a cache file stream: %s",
                                 Job.NativeObjectPath.data()));
-        // Store a file buffer into the cache stream.
+        
         auto &CacheStream = *(CachedFileStreamOrErr->get());
-        *(CacheStream.OS) << ObjFileMbRef.getBuffer();
-        if (Error Err = CacheStream.commit())
+
+        // Store a file path into the cache stream. This file later will be
+        // renamed into cache file.
+        *(CacheStream.OS) << Job.NativeObjectPath;
+		if (Error Err = CacheStream.commit())
           return Err;
+          AddBufferFn AddBuffer = CacheStream.GetAddBuffer();
+          AddBuffer(Job.Task, Job.ModuleID, std::move(ObjFileMbOrErr.get()));
       } else {
         auto StreamOrErr = AddStream(Job.Task, Job.ModuleID);
         if (Error Err = StreamOrErr.takeError())
diff --git a/llvm/lib/Support/Caching.cpp b/llvm/lib/Support/Caching.cpp
index 40a5c44771b65..d42d6654887b8 100644
--- a/llvm/lib/Support/Caching.cpp
+++ b/llvm/lib/Support/Caching.cpp
@@ -21,6 +21,7 @@
 #if !defined(_MSC_VER) && !defined(__MINGW32__)
 #include <unistd.h>
 #else
+#include "llvm/Support/Windows/WindowsSupport.h"
 #include <io.h>
 #endif
 
@@ -29,7 +30,7 @@ using namespace llvm;
 Expected<FileCache> llvm::localCache(const Twine &CacheNameRef,
                                      const Twine &TempFilePrefixRef,
                                      const Twine &CacheDirectoryPathRef,
-                                     AddBufferFn AddBuffer) {
+                                     AddBufferFn AddBuffer, bool CacheRename) {
 
   // Create local copies which are safely captured-by-copy in lambdas
   SmallString<64> CacheName, TempFilePrefix, CacheDirectoryPath;
@@ -142,6 +143,38 @@ Expected<FileCache> llvm::localCache(const Twine &CacheNameRef,
         AddBuffer(Task, ModuleName, std::move(*MBOrErr));
         return Error::success();
       }
+      virtual AddBufferFn GetAddBuffer() override { return AddBuffer; }
+    };
+
+    // This class is responsible for renaming/moving existing file into a
+    // cache directory. The path for an input file is passed through a string
+    // stream.
+    struct MoveFileToCache : CachedFileStream {
+      AddBufferFn AddBuffer;
+      size_t Task;
+      SmallString<0> FilePath;
+      MoveFileToCache(AddBufferFn AddBuffer, std::string EntryPath, size_t Task)
+          : CachedFileStream(
+                std::make_unique<raw_svector_ostream>(FilePath),
+                std::move(EntryPath)),
+            AddBuffer(std::move(AddBuffer)), Task(Task) {}
+      ~MoveFileToCache() {
+        // Rename/move native object file into cache directory, if they are
+        // located the same device/logical drive, otherwise we use a copy.
+        std::error_code EC = sys::fs::rename(FilePath, ObjectPathName);
+#ifdef _WIN32
+        if (EC ==
+            std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category()))
+#else
+        if (EC == std::make_error_code(std::errc::cross_device_link))
+#endif
+          EC = sys::fs::copy_file(FilePath, ObjectPathName);
+        if (EC)
+          report_fatal_error(Twine("Failed to rename or copy file ") +
+                             FilePath + " to " + ObjectPathName + ": " +
+                             EC.message() + "\n");
+      }
+      virtual AddBufferFn GetAddBuffer() override { return AddBuffer; }
     };
 
     return [=](size_t Task, const Twine &ModuleName)
@@ -154,6 +187,13 @@ Expected<FileCache> llvm::localCache(const Twine &CacheNameRef,
                                          CacheDirectoryPath + ": " +
                                          EC.message());
 
+      // MoveFileToChache class will rename/move the file into the cache on
+      // destruction.
+      if (CacheRename) {
+        return std::make_unique<MoveFileToCache>(
+            AddBuffer, std::string(EntryPath.str()), Task);
+      }
+
       // Write to a temporary to avoid race condition
       SmallString<64> TempFilenameModel;
       sys::path::append(TempFilenameModel, CacheDirectoryPath,
diff --git a/llvm/test/ThinLTO/X86/dtlto/dtlto-cache-rename-optimization.ll b/llvm/test/ThinLTO/X86/dtlto/dtlto-cache-rename-optimization.ll
new file mode 100644
index 0000000000000..0c082f38d7548
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/dtlto/dtlto-cache-rename-optimization.ll
@@ -0,0 +1,73 @@
+; DTLTO with llvm-lto2 and -cache-dir, using --save-temps
+; to leave distributor artifacts saved on the disk (except native object files).
+; native object files shouldn't be saved, because they are renamed into
+; cache entries. 
+; The test also checks that the cache is populated
+RUN: rm -rf %t && split-file %s %t && cd %t
+
+; Generate bitcode files with summary.
+RUN: opt -thinlto-bc t1.ll -o t1.bc
+RUN: opt -thinlto-bc t2.ll -o t2.bc
+
+; Generate fake object files for mock.py to return.
+RUN: touch t1.o t2.o
+
+; Create an empty subdirectory to avoid having to account for the input files.
+RUN: mkdir %t/out && cd %t/out
+
+DEFINE: %{command} = llvm-lto2 run ../t1.bc ../t2.bc -o t.o -cache-dir cache-dir \
+DEFINE:   --save-temps \
+DEFINE:   -dtlto-distributor=%python \
+DEFINE:   -dtlto-distributor-arg=%llvm_src_root/utils/dtlto/mock.py,../t1.o,../t2.o \
+DEFINE:   -r=../t1.bc,t1,px \
+DEFINE:   -r=../t2.bc,t2,px
+
+RUN: %{command}
+
+; 12 save-temps outputs plus the cache directory.
+RUN: ls | count 11
+RUN: ls | FileCheck %s --check-prefixes=THINLTO,SAVETEMPS,NOT-NATIVE
+RUN: ls cache-dir/* | count 2
+RUN: ls cache-dir/llvmcache-* | count 2
+
+; llvm-lto2 ThinLTO output files.
+THINLTO-DAG: {{^}}t.o.1{{$}}
+THINLTO-DAG: {{^}}t.o.2{{$}}
+
+; Common -save-temps files from llvm-lto2.
+SAVETEMPS-DAG: {{^}}t.o.resolution.txt{{$}}
+SAVETEMPS-DAG: {{^}}t.o.index.bc{{$}}
+SAVETEMPS-DAG: {{^}}t.o.index.dot{{$}}
+
+; -save-temps incremental files.
+SAVETEMPS-DAG: {{^}}t.o.0.0.preopt.bc{{$}}
+SAVETEMPS-DAG: {{^}}t.o.0.2.internalize.bc{{$}}
+
+; A jobs description JSON.
+SAVETEMPS-DAG: {{^}}t.[[#]].dist-file.json{{$}}
+
+; Summary shards emitted for DTLTO.
+SAVETEMPS-DAG: {{^}}t1.1.[[#]].native.o.thinlto.bc{{$}}
+SAVETEMPS-DAG: {{^}}t2.2.[[#]].native.o.thinlto.bc{{$}}
+
+; DTLTO native output files (the results of the external backend compilations)
+; should not be saved, because these files are renamed into cache entries
+NOT-NATIVE-NOT: native.o{{$}}
+
+;--- t1.ll
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @t1() {
+  ret void
+}
+
+;--- t2.ll
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @t2() {
+  ret void
+}
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index 399306f39daeb..d30245188b023 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -488,7 +488,8 @@ static int run(int argc, char **argv) {
 
   FileCache Cache;
   if (!CacheDir.empty())
-    Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),
+    Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer,
+                             !DTLTODistributor.empty()),
                   "failed to create cache");
 
   check(Lto.run(AddStream, Cache), "LTO::run failed");



More information about the llvm-commits mailing list