[lld] [llvm] [DTLTO] Delay individual bitcode file serialization until after cache checks (PR #191142)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 9 17:30:34 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld-elf

Author: Ben Dunbobbin (bd1976bris)

<details>
<summary>Changes</summary>

Defer DTLTO input serialization for archive members and FatLTO objects until the out-of-process ThinLTO backend has made its cache decisions.

Instead of eagerly writing temporary bitcode files during DTLTO input preparation, record the rewritten module ID and original input buffer in LTO state and thread that map through ThinLTO backend construction. The out-of-process backend now serializes only the uncached module inputs and any imported serialized inputs required by those uncached jobs.

If the ThinLTO cache is enabled, modules that hit the cache are not serialized. For a Clang link (Debug build with sanitizers and instrumentation) using an optimized toolchain (PGO non-LTO, llvmorg-22.1.0) on Windows 11 Pro (Build 26200), AMD Family 25 @ ~4.5 GHz, 16 cores / 32 threads, 64 GB RAM, I measured:
- No difference in serialization time when the cache is disabled.
- When the cache is enabled serialization previously took ~10% of link time (~7s on Windows); this is now eliminated.

Gains on Linux are smaller.

---

Patch is 27.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/191142.diff


7 Files Affected:

- (added) cross-project-tests/dtlto/cache-serialization.test (+98) 
- (modified) lld/COFF/LTO.cpp (+1-2) 
- (modified) lld/ELF/LTO.cpp (+1-2) 
- (modified) llvm/include/llvm/DTLTO/DTLTO.h (+17-22) 
- (modified) llvm/include/llvm/LTO/LTO.h (+19-18) 
- (modified) llvm/lib/DTLTO/DTLTO.cpp (+12-69) 
- (modified) llvm/lib/LTO/LTO.cpp (+95-17) 


``````````diff
diff --git a/cross-project-tests/dtlto/cache-serialization.test b/cross-project-tests/dtlto/cache-serialization.test
new file mode 100644
index 0000000000000..690e619ce15a2
--- /dev/null
+++ b/cross-project-tests/dtlto/cache-serialization.test
@@ -0,0 +1,98 @@
+REQUIRES: ld.lld
+
+# Show that DTLTO input file serialization interacts correctly with
+# the ThinLTO cache.
+#
+# To handle bitcode inputs that are not in individual files on disk,
+# such as members of non-thin archives, DTLTO serializes such input
+# bitcode to a temporary individual file on disk. This serialization
+# should only be performed if the backend compilation is required. A
+# backend compilation is only required if there is a miss in the ThinLTO
+# cache for that module, or a module is imported by a module that has
+# missed in the ThinLTO cache.
+#
+# Test DTLTO input serialization across three cases:
+#   1. ThinLTO cache miss for all backends
+#      (sanity check that the assumptions for this test hold).
+#   2. Full ThinLTO cache hit
+#   3. Partial ThinLTO cache hit
+
+RUN: rm -rf %t && split-file %s %t && cd %t
+
+RUN: %clang --target=x86_64-linux-gnu -O2 -flto=thin -c t1.c t2.c
+RUN: llvm-ar rcs t1.a t1.o
+RUN: llvm-ar rcs t2.a t2.o
+
+RUN: mkdir cache.dir
+DEFINE: %{link} = \
+DEFINE:   %clang --target=x86_64-linux-gnu -nostdlib -O2 -flto=thin -fuse-ld=lld \
+DEFINE:     -fthinlto-distributor=%python \
+DEFINE:     -Xthinlto-distributor=%llvm_src_root/utils/dtlto/local.py \
+DEFINE:     -Wl,--thinlto-remote-compiler=%clang \
+DEFINE:     -Wl,--thinlto-cache-dir=cache.dir \
+DEFINE:     -Wl,--save-temps -shared
+
+# First link: full cache miss.
+#
+# Both t1.o and t2.o require backend compilation, so both should be
+# serialized.
+# Each backend compilation should produce:
+#   * a native object
+#   * a thinlto.bc file
+#   * a regular saved temp object
+RUN: mkdir miss
+RUN: %{link} -Wl,--whole-archive t1.a t2.a -o miss/t.elf
+RUN: ls miss | sort | FileCheck %s --check-prefixes=JSON,ELF,MISS
+JSON: {{^}}t.[[#PID:]].dist-file.json{{$}}
+ELF: {{^}}t.elf.resolution.txt{{$}}
+MISS-NEXT: t1.a(t1.o at [[#T1_OFFSET:]]).1.[[#%X,HEXPID:]].1.[[#PID:]].native.o
+MISS-NEXT: t1.a(t1.o at [[#T1_OFFSET]]).1.[[#%X,HEXPID]].1.[[#PID]].native.o.thinlto.bc
+MISS-NEXT: t1.a(t1.o at [[#T1_OFFSET]]).1.[[#%X,HEXPID]].o
+MISS-NEXT: t2.a(t2.o at [[#T2_OFFSET:]]).2.[[#%X,HEXPID]].2.[[#PID]].native.o
+MISS-NEXT: t2.a(t2.o at [[#T2_OFFSET]]).2.[[#%X,HEXPID]].2.[[#PID]].native.o.thinlto.bc
+MISS-NEXT: t2.a(t2.o at [[#T2_OFFSET]]).2.[[#%X,HEXPID]].o
+MISS-NOT: {{.}}
+
+# Second link: full cache hit.
+#
+# Both t1.o and t2.o are satisfied from the ThinLTO cache, so no backend
+# compilation runs.
+# Only the .thinlto.bc individual summary index files are produced.
+RUN: mkdir hit
+RUN: %{link} -Wl,--whole-archive t1.a t2.a -o hit/t.elf
+RUN: ls hit | sort | FileCheck %s --check-prefixes=JSON,ELF,HIT
+HIT-NEXT: t1.a(t1.o at [[#T1_OFFSET:]]).1.[[#%X,HEXPID:]].1.[[#PID:]].native.o.thinlto.bc
+HIT-NEXT: t2.a(t2.o at [[#T2_OFFSET:]]).2.[[#%X,HEXPID]].2.[[#PID]].native.o.thinlto.bc
+HIT-NOT: {{.}}
+
+# Third link: partial cache hit.
+#
+# t1.o and t2.o are cached, but the new t3.o misses the cache and imports
+# from t1.o:
+#   * t3.o must be compiled and serialized
+#   * cached t1.o must be serialized because it is imported from
+#   * cached t2.o should not be serialized or compiled (only a .thinlto.bc
+#     will be produced for it)
+RUN: %clang --target=x86_64-linux-gnu -O2 -flto=thin -c t3.c
+RUN: llvm-ar rcs t3.a t3.o
+RUN: mkdir partial
+RUN: %{link} -Wl,--whole-archive t1.a t2.a t3.a -o partial/t.elf
+RUN: ls partial | sort | FileCheck %s --check-prefixes=JSON,ELF,PARTIAL
+PARTIAL-NEXT: t1.a(t1.o at [[#T1_OFFSET:]]).1.[[#%X,HEXPID:]].1.[[#PID]].native.o.thinlto.bc
+PARTIAL-NEXT: t1.a(t1.o at [[#T1_OFFSET]]).1.[[#%X,HEXPID]].o
+PARTIAL-NEXT: t2.a(t2.o at [[#T2_OFFSET:]]).2.[[#%X,HEXPID]].2.[[#PID]].native.o.thinlto.bc
+PARTIAL-NEXT: t3.a(t3.o at [[#T3_OFFSET:]]).3.[[#%X,HEXPID]].3.[[#PID]].native.o
+PARTIAL-NEXT: t3.a(t3.o at [[#T3_OFFSET]]).3.[[#%X,HEXPID]].3.[[#PID]].native.o.thinlto.bc
+PARTIAL-NEXT: t3.a(t3.o at [[#T3_OFFSET]]).3.[[#%X,HEXPID]].o
+PARTIAL-NOT: {{.}}
+
+#--- t1.c
+__attribute__((retain)) int t1(int x) { return x; }
+
+#--- t2.c
+extern int t1(int);
+__attribute__((retain)) int t2(int x) { return t1(x) + x; }
+
+#--- t3.c
+extern int t1(int);
+__attribute__((retain)) int t3(int x) { return t1(x) + x; }
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index 445ea52e995da..4d876067f72a2 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -155,8 +155,7 @@ BitcodeCompiler::BitcodeCompiler(COFFLinkerContext &c) : ctx(c) {
   else
     ltoObj = std::make_unique<lto::DTLTO>(
         createConfig(), backend, ctx.config.ltoPartitions,
-        llvm::lto::LTO::LTOKind::LTOK_Default, ctx.config.outputFile,
-        !ctx.config.saveTempsArgs.empty());
+        llvm::lto::LTO::LTOKind::LTOK_Default, ctx.config.outputFile);
 }
 
 BitcodeCompiler::~BitcodeCompiler() = default;
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 7b0fe2001439e..50b65dc1d0821 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -217,8 +217,7 @@ BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) {
   else
     ltoObj = std::make_unique<lto::DTLTO>(
         createConfig(ctx), backend, ctx.arg.ltoPartitions,
-        ltoModes[ctx.arg.ltoKind], ctx.arg.outputFile,
-        !ctx.arg.saveTempsArgs.empty());
+        ltoModes[ctx.arg.ltoKind], ctx.arg.outputFile);
   // Initialize usedStartStop.
   if (ctx.bitcodeFiles.empty())
     return;
diff --git a/llvm/include/llvm/DTLTO/DTLTO.h b/llvm/include/llvm/DTLTO/DTLTO.h
index 5a8566b71bc16..74a7e7a71c817 100644
--- a/llvm/include/llvm/DTLTO/DTLTO.h
+++ b/llvm/include/llvm/DTLTO/DTLTO.h
@@ -10,7 +10,6 @@
 #define LLVM_DTLTO_DTLTO_H
 
 #include "llvm/LTO/LTO.h"
-#include "llvm/Support/MemoryBuffer.h"
 
 namespace llvm {
 namespace lto {
@@ -22,25 +21,31 @@ namespace lto {
 // file on disk and be loadable via its ModuleID. This requirement is not met
 // for archive members, as an archive is a collection of files rather than a
 // standalone file. Similarly, for FatLTO objects, the bitcode is stored in a
-// section of the containing ELF object file. To address this, the class ensures
-// that an individual bitcode file exists for each input (by writing it out if
-// necessary) and that the ModuleID is updated to point to it. Module IDs are
-// also normalized on Windows to remove short 8.3 form paths that cannot be
-// loaded on remote machines.
+// section of the containing ELF object file. To address this, the class
+// updates the ModuleID of such bitcode inputs to a unique temporary path to
+// which the extracted input bitcode can be written. On Windows it also
+// normalizes the paths to avoid machine-local 8.3 short names that remote
+// workers cannot reliably load.
+//
+// The bitcode is not immediately written. Instead, the class records the
+// original input buffer and lets the ThinLTO backend write the file only if
+// backend compilation is actually required. This avoids writing the file when
+// the ThinLTO object cache already satisfies the backend job.
 //
 // The class ensures that lto::InputFile objects are preserved until enough of
 // the LTO pipeline has executed to determine the required per-module
-// information, such as whether a module will participate in ThinLTO.
+// information, such as whether a module will participate in ThinLTO and to
+// allow the ThinLTO backend to write out the associated bitcode buffer.
 class DTLTO : public LTO {
   using Base = LTO;
 
 public:
   LLVM_ABI DTLTO(Config Conf, ThinBackend Backend,
                  unsigned ParallelCodeGenParallelismLevel, LTOKind LTOMode,
-                 StringRef LinkerOutputFile, bool SaveTemps)
+                 StringRef LinkerOutputFile)
       : Base(std::move(Conf), Backend, ParallelCodeGenParallelismLevel,
              LTOMode),
-        LinkerOutputFile(LinkerOutputFile), SaveTemps(SaveTemps) {
+        LinkerOutputFile(LinkerOutputFile) {
     assert(!LinkerOutputFile.empty() && "expected a valid linker output file");
   }
 
@@ -48,16 +53,8 @@ class DTLTO : public LTO {
   LLVM_ABI Expected<std::shared_ptr<InputFile>>
   addInput(std::unique_ptr<InputFile> InputPtr) override;
 
-protected:
-  // Save the contents of ThinLTO-enabled input files that must be serialized
-  // for distribution, such as archive members and FatLTO objects, to individual
-  // bitcode files named after the module ID.
-  LLVM_ABI llvm::Error serializeInputsForDistribution() override;
-
-  LLVM_ABI void cleanup() override;
-
 private:
-  // Bump allocator for a purpose of saving updated module IDs.
+  // Bump allocator for saving updated module IDs.
   BumpPtrAllocator PtrAlloc;
   StringSaver Saver{PtrAlloc};
 
@@ -67,10 +64,8 @@ class DTLTO : public LTO {
   /// The normalized output directory, derived from LinkerOutputFile.
   StringRef LinkerOutputDir;
 
-  /// Controls preservation of any created temporary files.
-  bool SaveTemps;
-
-  // Array of input bitcode files for LTO.
+  // Array of input bitcode files for LTO. We use shared_ptr here to
+  // keep InputFile objects alive whilst the ThinLTO backend is invoked.
   std::vector<std::shared_ptr<lto::InputFile>> InputFiles;
 
   // Cache of whether a path refers to a thin archive.
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index aba2661e81c47..e04a2ef8b93c1 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -22,12 +22,14 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Bitcode/BitcodeReader.h"
 #include "llvm/IR/ModuleSummaryIndex.h"
 #include "llvm/LTO/Config.h"
 #include "llvm/Object/IRSymtab.h"
 #include "llvm/Support/Caching.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/StringSaver.h"
 #include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/thread.h"
@@ -134,11 +136,6 @@ class InputFile {
 
   MemoryBufferRef MbRef;
   bool IsFatLTOObject = false;
-  // For distributed compilation, each input must exist as an individual bitcode
-  // file on disk and be identified by its ModuleID. Archive members and FatLTO
-  // objects violate this. So, in these cases we flag that the bitcode must be
-  // written out to a new standalone file.
-  bool SerializeForDistribution = false;
   bool IsThinLTO = false;
   StringRef ArchivePath;
   StringRef MemberName;
@@ -212,12 +209,6 @@ class InputFile {
   LLVM_ABI BitcodeModule &getPrimaryBitcodeModule();
   // Returns the memory buffer reference for this input file.
   MemoryBufferRef getFileBuffer() const { return MbRef; }
-  // Returns true if this input should be serialized to disk for distribution.
-  // See the comment on SerializeForDistribution for details.
-  bool getSerializeForDistribution() const { return SerializeForDistribution; }
-  // Mark whether this input should be serialized to disk for distribution.
-  // See the comment on SerializeForDistribution for details.
-  void setSerializeForDistribution(bool SFD) { SerializeForDistribution = SFD; }
   // Returns true if this bitcode came from a FatLTO object.
   bool isFatLTOObject() const { return IsFatLTOObject; }
   // Mark this bitcode as coming from a FatLTO object.
@@ -303,12 +294,15 @@ class ThinBackendProc {
 /// This callable defines the behavior of a ThinLTO backend after the thin-link
 /// phase. It accepts a configuration \p C, a combined module summary index
 /// \p CombinedIndex, a map of module identifiers to global variable summaries
-/// \p ModuleToDefinedGVSummaries, a function to add output streams \p
-/// AddStream, and a file cache \p Cache. It returns a unique pointer to a
-/// ThinBackendProc, which can be used to launch backends in parallel.
+/// \p ModuleToDefinedGVSummaries, a map of rewritten DTLTO module identifiers
+/// to input bitcode buffers \p BitcodeForDistribution, a function to add
+/// output streams \p AddStream, and a file cache \p Cache. It returns a unique
+/// pointer to a ThinBackendProc, which can be used to launch backends in
+/// parallel.
 using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
     const Config &C, ModuleSummaryIndex &CombinedIndex,
     const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+    const StringMap<MemoryBufferRef> &BitcodeForDistribution,
     AddStreamFn AddStream, FileCache Cache,
     ArrayRef<StringRef> BitcodeLibFuncs)>;
 
@@ -325,11 +319,13 @@ struct ThinBackend {
   std::unique_ptr<ThinBackendProc> operator()(
       const Config &Conf, ModuleSummaryIndex &CombinedIndex,
       const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+      const StringMap<MemoryBufferRef> &BitcodeForDistribution,
       AddStreamFn AddStream, FileCache Cache,
       ArrayRef<StringRef> BitcodeLibFuncs) {
     assert(isValid() && "Invalid backend function");
     return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
-                std::move(AddStream), std::move(Cache), BitcodeLibFuncs);
+                BitcodeForDistribution, std::move(AddStream), std::move(Cache),
+                BitcodeLibFuncs);
   }
   ThreadPoolStrategy getParallelism() const { return Parallelism; }
   bool isValid() const { return static_cast<bool>(Func); }
@@ -483,12 +479,17 @@ class LTO {
   getLibFuncSymbols(const Triple &TT, llvm::StringSaver &Saver);
 
 protected:
-  // Called at the start of run().
-  virtual Error serializeInputsForDistribution() { return Error::success(); }
-
   // Called before returning from run().
   virtual void cleanup();
 
+  // For DTLTO, some ThinLTO-enabled inputs may have their module IDs rewritten
+  // to distinct temporary filenames so the backend can reference individual
+  // bitcode files for distributed compilation. This map holds the input
+  // bitcode so the ThinLTO backend can serialize those files at the rewritten
+  // paths. Serialization is deferred until the backend determines that the
+  // compilation job is not cached.
+  StringMap<MemoryBufferRef> BitcodeForDistribution;
+
 private:
   Config Conf;
 
diff --git a/llvm/lib/DTLTO/DTLTO.cpp b/llvm/lib/DTLTO/DTLTO.cpp
index b5e233fe0ef54..1eeac4905a369 100644
--- a/llvm/lib/DTLTO/DTLTO.cpp
+++ b/llvm/lib/DTLTO/DTLTO.cpp
@@ -21,12 +21,9 @@
 #include "llvm/LTO/LTO.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
 #include "llvm/Support/TimeProfiler.h"
-#include "llvm/Support/raw_ostream.h"
 #ifdef _WIN32
 #include "llvm/Support/Windows/WindowsSupport.h"
 #endif
@@ -37,27 +34,6 @@ using namespace llvm;
 
 namespace {
 
-// Saves the content of Buffer to Path overwriting any existing file.
-Error save(StringRef Buffer, StringRef Path) {
-  std::error_code EC;
-  raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::OF_None);
-  if (EC)
-    return createStringError(inconvertibleErrorCode(),
-                             "Failed to create file %s: %s", Path.data(),
-                             EC.message().c_str());
-  OS.write(Buffer.data(), Buffer.size());
-  if (OS.has_error())
-    return createStringError(inconvertibleErrorCode(),
-                             "Failed writing to file %s", Path.data());
-  return Error::success();
-}
-
-// Saves the content of Input to Path overwriting any existing file.
-Error save(lto::InputFile *Input, StringRef Path) {
-  MemoryBufferRef MB = Input->getFileBuffer();
-  return save(MB.getBuffer(), Path);
-}
-
 // Normalize and save a path. Aside from expanding Windows 8.3 short paths,
 // no other normalization is currently required here. These paths are
 // machine-local and break distribution systems; other normalization is
@@ -150,8 +126,13 @@ Expected<bool> lto::DTLTO::isThinArchive(const StringRef ArchivePath) {
 //    (normalized on Windows) to the member file on disk.
 // 4. For archive members and FatLTO objects, overwrite the module ID with a
 //    unique path (normalized on Windows) naming a file that will contain the
-//    member content. The file is created and populated later (see
-//    serializeInputs()).
+//    member content. The file is created and populated later by the ThinLTO
+//    backend once it knows the backend compilation job is not already cached.
+// 5. To allow the ThinLTO backend to write the file contents, this function
+//    records the input file buffer and provides it to the backend (associated
+//    with the new name). If a file with that name already exists, it is likely
+//    a leftover from a previously terminated linker process and can be safely
+//    overwritten.
 Expected<std::shared_ptr<lto::InputFile>>
 lto::DTLTO::addInput(std::unique_ptr<InputFile> InputPtr) {
   TimeTraceScope TimeScope("Add input for DTLTO");
@@ -201,7 +182,6 @@ lto::DTLTO::addInput(std::unique_ptr<InputFile> InputPtr) {
   }
 
   // A new file on disk will be needed for archive members and FatLTO objects.
-  Input->setSerializeForDistribution(true);
 
   // Get the normalized output directory, if we haven't already.
   if (LinkerOutputDir.empty()) {
@@ -219,47 +199,10 @@ lto::DTLTO::addInput(std::unique_ptr<InputFile> InputPtr) {
                         std::to_string(InputFiles.size()) /*Sequence number*/ +
                         "." + utohexstr(sys::Process::getProcessId()) + ".o");
   BM.setModuleIdentifier(Saver.save(Id.str()));
-  return Input;
-}
-
-// Save the contents of ThinLTO-enabled input files that must be serialized for
-// distribution, such as archive members and FatLTO objects, to individual
-// bitcode files named after the module ID.
-//
-// Must be called after all input files are added but before optimization
-// begins. If a file with that name already exists, it is likely a leftover from
-// a previously terminated linker process and can be safely overwritten.
-llvm::Error lto::DTLTO::serializeInputsForDistribution() {
-  for (auto &Input : InputFiles) {
-    if (!Input->isThinLTO() || !Input->getSerializeForDistribution())
-      continue;
-    // Save the content of the input file to a file named after the module ID.
-    StringRef ModuleId = Input->getName();
-    TimeTraceScope TimeScope("Serialize bitcode input for DTLTO", ModuleId);
-    // Cleanup this file on abnormal process exit.
-    if (!SaveTemps)
-      llvm::sys::RemoveFileOnSignal(ModuleId);
-    if (Error EC = save(Input.get(), ModuleId))
-      return EC;
-  }
 
-  return Error::success();
-}
-
-// Remove serialized inputs created to enable distribution.
-void lto::DTLTO::cleanup() {
-  if (!SaveTemps) {
-    TimeTraceScope TimeScope("Remove temporary inputs for DTLTO");
-    for (auto &Input : InputFiles) {
-      if (!Input->getSerializeForDistribution())
-        continue;
-      std::error_code EC =
-          sys::fs::remove(Input->getName(), /*IgnoreNonExisting=*/true);
-      if (EC &&
-          EC != std::make_error_code(std::errc::no_such_file_or_directory))
-        errs() << "warning: could not remove temporary DTLTO input file '"
-               << Input->getName() << "': " << EC.message() << "\n";
-    }
-  }
-  Base::cleanup();
+  // Record the input file buffer associated with the new identifier so the
+  // ThinLTO backend can write this to the filesystem to enable backend
+  // compilation.
+  BitcodeForDistribution[BM.getModuleIdentifier()] = Input->getFileBuffer();
+  return Input;
 }
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index 95faf3484c456..4b0aa1e18bdee 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -1301,9 +1301,6 @@ Error LTO::checkPartiallySplit() {
 Error LTO::run(AddStreamFn AddStream, FileCache Cache) {
   llvm::scope_exit CleanUp([this]() { cleanup(); });
 
-  if (Error EC = serializeInputsForDistribution())
-    return EC;
-
   // Compute "dead" symbols, we don't want to import/export these!
   DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
   DenseMap<GlobalValue::GUID, PrevailingType> GUIDPrevailingResolutions;
@@ -1879,8 +1876,8 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
   auto Func =
       [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
           const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
-          AddStreamFn A...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/191142


More information about the llvm-commits mailing list