https://github.com/mgcarrasco updated 
https://github.com/llvm/llvm-project/pull/167543

>From 0c3a34136d87a2c62143dba0b1a8ceb7a81172ca Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <[email protected]>
Date: Mon, 17 Nov 2025 05:17:45 -0600
Subject: [PATCH 1/5] [NFC][clang][driver] Improve readability of long and
 complex if statement

---
 clang/lib/Driver/Driver.cpp | 67 ++++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index de8d4601210ae..d66a75c51c2cc 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -5234,50 +5234,55 @@ Action *Driver::ConstructPhaseAction(
     return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
   }
   case phases::Backend: {
+    bool IsOffloadHIP = TargetDeviceOffloadKind == Action::OFK_HIP;
+    bool IsNewOffloadDriver =
+        Args.hasFlag(options::OPT_offload_new_driver,
+                     options::OPT_no_offload_new_driver, false);
     // Skip a redundant Backend phase for HIP device code when using the new
     // offload driver, where mid-end is done in linker wrapper.
-    if (TargetDeviceOffloadKind == Action::OFK_HIP &&
-        Args.hasFlag(options::OPT_offload_new_driver,
-                     options::OPT_no_offload_new_driver, false) &&
-        !offloadDeviceOnly())
+    if (IsOffloadHIP && IsNewOffloadDriver && !offloadDeviceOnly())
       return Input;
-
-    if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) {
+    bool IsOffloadBuild = TargetDeviceOffloadKind != Action::OFK_None;
+    bool IsEmitLLVM = Args.hasArg(options::OPT_emit_llvm);
+    bool IsEmitAssembly = Args.hasArg(options::OPT_S);
+    if (isUsingLTO() && !IsOffloadBuild) {
       types::ID Output;
-      if (Args.hasArg(options::OPT_ffat_lto_objects) &&
-          !Args.hasArg(options::OPT_emit_llvm))
+      if (Args.hasArg(options::OPT_ffat_lto_objects) && !IsEmitLLVM)
         Output = types::TY_PP_Asm;
-      else if (Args.hasArg(options::OPT_S))
+      else if (IsEmitAssembly)
         Output = types::TY_LTO_IR;
       else
         Output = types::TY_LTO_BC;
       return C.MakeAction<BackendJobAction>(Input, Output);
     }
-    if (isUsingOffloadLTO() && TargetDeviceOffloadKind != Action::OFK_None) {
-      types::ID Output =
-          Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
+    if (isUsingOffloadLTO() && IsOffloadBuild) {
+      types::ID Output = IsEmitAssembly ? types::TY_LTO_IR : types::TY_LTO_BC;
       return C.MakeAction<BackendJobAction>(Input, Output);
     }
-    if (Args.hasArg(options::OPT_emit_llvm) ||
-        TargetDeviceOffloadKind == Action::OFK_SYCL ||
-        (((Input->getOffloadingToolChain() &&
-           Input->getOffloadingToolChain()->getTriple().isAMDGPU() &&
-           TargetDeviceOffloadKind != Action::OFK_None) ||
-          TargetDeviceOffloadKind == Action::OFK_HIP) &&
-         ((Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
-                        false) ||
-           (Args.hasFlag(options::OPT_offload_new_driver,
-                         options::OPT_no_offload_new_driver, false) &&
-            (!offloadDeviceOnly() ||
-             (Input->getOffloadingToolChain() &&
-              TargetDeviceOffloadKind == Action::OFK_HIP &&
-              Input->getOffloadingToolChain()->getTriple().isSPIRV())))) ||
-          TargetDeviceOffloadKind == Action::OFK_OpenMP))) {
+
+    bool IsOffloadSYCL = TargetDeviceOffloadKind == Action::OFK_SYCL;
+    auto OffloadingToolChain = Input->getOffloadingToolChain();
+    bool IsOffloadAMDGPU = OffloadingToolChain &&
+                           OffloadingToolChain->getTriple().isAMDGPU() &&
+                           IsOffloadBuild;
+    bool IsRDC =
+        Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false);
+    bool IsSPIRV =
+        OffloadingToolChain && OffloadingToolChain->getTriple().isSPIRV();
+    bool IsOffloadOpenMP = TargetDeviceOffloadKind == Action::OFK_OpenMP;
+
+    bool IsLLVMBitcodeOutput =
+        IsEmitLLVM || IsOffloadSYCL ||
+        ((IsOffloadAMDGPU || IsOffloadHIP) &&
+         ((IsRDC || (IsNewOffloadDriver &&
+                     (!offloadDeviceOnly() || (IsOffloadHIP && IsSPIRV)))) ||
+          IsOffloadOpenMP));
+
+    if (IsLLVMBitcodeOutput) {
       types::ID Output =
-          Args.hasArg(options::OPT_S) &&
-                  (TargetDeviceOffloadKind == Action::OFK_None ||
-                   offloadDeviceOnly() ||
-                   (TargetDeviceOffloadKind == Action::OFK_HIP &&
+          IsEmitAssembly &&
+                  (!IsOffloadBuild || offloadDeviceOnly() ||
+                   (IsOffloadHIP &&
                     !Args.hasFlag(options::OPT_offload_new_driver,
                                   options::OPT_no_offload_new_driver,
                                   C.isOffloadingHostKind(Action::OFK_Cuda))))

>From db0f20b8a54858042455a79c8645f50a0b7caf5b Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <[email protected]>
Date: Tue, 11 Nov 2025 07:28:56 -0600
Subject: [PATCH 2/5] [clang][Driver] Add new the -use-spirv-backend option to
 enable the SPIRV backend instead of the SPIRV translator for HIP.

---
 clang/include/clang/Options/Options.td | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 786acd6abbd21..af2931ea4fda8 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -1427,6 +1427,16 @@ def fhip_emit_relocatable : Flag<["-"], 
"fhip-emit-relocatable">,
   HelpText<"Compile HIP source to relocatable">;
 def fno_hip_emit_relocatable : Flag<["-"], "fno-hip-emit-relocatable">,
   HelpText<"Do not override toolchain to compile HIP source to relocatable">;
+def use_spirv_backend
+    : Flag<["-"], "use-spirv-backend">,
+      Group<hip_Group>,
+      Flags<[HelpHidden]>,
+      HelpText<"Use the SPIRV backend for compilation ">;
+def no_use_spirv_backend
+    : Flag<["-"], "no-use-spirv-backend">,
+      Group<hip_Group>,
+      Flags<[HelpHidden]>,
+      HelpText<"Do not use the SPIRV backend for compilation ">;
 }
 
 // Clang specific/exclusive options for OpenACC.

>From 8f86bda1bd5d286337e4a103777252cc80e99b29 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <[email protected]>
Date: Wed, 19 Nov 2025 08:49:29 -0600
Subject: [PATCH 3/5] [clang][Driver] Add test cases for SPIR-V backend support
 in the new driver.

---
 .../test/Driver/hip-spirv-backend-bindings.c  | 57 +++++++++++++
 clang/test/Driver/hip-spirv-backend-opt.c     | 55 +++++++++++++
 clang/test/Driver/hip-spirv-backend-phases.c  | 80 +++++++++++++++++++
 3 files changed, 192 insertions(+)
 create mode 100644 clang/test/Driver/hip-spirv-backend-bindings.c
 create mode 100644 clang/test/Driver/hip-spirv-backend-opt.c
 create mode 100644 clang/test/Driver/hip-spirv-backend-phases.c

diff --git a/clang/test/Driver/hip-spirv-backend-bindings.c 
b/clang/test/Driver/hip-spirv-backend-bindings.c
new file mode 100644
index 0000000000000..59b3f4fb54d4c
--- /dev/null
+++ b/clang/test/Driver/hip-spirv-backend-bindings.c
@@ -0,0 +1,57 @@
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend -ccc-print-bindings \
+// RUN: 2>&1 | FileCheck %s --check-prefixes=CHECK-SPIRV-BASE,CHECK-SPIRV
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend -fgpu-rdc -ccc-print-bindings \
+// RUN: 2>&1 | FileCheck %s --check-prefixes=CHECK-SPIRV-BASE,CHECK-SPIRV-RDC
+
+// CHECK-SPIRV-BASE: # "spirv64-amd-amdhsa" - "clang", inputs: 
["[[INPUT:.+]]"], output: "[[HIPI:.+\.hipi]]"
+// CHECK-SPIRV-BASE: # "spirv64-amd-amdhsa" - "clang", inputs: ["[[HIPI]]"], 
output: "[[SPV_BC:.+\.bc]]"
+// CHECK-SPIRV: # "spirv64-amd-amdhsa" - "Offload::Packager", inputs: 
["[[SPV_BC]]"], output: "[[HIP_OUT:.+\.out]]"
+// CHECK-SPIRV: # "spirv64-amd-amdhsa" - "Offload::Linker", inputs: 
["[[HIP_OUT]]"], output: "[[HIPFB:.+\.hipfb]]"
+// CHECK-SPIRV-RDC: # "x86_64-unknown-linux-gnu" - "Offload::Packager", 
inputs: ["[[SPV_BC]]"], output: "[[HIP_OUT:.+\.out]]"
+// CHECK-SPIRV-BASE: # "x86_64-unknown-linux-gnu" - "clang", inputs: 
["[[INPUT]]"], output: "[[HIPI:.+\.hipi]]"
+// CHECK-SPIRV: # "x86_64-unknown-linux-gnu" - "clang", inputs: ["[[HIPI]]", 
"[[HIPFB]]"], output: "[[x86_BC:.+\.bc]]"
+// CHECK-SPIRV-RDC: # "x86_64-unknown-linux-gnu" - "clang", inputs: 
["[[HIPI]]", "[[HIP_OUT]]"], output: "[[x86_BC:.+\.bc]]"
+// CHECK-SPIRV-BASE: # "x86_64-unknown-linux-gnu" - "clang", inputs: 
["[[x86_BC]]"], output: "[[x86_S:.+\.s]]"
+// CHECK-SPIRV-BASE: # "x86_64-unknown-linux-gnu" - "clang::as", inputs: 
["[[x86_S]]"], output: "[[x86_O:.+\.o]]"
+// CHECK-SPIRV-BASE: # "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: 
["[[x86_O]]"], output: "{{.+\.out}}"
+
+// CHECK-SPIRV # "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: 
["[[x86_O]]"], output: "[[x86_O:.+\.o]]"
+// CHECK-SPIRV # "x86_64-unknown-linux-gnu" - "GNU::Linker", inputs: 
["[[x86_O]]"], output: "{{.+\.out}}"
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -ccc-print-bindings \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-OFFLOAD-DEVICE-ONLY
+
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "clang", inputs: 
["[[INPUT:.+]]"], output: "[[HIPI:.+\.hipi]]"
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "clang", inputs: 
["[[HIPI]]"], output: "[[SPV_BC:.+\.bc]]"
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "clang", inputs: 
["[[SPV_BC]]"], output: "[[SPV_OUT:.+\.out]]"
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "AMDGCN::Linker", 
inputs: ["[[SPV_OUT]]"], output: "{{.+\.hipfb}}"
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -fgpu-rdc 
-ccc-print-bindings \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC
+
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: # "spirv64-amd-amdhsa" - "clang", 
inputs: ["[[INPUT:.+]]"], output: "[[HIPI:.+\.hipi]]"
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: # "spirv64-amd-amdhsa" - "clang", 
inputs: ["[[HIPI]]"], output: "[[SPV_BC:.+\.bc]]"
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: # "spirv64-amd-amdhsa" - "clang", 
inputs: ["[[SPV_BC]]"], output: "{{.+}}"
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -S -fgpu-rdc 
-ccc-print-bindings \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -S 
-ccc-print-bindings \
+// RUN: 2>&1 | FileCheck %s 
--check-prefix=CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY
+
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "clang", 
inputs: ["[[INPUT:.+]]"], output: "[[HIPI:.+\.hipi]]"
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "clang", 
inputs: ["[[HIPI]]"], output: "[[SPV_BC:.+\.bc]]"
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: # "spirv64-amd-amdhsa" - "clang", 
inputs: ["[[SPV_BC]]"], output: "{{.+\.s}}"
diff --git a/clang/test/Driver/hip-spirv-backend-opt.c 
b/clang/test/Driver/hip-spirv-backend-opt.c
new file mode 100644
index 0000000000000..d5f55f766d787
--- /dev/null
+++ b/clang/test/Driver/hip-spirv-backend-opt.c
@@ -0,0 +1,55 @@
+// This test case validates the behavior of -use-spirv-backend
+
+// --offload-device-only is always set --- testing interactions with -S and 
-fgpu-rdc
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend --offload-device-only -S \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-TEXTUAL
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend --offload-device-only \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-BINARY
+
+// The new driver's behavior is to emit LLVM IR for --offload-device-only and 
-fgpu-rdc (independently of SPIR-V).
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -### -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -S -fgpu-rdc \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-LL,CHECK-FGPU-RDC
+
+// The new driver's behavior is to emit LLVM IR for --offload-device-only and 
-fgpu-rdc (independently of SPIR-V).
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend --offload-device-only -fgpu-rdc \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-BC,CHECK-FGPU-RDC
+
+// --offload-device-only is always unset --- testing interactions with -S and 
-fgpu-rdc
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend -S -fgpu-rdc \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-BC,CHECK-FGPU-RDC
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend -S \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-BC
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend -fgpu-rdc \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-BC,CHECK-CLANG-LINKER-WRAPPER
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -### -x hip %s -save-temps  \
+// RUN:         -use-spirv-backend \
+// RUN: 2>&1 | FileCheck %s 
--check-prefixes=CHECK-SPIRV-TRANSLATOR,CHECK-SPIRV-BACKEND-BC,CHECK-CLANG-LINKER-WRAPPER
+
+// CHECK-SPIRV-TRANSLATOR-NOT: "{{.*llvm-spirv.*}}"
+// CHECK-SPIRV-BACKEND-TEXTUAL: "{{.*}}clang{{.*}}" "-cc1" "-triple" 
"spirv64-amd-amdhsa" {{.*}} "-S"
+// CHECK-SPIRV-BACKEND-BINARY: "{{.*}}clang{{.*}}" "-cc1" "-triple" 
"spirv64-amd-amdhsa" {{.*}} "-emit-obj"
+// CHECK-SPIRV-BACKEND-BC: "{{.*}}clang{{.*}}" "-cc1" "-triple" 
"spirv64-amd-amdhsa" {{.*}} "-emit-llvm-bc"
+// CHECK-SPIRV-BACKEND-LL: "{{.*}}clang{{.*}}" "-cc1" "-triple" 
"spirv64-amd-amdhsa" {{.*}} "-emit-llvm"
+// CHECK-FGPU-RDC-SAME: {{.*}} "-fgpu-rdc"
+// CHECK-CLANG-LINKER-WRAPPER: "{{.*}}clang-linker-wrapper" 
"--should-extract=amdgcnspirv" {{.*}} 
"--device-compiler=spirv64-amd-amdhsa=-use-spirv-backend"
diff --git a/clang/test/Driver/hip-spirv-backend-phases.c 
b/clang/test/Driver/hip-spirv-backend-phases.c
new file mode 100644
index 0000000000000..d743b8cd50c40
--- /dev/null
+++ b/clang/test/Driver/hip-spirv-backend-phases.c
@@ -0,0 +1,80 @@
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend -ccc-print-phases \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-BINARY
+
+// CHECK-SPIRV-BINARY: [[P0:[0-9]+]]: input, "[[INPUT:.*]].c", hip, (host-hip)
+// CHECK-SPIRV-BINARY: [[P1:[0-9]+]]: preprocessor, {[[P0]]}, hip-cpp-output, 
(host-hip)
+// CHECK-SPIRV-BINARY: [[P2:[0-9]+]]: compiler, {[[P1]]}, ir, (host-hip)
+
+// CHECK-SPIRV-BINARY: [[P3:[0-9]+]]: input, "[[INPUT]].c", hip, (device-hip, 
amdgcnspirv)
+// CHECK-SPIRV-BINARY: [[P4:[0-9]+]]: preprocessor,  {[[P3]]}, hip-cpp-output, 
(device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY: [[P5:[0-9]+]]: compiler,  {[[P4]]}, ir, (device-hip, 
amdgcnspirv)
+// CHECK-SPIRV-BINARY: [[P6:[0-9]+]]: offload,  "device-hip 
(spirv64-amd-amdhsa:amdgcnspirv)" {[[P5]]}, ir
+// CHECK-SPIRV-BINARY: [[P7:[0-9]+]]: llvm-offload-binary, {[[P6]]}, image, 
(device-hip)
+// CHECK-SPIRV-BINARY: [[P8:[0-9]+]]: clang-linker-wrapper, {[[P7]]}, 
hip-fatbin, (device-hip)
+
+// CHECK-SPIRV-BINARY: [[P9:[0-9]+]]: offload, "host-hip 
(x86_64-unknown-linux-gnu)" {[[P2]]}, "device-hip (spirv64-amd-amdhsa)" 
{[[P8]]}, ir
+// CHECK-SPIRV-BINARY: [[P10:[0-9]+]]: backend, {[[P9]]}, assembler, (host-hip)
+// CHECK-SPIRV-BINARY: [[P11:[0-9]+]]: assembler, {[[P10]]}, object, (host-hip)
+// CHECK-SPIRV-BINARY: [[P12:[0-9]+]]: clang-linker-wrapper, {[[P11]]}, image, 
(host-hip)
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend -fgpu-rdc -ccc-print-phases \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-BINARY-RDC
+
+// CHECK-SPIRV-BINARY-RDC: [[P0:[0-9]+]]: input, "[[INPUT:.*]].c", hip, 
(host-hip)
+// CHECK-SPIRV-BINARY-RDC: [[P1:[0-9]+]]: preprocessor, {[[P0]]}, 
hip-cpp-output, (host-hip)
+// CHECK-SPIRV-BINARY-RDC: [[P2:[0-9]+]]: compiler, {[[P1]]}, ir, (host-hip)
+
+// CHECK-SPIRV-BINARY-RDC: [[P3:[0-9]+]]: input, "[[INPUT]].c", hip, 
(device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-RDC: [[P4:[0-9]+]]: preprocessor,  {[[P3]]}, 
hip-cpp-output, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-RDC: [[P5:[0-9]+]]: compiler,  {[[P4]]}, ir, 
(device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-RDC: [[P6:[0-9]+]]: offload,  "device-hip 
(spirv64-amd-amdhsa:amdgcnspirv)" {[[P5]]}, ir
+// CHECK-SPIRV-BINARY-RDC: [[P7:[0-9]+]]: llvm-offload-binary, {[[P6]]}, 
image, (device-hip)
+
+// CHECK-SPIRV-BINARY-RDC: [[P8:[0-9]+]]: offload, "host-hip 
(x86_64-unknown-linux-gnu)" {[[P2]]}, "device-hip (x86_64-unknown-linux-gnu)" 
{[[P7]]}, ir
+// CHECK-SPIRV-BINARY-RDC: [[P9:[0-9]+]]: backend, {[[P8]]}, assembler, 
(host-hip)
+// CHECK-SPIRV-BINARY-RDC: [[P10:[0-9]+]]: assembler, {[[P9]]}, object, 
(host-hip)
+// CHECK-SPIRV-BINARY-RDC: [[P11:[0-9]+]]: clang-linker-wrapper, {[[P10]]}, 
image, (host-hip)
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -ccc-print-phases \
+// RUN: 2>&1 | FileCheck %s 
--check-prefix=CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY
+
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P0:[0-9]+]]: input, "{{.*}}.c", 
hip, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P1:[0-9]+]]: preprocessor, 
{[[P0]]}, hip-cpp-output, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P2:[0-9]+]]: compiler, {[[P1]]}, 
ir, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P3:[0-9]+]]: backend, {[[P2]]}, 
image, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P4:[0-9]+]]: offload, "device-hip 
(spirv64-amd-amdhsa:amdgcnspirv)" {[[P3]]}, image
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P5:[0-9]+]]: linker, {[[P4]]}, 
hip-fatbin, (device-hip)
+// CHECK-SPIRV-BINARY-OFFLOAD-DEVICE-ONLY: [[P6:[0-9]+]]: offload, "device-hip 
(spirv64-amd-amdhsa)" {[[P5]]}, none
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \ 
+// RUN:         -use-spirv-backend --offload-device-only -fgpu-rdc 
-ccc-print-phases \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC
+
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: [[P0:[0-9]+]]: input, "{{.*}}.c", hip, 
(device-hip, amdgcnspirv)
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: [[P1:[0-9]+]]: preprocessor, {[[P0]]}, 
hip-cpp-output, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: [[P2:[0-9]+]]: compiler, {[[P1]]}, ir, 
(device-hip, amdgcnspirv)
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: [[P3:[0-9]+]]: backend, {[[P2]]}, ir, 
(device-hip, amdgcnspirv)
+// CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC: [[P4:[0-9]+]]: offload, "device-hip 
(spirv64-amd-amdhsa:amdgcnspirv)" {[[P3]]}, none
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -S -fgpu-rdc 
-ccc-print-phases \
+// RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-OFFLOAD-DEVICE-ONLY-RDC
+
+// RUN: %clang --offload-new-driver --target=x86_64-unknown-linux-gnu 
--offload-arch=amdgcnspirv \
+// RUN:         -nogpuinc -nogpulib -x hip %s -save-temps \
+// RUN:         -use-spirv-backend --offload-device-only -S -ccc-print-phases \
+// RUN: 2>&1 | FileCheck %s 
--check-prefix=CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY
+
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: [[P0:[0-9]+]]: input, "{{.*}}.c", 
hip, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: [[P1:[0-9]+]]: preprocessor, 
{[[P0]]}, hip-cpp-output, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: [[P2:[0-9]+]]: compiler, {[[P1]]}, 
ir, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: [[P3:[0-9]+]]: backend, {[[P2]]}, 
assembler, (device-hip, amdgcnspirv)
+// CHECK-SPIRV-TEXTUAL-OFFLOAD-DEVICE-ONLY: [[P4:[0-9]+]]: offload, 
"device-hip (spirv64-amd-amdhsa:amdgcnspirv)" {[[P3]]}, none

