Skip to content

Conversation

nga888
Copy link
Collaborator

@nga888 nga888 commented Oct 8, 2025

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 #159125.

@llvmbot llvmbot added clang Clang issues not falling into any other category lld clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' lld:ELF lld:COFF platform:windows LTO Link time optimization (regular/full LTO or ThinLTO) labels Oct 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 8, 2025

@llvm/pr-subscribers-lld
@llvm/pr-subscribers-lto
@llvm/pr-subscribers-lld-coff
@llvm/pr-subscribers-lld-elf

@llvm/pr-subscribers-clang

Author: Andrew Ng (nga888)

Changes

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 #159125.


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

21 Files Affected:

  • (modified) clang/include/clang/Driver/CommonArgs.h (+3)
  • (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+19-10)
  • (modified) clang/lib/Driver/ToolChains/PS4CPU.cpp (+1-10)
  • (added) clang/test/Driver/DTLTO/dtlto-helper.py (+11)
  • (modified) clang/test/Driver/DTLTO/dtlto.c (+13-10)
  • (removed) clang/test/Driver/DTLTO/filename.py (-4)
  • (added) clang/test/Driver/DTLTO/lit.local.cfg (+3)
  • (modified) clang/test/Driver/DTLTO/ps5-dtlto.c (+11-7)
  • (modified) lld/COFF/Config.h (+3)
  • (modified) lld/COFF/Driver.cpp (+4)
  • (modified) lld/COFF/LTO.cpp (+2-2)
  • (modified) lld/COFF/Options.td (+3)
  • (modified) lld/ELF/Config.h (+1)
  • (modified) lld/ELF/Driver.cpp (+2)
  • (modified) lld/ELF/LTO.cpp (+2-1)
  • (modified) lld/ELF/Options.td (+3)
  • (modified) lld/docs/DTLTO.rst (+13-5)
  • (modified) llvm/include/llvm/LTO/LTO.h (+3)
  • (modified) llvm/lib/LTO/LTO.cpp (+10-1)
  • (modified) llvm/test/ThinLTO/X86/dtlto/json.ll (+16-4)
  • (modified) llvm/tools/llvm-lto2/llvm-lto2.cpp (+10-1)
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..076c466527351
--- /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(DistributorA...
[truncated]

Copy link

github-actions bot commented Oct 8, 2025

✅ With the latest revision this PR passed the Python code formatter.

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 llvm#159125.
@nga888 nga888 force-pushed the fix-multi-call-dtlto-159125 branch from bfb955c to 6750200 Compare October 8, 2025 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category lld:COFF lld:ELF lld LTO Link time optimization (regular/full LTO or ThinLTO) platform:windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DTLTO] Clang driver broken with the multicall toolchain executable

2 participants