[clang] [lld] [llvm] [DTLTO][Clang][LLD] Fix DTLTO for multi-call LLVM driver toolchain (PR #162456)

Andrew Ng via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 8 05:01:50 PDT 2025


https://github.com/nga888 updated https://github.com/llvm/llvm-project/pull/162456

>From 675020072d011527c23739e4bc4af854c147a198 Mon Sep 17 00:00:00 2001
From: Andrew Ng <andrew.ng at sony.com>
Date: Thu, 2 Oct 2025 16:31:49 +0100
Subject: [PATCH] [DTLTO][Clang][LLD] Fix DTLTO for multi-call LLVM driver
 toolchain

Add DTLTO linker option `--thinlto-remote-compiler-prepend-arg` to
enable support for the multi-call LLVM driver that requires an
additional option to specify the subcommand, e.g. "llvm clang ...".

Fixes https://github.com/llvm/llvm-project/issues/159125.
---
 clang/include/clang/Driver/CommonArgs.h    |  3 +++
 clang/lib/Driver/ToolChains/CommonArgs.cpp | 29 ++++++++++++++--------
 clang/lib/Driver/ToolChains/PS4CPU.cpp     | 11 +-------
 clang/test/Driver/DTLTO/dtlto-helper.py    | 11 ++++++++
 clang/test/Driver/DTLTO/dtlto.c            | 23 +++++++++--------
 clang/test/Driver/DTLTO/filename.py        |  4 ---
 clang/test/Driver/DTLTO/lit.local.cfg      |  3 +++
 clang/test/Driver/DTLTO/ps5-dtlto.c        | 18 ++++++++------
 lld/COFF/Config.h                          |  3 +++
 lld/COFF/Driver.cpp                        |  4 +++
 lld/COFF/LTO.cpp                           |  4 +--
 lld/COFF/Options.td                        |  3 +++
 lld/ELF/Config.h                           |  1 +
 lld/ELF/Driver.cpp                         |  2 ++
 lld/ELF/LTO.cpp                            |  3 ++-
 lld/ELF/Options.td                         |  3 +++
 lld/docs/DTLTO.rst                         | 18 ++++++++++----
 llvm/include/llvm/LTO/LTO.h                |  3 +++
 llvm/lib/LTO/LTO.cpp                       | 11 +++++++-
 llvm/test/ThinLTO/X86/dtlto/json.ll        | 20 ++++++++++++---
 llvm/tools/llvm-lto2/llvm-lto2.cpp         | 11 +++++++-
 21 files changed, 133 insertions(+), 55 deletions(-)
 create mode 100644 clang/test/Driver/DTLTO/dtlto-helper.py
 delete mode 100644 clang/test/Driver/DTLTO/filename.py
 create mode 100644 clang/test/Driver/DTLTO/lit.local.cfg

diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index 23426c0a3e02e..ac17d6211d882 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -76,6 +76,9 @@ void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
                     const JobAction &JA, const llvm::opt::ArgList &Args,
                     const InputInfo &Output, const char *OutFile);
 
+void addDTLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args,
+                     llvm::opt::ArgStringList &CmdArgs);
+
 void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args,
                    llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output,
                    const InputInfoList &Inputs, bool IsThinLTO);
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 49ee53f0ba3bf..18766042607bf 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -949,6 +949,24 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC,
   return EnableTLSDESC;
 }
 