>From af8f21083d0c56403305e139a910e720ad8927bd Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <[email protected]>
Date: Wed, 19 Nov 2025 08:50:55 -0600
Subject: [PATCH 4/5] [clang][Driver] Enable the SPIR-V backend for the new
 driver.

---
 clang/lib/Driver/Driver.cpp            | 42 ++++++++++++++++++++--
 clang/lib/Driver/ToolChains/Clang.cpp  | 10 +++++-
 clang/lib/Driver/ToolChains/HIPAMD.cpp | 48 +++++++++++++++++++-------
 3 files changed, 83 insertions(+), 17 deletions(-)

diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index d66a75c51c2cc..f7dfcc2936f3c 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -5024,15 +5024,24 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
     // Compiling HIP in device-only non-RDC mode requires linking each action
     // individually.
     for (Action *&A : DeviceActions) {
-      // Special handling for the HIP SPIR-V toolchain because it doesn't use
-      // the SPIR-V backend yet doesn't report the output as an object.
       bool IsAMDGCNSPIRV = A->getOffloadingToolChain() &&
                            A->getOffloadingToolChain()->getTriple().getOS() ==
                                llvm::Triple::OSType::AMDHSA &&
                            A->getOffloadingToolChain()->getTriple().isSPIRV();
+      bool UseSPIRVBackend = Args.hasFlag(options::OPT_use_spirv_backend,
+                                          options::OPT_no_use_spirv_backend,
+                                          /*Default=*/false);
+
+      // Special handling for the HIP SPIR-V toolchain in device-only.
+      // The translator path has a linking step, whereas the SPIR-V backend 
path
+      // does not to avoid any external dependency such as spirv-link. The
+      // linking step is skipped for the SPIR-V backend path.
+      bool IsAMDGCNSPIRVWithBackend = IsAMDGCNSPIRV && UseSPIRVBackend;
+
       if ((A->getType() != types::TY_Object && !IsAMDGCNSPIRV &&
            A->getType() != types::TY_LTO_BC) ||
-          HIPRelocatableObj || !HIPNoRDC || !offloadDeviceOnly())
+          HIPRelocatableObj || !HIPNoRDC || !offloadDeviceOnly() ||
+          (IsAMDGCNSPIRVWithBackend && offloadDeviceOnly()))
         continue;
       ActionList LinkerInput = {A};
       A = C.MakeAction<LinkJobAction>(LinkerInput, types::TY_Image);
