https://github.com/jhuber6 updated 
https://github.com/llvm/llvm-project/pull/224446

>From a217f89d53671c82d6aff719d1812497b4f1ad70 Mon Sep 17 00:00:00 2001
From: Joseph Huber <[email protected]>
Date: Thu, 17 Sep 2026 16:41:01 -0500
Subject: [PATCH 1/3] [ClangLinkerWrapper] Emit extra job to generate
 -save-temps assembly

Summary:
This is an oft-requested feature and unfortunately cannot be done
easily. The approach is just to make a redundant job that does the same
handling, but emits an `--lto-emit-asm` job in the background. Ideally
these get enough parallelism that the total compile time doesn't change
much.

I cannot find a cleaner way to return the 'old driver behavior' for
emitting assembly as was requested. THe LTO pipeline is not built to
generate intermediate files like this, and running this *then* consuming
the assembly on output would break thinLTO, partitioned LTO, or future
object linking.
---
 .../clang-linker-wrapper/linker-wrapper.c     |  6 +++
 .../ClangLinkerWrapper.cpp                    | 45 +++++++++++++++----
 2 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index 550cab4b0604d..11f03e663edbf 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -51,6 +51,12 @@ __attribute__((visibility("protected"), used)) int x;
 
 // AMDGPU-LTO-TEMPS: clang{{.*}} --target=amdgpu10.30-amd-amdhsa -mcpu=gfx1030 
{{.*}}-save-temps
 
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run 
--save-temps \
+// RUN:   --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s 
--check-prefix=AMDGPU-SAVE-TEMPS-ASM
+
+// AMDGPU-SAVE-TEMPS-ASM-DAG: clang{{.*}} --target=amdgpu10.30-amd-amdhsa 
-mcpu=gfx1030 {{.*}}-Wl,--save-temps{{$}}
+// AMDGPU-SAVE-TEMPS-ASM-DAG: clang{{.*}} --target=amdgpu10.30-amd-amdhsa 
-mcpu=gfx1030 {{.*}}-Xlinker --lto-emit-asm
+
 // RUN: llvm-offload-binary -o %t.out \
 // RUN:   
--image=file=%t.spirv.bc,kind=sycl,triple=spirv64-unknown-unknown,arch=foo
 // RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o 
-fembed-offload-object=%t.out
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 59faf38dda140..1ac27a75e990b 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -241,20 +241,34 @@ Expected<StringRef> createOutputFile(const Twine &Prefix, 
StringRef Extension) {
 }
 
 /// Execute the command \p ExecutablePath with the arguments \p Args.
-Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args) {
+/// If \p Proc is set, launch without waiting and store the process handle.
+Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args,
+                      sys::ProcessInfo *Proc = nullptr) {
   if (Verbose || DryRun)
     printCommands(Args);
 
   if (DryRun)
     return Error::success();
 
-  // If the command line fits within system limits, execute directly.
-  if (sys::commandLineFitsWithinSystemLimits(ExecutablePath, Args)) {
-    if (sys::ExecuteAndWait(ExecutablePath, Args))
+  auto Launch = [&](ArrayRef<StringRef> ExecArgs) -> Error {
+    if (Proc) {
+      bool ExecutionFailed = false;
+      *Proc = sys::ExecuteNoWait(ExecutablePath, ExecArgs, std::nullopt, {}, 0,
+                                 nullptr, &ExecutionFailed);
+      if (ExecutionFailed)
+        return createStringError(
+            "'%s' failed", sys::path::filename(ExecutablePath).str().c_str());
+      return Error::success();
+    }
+    if (sys::ExecuteAndWait(ExecutablePath, ExecArgs))
       return createStringError(
           "'%s' failed", sys::path::filename(ExecutablePath).str().c_str());
     return Error::success();
-  }
+  };
+
+  // If the command line fits within system limits, execute directly.
+  if (sys::commandLineFitsWithinSystemLimits(ExecutablePath, Args))
+    return Launch(Args);
 
   // Write the arguments to a response file and pass that instead.
   auto TempFileOrErr = createOutputFile("response", "rsp");
@@ -274,10 +288,7 @@ Error executeCommands(StringRef ExecutablePath, 
ArrayRef<StringRef> Args) {
 
   std::string ResponseFile = ("@" + *TempFileOrErr).str();
   SmallVector<StringRef, 2> NewArgs = {Args.front(), ResponseFile};
-  if (sys::ExecuteAndWait(ExecutablePath, NewArgs))
-    return createStringError("'%s' failed",
-                             
sys::path::filename(ExecutablePath).str().c_str());
-  return Error::success();
+  return Launch(NewArgs);
 }
 
 Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) {
@@ -624,9 +635,25 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args,
   for (StringRef Arg : Args.getAllArgValues(OPT_compiler_arg_EQ))
     CmdArgs.push_back(Args.MakeArgString(Arg));
 
+  // We cannot generate temporary assembly files to satisfy `--save-temps`
+  // through the LTO pipeline. Launch a separate clang job to emit the file.
+  sys::ProcessInfo AsmProc;
+  if (SaveTemps && Triple.isAMDGPU()) {
+    SmallVector<StringRef, 16> AsmArgs(CmdArgs);
+    AsmArgs.append({"-Xlinker", "--lto-emit-asm"});
+    if (Error Err = executeCommands(*ClangPath, AsmArgs, &AsmProc))
+      return std::move(Err);
+  }
+
   if (Error Err = executeCommands(*ClangPath, CmdArgs))
     return std::move(Err);
 
+  if (SaveTemps && Triple.isAMDGPU() && !DryRun) {
+    if (sys::Wait(AsmProc, std::nullopt).ReturnCode)
+      return createStringError("'%s' failed",
+                               sys::path::filename(*ClangPath).str().c_str());
+  }
+
   return *TempFileOrErr;
 }
 } // namespace generic

