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