+void tools::addDTLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
+                            llvm::opt::ArgStringList &CmdArgs) {
+  if (Arg *A = Args.getLastArg(options::OPT_fthinlto_distributor_EQ)) {
+    CmdArgs.push_back(
+        Args.MakeArgString("--thinlto-distributor=" + Twine(A->getValue())));
+    const Driver &D = ToolChain.getDriver();
+    CmdArgs.push_back(Args.MakeArgString("--thinlto-remote-compiler=" +
+                                         Twine(D.getClangProgramPath())));
+    if (auto *PA = D.getPrependArg())
+      CmdArgs.push_back(Args.MakeArgString(
+          "--thinlto-remote-compiler-prepend-arg=" + Twine(PA)));
+
+    for (const auto &A :
+         Args.getAllArgValues(options::OPT_Xthinlto_distributor_EQ))
+      CmdArgs.push_back(Args.MakeArgString("--thinlto-distributor-arg=" + A));
+  }
+}
+
 void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
                           ArgStringList &CmdArgs, const InputInfo &Output,
                           const InputInfoList &Inputs, bool IsThinLTO) {
@@ -1345,16 +1363,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
     CmdArgs.push_back(
         Args.MakeArgString(Twine(PluginOptPrefix) + "-time-passes"));
 
-  if (Arg *A = Args.getLastArg(options::OPT_fthinlto_distributor_EQ)) {
-    CmdArgs.push_back(
-        Args.MakeArgString("--thinlto-distributor=" + Twine(A->getValue())));
-    CmdArgs.push_back(
-        Args.MakeArgString("--thinlto-remote-compiler=" +
-                           Twine(ToolChain.getDriver().getClangProgramPath())));
-
-    for (auto A : Args.getAllArgValues(options::OPT_Xthinlto_distributor_EQ))
-      CmdArgs.push_back(Args.MakeArgString("--thinlto-distributor-arg=" + A));
-  }
+  addDTLTOOptions(ToolChain, Args, CmdArgs);
 }
 
 void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp
index 61afc61a53dfd..34ec65ae59602 100644
--- a/clang/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -344,16 +344,7 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
   // pass LTO options to ensure proper codegen, metadata production, etc if
   // LTO indeed occurs.
 
-  if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_distributor_EQ)) {
-    CmdArgs.push_back(
-        Args.MakeArgString("--thinlto-distributor=" + Twine(A->getValue())));
-    CmdArgs.push_back(Args.MakeArgString("--thinlto-remote-compiler=" +
-                                         Twine(D.getClangProgramPath())));
-
-    for (const auto &A :
-         Args.getAllArgValues(options::OPT_Xthinlto_distributor_EQ))
-      CmdArgs.push_back(Args.MakeArgString("--thinlto-distributor-arg=" + A));
-  }
+  tools::addDTLTOOptions(TC, Args, CmdArgs);
 
   if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto,
                    true))
diff --git a/clang/test/Driver/DTLTO/dtlto-helper.py b/clang/test/Driver/DTLTO/dtlto-helper.py
new file mode 100644
index 0000000000000..6eb9f68e43bce
--- /dev/null
+++ b/clang/test/Driver/DTLTO/dtlto-helper.py
@@ -0,0 +1,11 @@
+from pathlib import Path
+import sys
+
+# Arg 1: "clang" path.
+p = Path(sys.argv[1])
+print(f"clang-name:{p.resolve().name}")
+# Arg 2: Non-zero for LLVM driver.
+if sys.argv[2] != "0":
+    print(f'prepend-arg:"--thinlto-remote-compiler-prepend-arg={p.name}"')
+else:
+    print("prepend-arg: ")
diff --git a/clang/test/Driver/DTLTO/dtlto.c b/clang/test/Driver/DTLTO/dtlto.c
index f31b635feed96..9b4d0e025cee1 100644
--- a/clang/test/Driver/DTLTO/dtlto.c
+++ b/clang/test/Driver/DTLTO/dtlto.c
@@ -3,16 +3,18 @@
 /// Check DTLTO options are forwarded to the linker.
 
 /// Check that options are forwarded as expected with --thinlto-distributor=.
-// RUN: %python %S/filename.py %clang > %t_forward.log
+// RUN: %python %S/dtlto-helper.py %clang %llvm-driver > %t_forward.log
 // RUN: %clang -flto=thin %s -### -fuse-ld=lld --target=x86_64-linux-gnu \
 // RUN:   -Xthinlto-distributor=a1 -Xthinlto-distributor=a2,a3 \
 // RUN:   -fthinlto-distributor=d.exe -Werror >>%t_forward.log 2>&1
 // RUN: FileCheck %s --input-file=%t_forward.log --check-prefix=FORWARD
 