@@ -5271,9 +5280,20 @@ Action *Driver::ConstructPhaseAction(
         OffloadingToolChain && OffloadingToolChain->getTriple().isSPIRV();
     bool IsOffloadOpenMP = TargetDeviceOffloadKind == Action::OFK_OpenMP;
 
+    bool IsHIP = TargetDeviceOffloadKind == Action::OFK_HIP;
+    bool UseSPIRVBackend = Args.hasFlag(options::OPT_use_spirv_backend,
+                                        options::OPT_no_use_spirv_backend,
+                                        /*Default=*/false);
+    // If offloadDeviceOnly(), we call the SPIRV backend unless LLVM bitcode 
was
+    // requested explicitly or RDC is set. If !offloadDeviceOnly, we emit LLVM
+    // bitcode, and clang-linker-wrapper will compile it to SPIRV.
+    bool UseSPIRVBackendForHipDeviceOnlyNoRDC =
+        IsHIP && IsSPIRV && UseSPIRVBackend && offloadDeviceOnly() && !IsRDC;
+
     bool IsLLVMBitcodeOutput =
         IsEmitLLVM || IsOffloadSYCL ||
         ((IsOffloadAMDGPU || IsOffloadHIP) &&
+         !UseSPIRVBackendForHipDeviceOnlyNoRDC &&
          ((IsRDC || (IsNewOffloadDriver &&
                      (!offloadDeviceOnly() || (IsOffloadHIP && IsSPIRV)))) ||
           IsOffloadOpenMP));
@@ -5290,6 +5310,22 @@ Action *Driver::ConstructPhaseAction(
               : types::TY_LLVM_BC;
       return C.MakeAction<BackendJobAction>(Input, Output);
     }
+
+    // The SPIRV backend compilation path for HIP must avoid external
+    // dependencies. The default compilation path assembles and links its
+    // output, but the SPIRV assembler and linker are external tools. This code
+    // ensures the backend emits binary SPIRV directly to bypass those steps 
and
+    // avoid failures. Without -save-temps, the compiler may already skip
+    // assembling and linking. With -save-temps, these steps must be explicitly
+    // disabled, as done here. We also force skipping these steps regardless of
+    // -save-temps to avoid relying on optimizations (unless -S is set).
+    bool IsBinarySPIRVOutput =
+        UseSPIRVBackendForHipDeviceOnlyNoRDC && !Args.hasArg(options::OPT_S);
+    if (IsBinarySPIRVOutput) {
+      // The current HIP bundling expects the type to be types::TY_Image
+      return C.MakeAction<BackendJobAction>(Input, types::TY_Image);
+    }
+
     return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
   }
   case phases::Assemble:
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..03796c7d0fe4a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5057,6 +5057,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
     Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ);
   }
 