>From 00956d20b1268d68b0194c03534436c71fbe9b45 Mon Sep 17 00:00:00 2001
From: Joseph Huber <[email protected]>
Date: Thu, 17 Sep 2026 22:47:51 -0500
Subject: [PATCH 2/3] remove

---
 clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c | 2 +-
 clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp       | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index 11f03e663edbf..b092052cabb9e 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -55,7 +55,7 @@ __attribute__((visibility("protected"), used)) int x;
 // RUN:   --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s 
--check-prefix=AMDGPU-SAVE-TEMPS-ASM
 
 // AMDGPU-SAVE-TEMPS-ASM-DAG: clang{{.*}} --target=amdgpu10.30-amd-amdhsa 
-mcpu=gfx1030 {{.*}}-Wl,--save-temps{{$}}
-// AMDGPU-SAVE-TEMPS-ASM-DAG: clang{{.*}} --target=amdgpu10.30-amd-amdhsa 
-mcpu=gfx1030 {{.*}}-Xlinker --lto-emit-asm
+// AMDGPU-SAVE-TEMPS-ASM-DAG: clang{{.*}} --target=amdgpu10.30-amd-amdhsa 
-mcpu=gfx1030 {{.*}}-Xlinker --lto-emit-asm{{$}}
 
 // RUN: llvm-offload-binary -o %t.out \
 // RUN:   
--image=file=%t.spirv.bc,kind=sycl,triple=spirv64-unknown-unknown,arch=foo
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 1ac27a75e990b..d2f277f180de7 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -640,6 +640,7 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args,
   sys::ProcessInfo AsmProc;
   if (SaveTemps && Triple.isAMDGPU()) {
     SmallVector<StringRef, 16> AsmArgs(CmdArgs);
+    llvm::erase(AsmArgs, "-Wl,--save-temps");
     AsmArgs.append({"-Xlinker", "--lto-emit-asm"});
     if (Error Err = executeCommands(*ClangPath, AsmArgs, &AsmProc))
       return std::move(Err);

>From deb561cf571c321aa8a4dfe160fed08acd74148c Mon Sep 17 00:00:00 2001
From: Joseph Huber <[email protected]>
Date: Fri, 18 Sep 2026 09:01:08 -0500
Subject: [PATCH 3/3] address comment

---
 .../clang-linker-wrapper/ClangLinkerWrapper.cpp      | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index d2f277f180de7..a0eee34df6c22 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -646,14 +646,14 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, 
const ArgList &Args,
       return std::move(Err);
   }
 
-  if (Error Err = executeCommands(*ClangPath, CmdArgs))
-    return std::move(Err);
-
+  Error Err = executeCommands(*ClangPath, CmdArgs);
   if (SaveTemps && Triple.isAMDGPU() && !DryRun) {
-    if (sys::Wait(AsmProc, std::nullopt).ReturnCode)
-      return createStringError("'%s' failed",
-                               sys::path::filename(*ClangPath).str().c_str());
+    if (sys::Wait(AsmProc, std::nullopt).ReturnCode && !Err)
+      Err = createStringError("'%s' failed",
+                              sys::path::filename(*ClangPath).str().c_str());
   }
+  if (Err)
+    return std::move(Err);
 
   return *TempFileOrErr;
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to