-// FORWARD: filename.py:[[CLANG:.*]]
-// FORWARD: ld.lld
+// FORWARD:      clang-name:[[CLANG:.*]]
+// FORWARD-NEXT: prepend-arg:[[PREPEND_ARG:.*]]
+// FORWARD:      ld.lld
 // FORWARD-SAME: "--thinlto-distributor=d.exe"
 // FORWARD-SAME: "--thinlto-remote-compiler={{[^"]*}}[[CLANG]]"
+// FORWARD-SAME: [[PREPEND_ARG]]
 // FORWARD-SAME: "--thinlto-distributor-arg=a1"
 // FORWARD-SAME: "--thinlto-distributor-arg=a2"
 // FORWARD-SAME: "--thinlto-distributor-arg=a3"
@@ -30,24 +32,25 @@
 
 /// Check the expected arguments are forwarded by default with only
 /// --thinlto-distributor=.
-// RUN: %python %S/filename.py %clang > %t_default.log
+// RUN: %python %S/dtlto-helper.py %clang %llvm-driver > %t_default.log
 // RUN: %clang -flto=thin %s -### -fuse-ld=lld --target=x86_64-linux-gnu \
 // RUN:   -fthinlto-distributor=d.exe -Werror >>%t_default.log 2>&1
 // RUN: FileCheck %s --input-file=%t_default.log --check-prefix=DEFAULT \
 // RUN:   --implicit-check-not=distributor --implicit-check-not=remote-compiler
 
-// DEFAULT: filename.py:[[CLANG:.*]]
-// DEFAULT: ld.lld
+// DEFAULT:      clang-name:[[CLANG:.*]]
+// DEFAULT-NEXT: prepend-arg:[[PREPEND_ARG:.*]]
+// DEFAULT:      ld.lld
 // DEFAULT-SAME: "--thinlto-distributor=d.exe"
 // DEFAULT-SAME: "--thinlto-remote-compiler={{[^"]*}}[[CLANG]]"
+// DEFAULT-SAME: [[PREPEND_ARG]]
 
 /// Check that nothing is forwarded when the compiler is not in LTO mode, and that
 /// appropriate unused option warnings are issued.
-// RUN: %python %S/filename.py %clang > %t_noflto.log
 // RUN: %clang %s -### -fuse-ld=lld --target=x86_64-linux-gnu \
-// RUN:   -fthinlto-distributor=d.exe  >>%t_noflto.log 2>&1
-// RUN: FileCheck %s --input-file=%t_noflto.log --check-prefix=NOFLTO \
-// RUN:   --implicit-check-not=distributor --implicit-check-not=remote-compiler
+// RUN:   -fthinlto-distributor=d.exe 2>&1 | \
+// RUN: FileCheck %s --check-prefix=NOFLTO --implicit-check-not=distributor \
+// RUN:   --implicit-check-not=remote-compiler
 
 // NOFLTO: warning: argument unused during compilation: '-fthinlto-distributor=d.exe'
 // NOFLTO: ld.lld
diff --git a/clang/test/Driver/DTLTO/filename.py b/clang/test/Driver/DTLTO/filename.py
deleted file mode 100644
index df1aeb6682543..0000000000000
--- a/clang/test/Driver/DTLTO/filename.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from pathlib import Path
-import sys
-
-print(f"filename.py:{Path(sys.argv[1]).resolve().name}")
diff --git a/clang/test/Driver/DTLTO/lit.local.cfg b/clang/test/Driver/DTLTO/lit.local.cfg
new file mode 100644
index 0000000000000..0756c5cfa11ca
--- /dev/null
+++ b/clang/test/Driver/DTLTO/lit.local.cfg
@@ -0,0 +1,3 @@
+from lit.llvm import llvm_config
+
+config.substitutions.append(("%llvm-driver", "1" if "llvm-driver" in config.available_features else "0"))
diff --git a/clang/test/Driver/DTLTO/ps5-dtlto.c b/clang/test/Driver/DTLTO/ps5-dtlto.c
index 4c10a026f944b..944088f15bc9e 100644
--- a/clang/test/Driver/DTLTO/ps5-dtlto.c
+++ b/clang/test/Driver/DTLTO/ps5-dtlto.c
@@ -3,16 +3,18 @@
 /// Check DTLTO options are forwarded to the linker.
 
 /// Check that options are forwarded as expected with --thinlto-distributor=.