+  bool IsAMDSPIRVForHIPDevice =
+      IsHIPDevice && getToolChain().getTriple().isSPIRV() &&
+      getToolChain().getTriple().getVendor() == llvm::Triple::AMD;
+
   if (isa<AnalyzeJobAction>(JA)) {
     assert(JA.getType() == types::TY_Plist && "Invalid output type.");
     CmdArgs.push_back("-analyze");
@@ -5154,6 +5158,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
       rewriteKind = RK_Fragile;
     } else if (JA.getType() == types::TY_CIR) {
       CmdArgs.push_back("-emit-cir");
+    } else if (JA.getType() == types::TY_Image && IsAMDSPIRVForHIPDevice) {
+      CmdArgs.push_back("-emit-obj");
     } else {
       assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
     }
@@ -9084,7 +9090,9 @@ void LinkerWrapper::ConstructJob(Compilation &C, const 
JobAction &JA,
       OPT_fno_lto,
       OPT_flto,
       OPT_flto_partitions_EQ,
-      OPT_flto_EQ};
+      OPT_flto_EQ,
+      OPT_use_spirv_backend};
+
   const llvm::DenseSet<unsigned> LinkerOptions{OPT_mllvm, OPT_Zlinker_input};
   auto ShouldForwardForToolChain = [&](Arg *A, const ToolChain &TC) {
     // Don't forward -mllvm to toolchains that don't support LLVM.
diff --git a/clang/lib/Driver/ToolChains/HIPAMD.cpp 
b/clang/lib/Driver/ToolChains/HIPAMD.cpp
index 231a38c2d3717..c7f8ca1a7f520 100644
--- a/clang/lib/Driver/ToolChains/HIPAMD.cpp
+++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp
@@ -159,10 +159,9 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, 
const JobAction &JA,
 
 // For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode
 // and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). 
It
-// calls llvm-link and then the llvm-spirv translator. Once the SPIR-V BE will
-// be promoted from experimental, we will switch to using that. TODO: consider
-// if we want to run any targeted optimisations over IR here, over generic
-// SPIR-V.
+// calls llvm-link and then the llvm-spirv translator or the SPIR-V BE.
+// TODO: consider if we want to run any targeted optimisations over IR here,
+// over generic SPIR-V.
 void AMDGCN::Linker::constructLinkAndEmitSpirvCommand(
     Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
     const InputInfo &Output, const llvm::opt::ArgList &Args) const {
@@ -173,17 +172,40 @@ void AMDGCN::Linker::constructLinkAndEmitSpirvCommand(
   const char *LinkedBCFilePath = HIP::getTempFile(C, LinkedBCFilePrefix, "bc");
   InputInfo LinkedBCFile(&JA, LinkedBCFilePath, Output.getBaseInput());
 
+  bool UseSPIRVBackend =
+      Args.hasFlag(options::OPT_use_spirv_backend,
+                   options::OPT_no_use_spirv_backend, /*Default=*/false);
+
   constructLlvmLinkCommand(C, JA, Inputs, LinkedBCFile, Args);
 
-  // Emit SPIR-V binary.
-  llvm::opt::ArgStringList TrArgs{
-      "--spirv-max-version=1.6",
-      "--spirv-ext=+all",
-      "--spirv-allow-unknown-intrinsics",
-      "--spirv-lower-const-expr",
-      "--spirv-preserve-auxdata",
-      "--spirv-debug-info-version=nonsemantic-shader-200"};
-  SPIRV::constructTranslateCommand(C, *this, JA, Output, LinkedBCFile, TrArgs);
+  if (UseSPIRVBackend) {
+    // This code handles the case in the new driver when --offload-device-only
+    // is unset and clang-linker-wrapper forwards the bitcode that must be
+    // compiled to SPIR-V.
+
+    llvm::opt::ArgStringList CmdArgs;
+    const char *Triple =
+        C.getArgs().MakeArgString("-triple=spirv64-amd-amdhsa");
+
+    CmdArgs.append({"-cc1", Triple, "-emit-obj", "-disable-llvm-optzns",
+                    LinkedBCFile.getFilename(), "-o", Output.getFilename()});
+
+    const char *Exec = getToolChain().getDriver().getClangProgramPath();
+    C.addCommand(std::make_unique<Command>(JA, *this,
+                                           ResponseFileSupport::None(), Exec,
+                                           CmdArgs, LinkedBCFile, Output));
+  } else {
+    // Emit SPIR-V binary using the translator
+    llvm::opt::ArgStringList TrArgs{
+        "--spirv-max-version=1.6",
+        "--spirv-ext=+all",
+        "--spirv-allow-unknown-intrinsics",
+        "--spirv-lower-const-expr",
+        "--spirv-preserve-auxdata",
+        "--spirv-debug-info-version=nonsemantic-shader-200"};
+    SPIRV::constructTranslateCommand(C, *this, JA, Output, LinkedBCFile,
+                                     TrArgs);
+  }
 }
 
 // For amdgcn the inputs of the linker job are device bitcode and output is

>From 46bd79cb64e9f672a7f9e995830a0be432fd1999 Mon Sep 17 00:00:00 2001
From: Manuel Carrasco <[email protected]>
Date: Wed, 19 Nov 2025 09:12:27 -0600
Subject: [PATCH 5/5] [NFC] Replace boolean variable with its expression.

---
 clang/lib/Driver/Driver.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index f7dfcc2936f3c..10a3062382280 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -5319,9 +5319,7 @@ Action *Driver::ConstructPhaseAction(
     // assembling and linking. With -save-temps, these steps must be explicitly
     // disabled, as done here. We also force skipping these steps regardless of
     // -save-temps to avoid relying on optimizations (unless -S is set).
-    bool IsBinarySPIRVOutput =
-        UseSPIRVBackendForHipDeviceOnlyNoRDC && !Args.hasArg(options::OPT_S);
-    if (IsBinarySPIRVOutput) {
+    if (UseSPIRVBackendForHipDeviceOnlyNoRDC && !Args.hasArg(options::OPT_S)) {
       // The current HIP bundling expects the type to be types::TY_Image
       return C.MakeAction<BackendJobAction>(Input, types::TY_Image);
     }

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

Reply via email to