-// RUN: %python %S/filename.py %clang > %t_forward.log
+// RUN: %python %S/dtlto-helper.py %clang %llvm-driver > %t_forward.log
 // RUN: %clang -flto=thin %s -### --target=x86_64-sie-ps5 \
 // RUN:   -Xthinlto-distributor=a1 -Xthinlto-distributor=a2,a3 \
 // RUN:   -fthinlto-distributor=d.exe -Werror >>%t_forward.log 2>&1
 // RUN: FileCheck %s --input-file=%t_forward.log --check-prefix=FORWARD
 
-// FORWARD: filename.py:[[CLANG:.*]]
-// FORWARD: prospero-lld
+// FORWARD:      clang-name:[[CLANG:.*]]
+// FORWARD-NEXT: prepend-arg:[[PREPEND_ARG:.*]]
+// FORWARD:      prospero-lld
 // FORWARD-SAME: "--thinlto-distributor=d.exe"
 // FORWARD-SAME: "--thinlto-remote-compiler={{[^"]*}}[[CLANG]]"
+// FORWARD-SAME: [[PREPEND_ARG]]
 // FORWARD-SAME: "--thinlto-distributor-arg=a1"
 // FORWARD-SAME: "--thinlto-distributor-arg=a2"
 // FORWARD-SAME: "--thinlto-distributor-arg=a3"
@@ -30,20 +32,22 @@
 
 /// Check the expected arguments are forwarded by default with only
 /// --thinlto-distributor=.
-// RUN: %python %S/filename.py %clang > %t_default.log
+// RUN: %python %S/dtlto-helper.py %clang %llvm-driver > %t_default.log
 // RUN: %clang -flto=thin %s -### --target=x86_64-sie-ps5 \
 // RUN:   -fthinlto-distributor=d.exe -Werror >>%t_default.log 2>&1
 // RUN: FileCheck %s --input-file=%t_default.log --check-prefix=DEFAULT \
 // RUN:   --implicit-check-not=distributor --implicit-check-not=remote-compiler
 
-// DEFAULT: filename.py:[[CLANG:.*]]
-// DEFAULT: prospero-lld
+// DEFAULT:      clang-name:[[CLANG:.*]]
+// DEFAULT-NEXT: prepend-arg:[[PREPEND_ARG:.*]]
+// DEFAULT:      prospero-lld
 // DEFAULT-SAME: "--thinlto-distributor=d.exe"
 // DEFAULT-SAME: "--thinlto-remote-compiler={{[^"]*}}[[CLANG]]"
+// DEFAULT-SAME: [[PREPEND_ARG]]
 
 /// Check that the arguments are forwarded unconditionally even when the
 /// compiler is not in LTO mode.
-// RUN: %python %S/filename.py %clang > %t_noflto.log
+// RUN: %python %S/dtlto-helper.py %clang %llvm-driver > %t_noflto.log
 // RUN: %clang %s -### --target=x86_64-sie-ps5 \
 // RUN:   -fthinlto-distributor=d.exe -Werror >>%t_noflto.log 2>&1
 // RUN: FileCheck %s --input-file=%t_noflto.log --check-prefix=DEFAULT \
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 76b7c1f61cd25..16997e4de780e 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -201,6 +201,9 @@ struct Configuration {
   // Used for /thinlto-remote-compiler:<path>
   StringRef dtltoCompiler;
 
+  // Used for /thinlto-remote-compiler-prepend-arg:<arg>
+  llvm::SmallVector<llvm::StringRef, 0> dtltoCompilerPrependArgs;
+
   // Used for /thinlto-remote-compiler-arg:<arg>
   llvm::SmallVector<llvm::StringRef, 0> dtltoCompilerArgs;
 
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 3676b8881016b..0e528de9c3652 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2113,6 +2113,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
     Err(ctx) << "A value must be specified for /thinlto-remote-compiler if "
                 "/thinlto-distributor is specified.";
 
+  // Handle /thinlto-remote-compiler-prepend-arg:<arg>
+  config->dtltoCompilerPrependArgs =
+      args::getStrings(args, OPT_thinlto_remote_compiler_prepend_arg);
+
   // Handle /thinlto-remote-compiler-arg:<arg>
   config->dtltoCompilerArgs =
       args::getStrings(args, OPT_thinlto_remote_compiler_arg);
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index a988be610864a..b1efb28347f74 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -118,8 +118,8 @@ BitcodeCompiler::BitcodeCompiler(COFFLinkerContext &c) : ctx(c) {
         /*ShouldEmitIndexFiles=*/false,
         /*ShouldEmitImportFiles=*/false, ctx.config.outputFile,
         ctx.config.dtltoDistributor, ctx.config.dtltoDistributorArgs,
-        ctx.config.dtltoCompiler, ctx.config.dtltoCompilerArgs,
-        !ctx.config.saveTempsArgs.empty());
+        ctx.config.dtltoCompiler, ctx.config.dtltoCompilerPrependArgs,
+        ctx.config.dtltoCompilerArgs, !ctx.config.saveTempsArgs.empty());
   } else if (ctx.config.thinLTOIndexOnly) {
     auto OnIndexWrite = [&](StringRef S) { thinIndices.erase(S); };
     backend = lto::createWriteIndexesThinBackend(
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index f3d0eb3356200..d77478fc9c987 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -292,6 +292,9 @@ def thinlto_distributor_arg : P<"thinlto-distributor-arg",
 def thinlto_remote_compiler : P<"thinlto-remote-compiler",
   "Compiler for the ThinLTO distributor to invoke for ThinLTO backend "
   "compilations">;
+def thinlto_remote_compiler_prepend_arg : P<"thinlto-remote-compiler-prepend-arg",
+  "Compiler prepend arguments for the ThinLTO distributor to pass for ThinLTO backend "
+  "compilations">;
 def thinlto_remote_compiler_arg : P<"thinlto-remote-compiler-arg",
   "Compiler arguments for the ThinLTO distributor to pass for ThinLTO backend "
   "compilations">;
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index fd57967a1d21f..8ec5a2c04e71c 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -278,6 +278,7 @@ struct Config {
   llvm::StringRef dtltoDistributor;
   llvm::SmallVector<llvm::StringRef, 0> dtltoDistributorArgs;
   llvm::StringRef dtltoCompiler;
+  llvm::SmallVector<llvm::StringRef, 0> dtltoCompilerPrependArgs;
   llvm::SmallVector<llvm::StringRef, 0> dtltoCompilerArgs;
   llvm::SmallVector<llvm::StringRef, 0> undefined;
   llvm::SmallVector<SymbolVersion, 0> dynamicList;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 62f7fffce7dbe..e52d3a0e11113 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1400,6 +1400,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
   ctx.arg.dtltoDistributorArgs =
       args::getStrings(args, OPT_thinlto_distributor_arg);
   ctx.arg.dtltoCompiler = args.getLastArgValue(OPT_thinlto_remote_compiler_eq);
+  ctx.arg.dtltoCompilerPrependArgs =
+      args::getStrings(args, OPT_thinlto_remote_compiler_prepend_arg);
   ctx.arg.dtltoCompilerArgs =
       args::getStrings(args, OPT_thinlto_remote_compiler_arg);
   ctx.arg.dwoDir = args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq);
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 8d4a6c9e3a81e..80c6d2482f9fa 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -186,7 +186,8 @@ BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) {
         ctx.arg.thinLTOEmitIndexFiles, ctx.arg.thinLTOEmitImportsFiles,
         ctx.arg.outputFile, ctx.arg.dtltoDistributor,
         ctx.arg.dtltoDistributorArgs, ctx.arg.dtltoCompiler,
-        ctx.arg.dtltoCompilerArgs, !ctx.arg.saveTempsArgs.empty());
+        ctx.arg.dtltoCompilerPrependArgs, ctx.arg.dtltoCompilerArgs,
+        !ctx.arg.saveTempsArgs.empty());
   } else {
     backend = lto::createInProcessThinBackend(
         llvm::heavyweight_hardware_concurrency(ctx.arg.thinLTOJobs),
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 0d6dda4b60d3a..75184de496448 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -725,6 +725,9 @@ defm thinlto_distributor_arg: EEq<"thinlto-distributor-arg", "Arguments to "
 def thinlto_remote_compiler_eq: JJ<"thinlto-remote-compiler=">,
   HelpText<"Compiler for the ThinLTO distributor to invoke for ThinLTO backend "
   "compilations">;
+defm thinlto_remote_compiler_prepend_arg: EEq<"thinlto-remote-compiler-prepend-arg",
+  "Compiler prepend arguments for the ThinLTO distributor to pass for ThinLTO backend "
+  "compilations">;
 defm thinlto_remote_compiler_arg: EEq<"thinlto-remote-compiler-arg",
   "Compiler arguments for the ThinLTO distributor to pass for ThinLTO backend "
   "compilations">;
diff --git a/lld/docs/DTLTO.rst b/lld/docs/DTLTO.rst
index 54fcc034d1371..bec24e6fab2c6 100644
--- a/lld/docs/DTLTO.rst
+++ b/lld/docs/DTLTO.rst
@@ -14,19 +14,23 @@ ELF LLD
 
 The command-line interface is as follows:
 
-- ``--thinlto-distributor=<path>``  
+- ``--thinlto-distributor=<path>``
   Specifies the file to execute as the distributor process. If specified,
   ThinLTO backend compilations will be distributed.
 
-- ``--thinlto-remote-compiler=<path>``  
+- ``--thinlto-remote-compiler=<path>``
   Specifies the path to the compiler that the distributor process will use for
   backend compilations. The compiler invoked must match the version of LLD.
 
-- ``--thinlto-distributor-arg=<arg>``  
+- ``--thinlto-distributor-arg=<arg>``
   Specifies ``<arg>`` on the command line when invoking the distributor.
   Can be specified multiple times.
 
-- ``--thinlto-remote-compiler-arg=<arg>``  
+- ``--thinlto-remote-compiler-prepend-arg=<arg>``
+  Prepends ``<arg>`` to the remote compiler's command line.
+  Can be specified multiple times.
+
+- ``--thinlto-remote-compiler-arg=<arg>``
   Appends ``<arg>`` to the remote compiler's command line.
   Can be specified multiple times.
 
@@ -57,6 +61,10 @@ The command-line interface is as follows:
   Specifies ``<arg>`` on the command line when invoking the distributor.
   Can be specified multiple times.
 
+- ``/thinlto-remote-compiler-prepend-arg:<arg>``
+  Prepends ``<arg>`` to the remote compiler's command line.
+  Can be specified multiple times.
+
 - ``/thinlto-remote-compiler-arg:<arg>``
   Appends ``<arg>`` to the remote compiler's command line.
   Can be specified multiple times.
@@ -72,4 +80,4 @@ Currently, other options are silently accepted but do not have the intended
 effect. Support for such options could be expanded in the future.
 
 Currently, there is no DTLTO command line interface supplied for ``clang-cl``,
-as users are expected to invoke LLD directly.
\ No newline at end of file
+as users are expected to invoke LLD directly.
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index 3a9a7f7c25859..3a753fef54b5a 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -323,6 +323,8 @@ LLVM_ABI ThinBackend createInProcessThinBackend(
 /// distributor.
 /// RemoteCompiler specifies the path to a Clang executable to be invoked for
 /// the backend jobs.
+/// RemoteCompilerPrependArgs specifies a list of prepend arguments to be
+/// applied to the backend compilations.
 /// RemoteCompilerArgs specifies a list of arguments to be applied to the
 /// backend compilations.
 /// SaveTemps is a debugging tool that prevents temporary files created by this
@@ -332,6 +334,7 @@ LLVM_ABI ThinBackend createOutOfProcessThinBackend(
     bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
     StringRef LinkerOutputFile, StringRef Distributor,
     ArrayRef<StringRef> DistributorArgs, StringRef RemoteCompiler,
+    ArrayRef<StringRef> RemoteCompilerPrependArgs,
     ArrayRef<StringRef> RemoteCompilerArgs, bool SaveTemps);
 
 /// This ThinBackend writes individual module indexes to files, instead of
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index e6544f3bafff4..0acba09f8661f 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -2252,6 +2252,7 @@ class OutOfProcessThinBackend : public CGThinBackend {
   ArrayRef<StringRef> DistributorArgs;
 
   SString RemoteCompiler;
+  ArrayRef<StringRef> RemoteCompilerPrependArgs;
   ArrayRef<StringRef> RemoteCompilerArgs;
 
   bool SaveTemps;
@@ -2288,12 +2289,14 @@ class OutOfProcessThinBackend : public CGThinBackend {
       bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
       StringRef LinkerOutputFile, StringRef Distributor,
       ArrayRef<StringRef> DistributorArgs, StringRef RemoteCompiler,
+      ArrayRef<StringRef> RemoteCompilerPrependArgs,
       ArrayRef<StringRef> RemoteCompilerArgs, bool SaveTemps)
       : CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
                       AddStream, OnWrite, ShouldEmitIndexFiles,
                       ShouldEmitImportsFiles, ThinLTOParallelism),
         LinkerOutputFile(LinkerOutputFile), DistributorPath(Distributor),
         DistributorArgs(DistributorArgs), RemoteCompiler(RemoteCompiler),
+        RemoteCompilerPrependArgs(RemoteCompilerPrependArgs),
         RemoteCompilerArgs(RemoteCompilerArgs), SaveTemps(SaveTemps) {}
 
   virtual void setup(unsigned ThinLTONumTasks, unsigned ThinLTOTaskOffset,
@@ -2415,6 +2418,11 @@ class OutOfProcessThinBackend : public CGThinBackend {
         JOS.attributeArray("args", [&]() {
           JOS.value(RemoteCompiler);
 
+          // Forward any supplied prepend options.
+          if (!RemoteCompilerPrependArgs.empty())
+            for (auto &A : RemoteCompilerPrependArgs)
+              JOS.value(A);
+
           JOS.value("-c");
 
           JOS.value(Saver.save("--target=" + Triple.str()));
@@ -2545,6 +2553,7 @@ ThinBackend lto::createOutOfProcessThinBackend(
     bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
     StringRef LinkerOutputFile, StringRef Distributor,
     ArrayRef<StringRef> DistributorArgs, StringRef RemoteCompiler,
+    ArrayRef<StringRef> RemoteCompilerPrependArgs,
     ArrayRef<StringRef> RemoteCompilerArgs, bool SaveTemps) {
   auto Func =
       [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
@@ -2554,7 +2563,7 @@ ThinBackend lto::createOutOfProcessThinBackend(
             Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
             AddStream, OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles,
             LinkerOutputFile, Distributor, DistributorArgs, RemoteCompiler,
-            RemoteCompilerArgs, SaveTemps);
+            RemoteCompilerPrependArgs, RemoteCompilerArgs, SaveTemps);
       };
   return ThinBackend(Func, Parallelism);
 }
diff --git a/llvm/test/ThinLTO/X86/dtlto/json.ll b/llvm/test/ThinLTO/X86/dtlto/json.ll
index 1a38438e7b791..ee1c428c31c7c 100644
--- a/llvm/test/ThinLTO/X86/dtlto/json.ll
+++ b/llvm/test/ThinLTO/X86/dtlto/json.ll
@@ -7,21 +7,33 @@ RUN: rm -rf %t && split-file %s %t && cd %t
 RUN: opt -thinlto-bc t1.ll -o t1.bc
 RUN: opt -thinlto-bc t2.ll -o t2.bc
 
-; Perform DTLTO.
+; Perform DTLTO with clang.
 RUN: not llvm-lto2 run t1.bc t2.bc -o my.output \
 RUN:     -r=t1.bc,t1,px -r=t2.bc,t2,px \
 RUN:     -dtlto-distributor=%python \
 RUN:     -dtlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py,--da1=10,--da2=10 \
 RUN:     -dtlto-compiler=my_clang.exe \
 RUN:     -dtlto-compiler-arg=--rota1=10,--rota2=20 \
-RUN:   2>&1 | FileCheck %s
+RUN:   2>&1 | FileCheck --check-prefixes=CHECK,CLANG %s
+
+; Perform DTLTO with LLVM driver.
+RUN: not llvm-lto2 run t1.bc t2.bc -o my.output \
+RUN:     -r=t1.bc,t1,px -r=t2.bc,t2,px \
+RUN:     -dtlto-distributor=%python \
+RUN:     -dtlto-distributor-arg=%llvm_src_root/utils/dtlto/validate.py,--da1=10,--da2=10 \
+RUN:     -dtlto-compiler=llvm \
+RUN:     -dtlto-compiler-prepend-arg=clang \
+RUN:     -dtlto-compiler-arg=--rota1=10,--rota2=20 \
+RUN:   2>&1 | FileCheck --check-prefixes=CHECK,LLVM %s
 
 CHECK: distributor_args=['--da1=10', '--da2=10']
 
 ; Check the common object.
 CHECK:      "linker_output": "my.output"
 CHECK:      "args":
-CHECK-NEXT: "my_clang.exe"
+CLANG-NEXT: "my_clang.exe"
+LLVM-NEXT:  "llvm"
+LLVM-NEXT:  "clang"
 CHECK-NEXT: "-c"
 CHECK-NEXT: "--target=x86_64-unknown-linux-gnu"
 CHECK-NEXT: "-O2"
@@ -30,7 +42,7 @@ CHECK-NEXT: "-Wno-unused-command-line-argument"
 CHECK-NEXT: "--rota1=10"
 CHECK-NEXT: "--rota2=20"
 CHECK-NEXT: ]
-CHECK: "inputs": []
+CHECK:      "inputs": []
 
 ; Check the first job entry.
 CHECK:      "args":
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index ff75bb564b1e8..399306f39daeb 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -111,6 +111,12 @@ static cl::opt<std::string> DTLTOCompiler(
     "dtlto-compiler",
     cl::desc("Compiler to use for DTLTO ThinLTO backend compilations."));
 
+static cl::list<std::string> DTLTOCompilerPrependArgs(
+    "dtlto-compiler-prepend-arg", cl::CommaSeparated,
+    cl::desc("Prepend arguments to pass to the remote compiler for backend "
+             "compilations."),
+    cl::value_desc("arg"));
+
 static cl::list<std::string> DTLTOCompilerArgs(
     "dtlto-compiler-arg", cl::CommaSeparated,
     cl::desc("Arguments to pass to the remote compiler for backend "
@@ -371,6 +377,9 @@ static int run(int argc, char **argv) {
                     "with -dtlto-distributor\n";
   auto DTLTODistributorArgsSV = llvm::to_vector<0>(llvm::map_range(
       DTLTODistributorArgs, [](const std::string &S) { return StringRef(S); }));
+  auto DTLTOCompilerPrependArgsSV = llvm::to_vector<0>(
+      llvm::map_range(DTLTOCompilerPrependArgs,
+                      [](const std::string &S) { return StringRef(S); }));
   auto DTLTOCompilerArgsSV = llvm::to_vector<0>(llvm::map_range(
       DTLTOCompilerArgs, [](const std::string &S) { return StringRef(S); }));
 
@@ -388,7 +397,7 @@ static int run(int argc, char **argv) {
         llvm::heavyweight_hardware_concurrency(Threads),
         /*OnWrite=*/{}, ThinLTOEmitIndexes, ThinLTOEmitImports, OutputFilename,
         DTLTODistributor, DTLTODistributorArgsSV, DTLTOCompiler,
-        DTLTOCompilerArgsSV, SaveTemps);
+        DTLTOCompilerPrependArgsSV, DTLTOCompilerArgsSV, SaveTemps);
   } else
     Backend = createInProcessThinBackend(
         llvm::heavyweight_hardware_concurrency(Threads),



More information about the llvm-commits mailing list