[clang] [llvm] [HIPSPV] Add in-tree SPIR-V backend support for chipStar (PR #186972)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 17 01:10:04 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-spir-v
Author: Paulius Velesko (pvelesko)
<details>
<summary>Changes</summary>
## Summary
chipStar (https://github.com/CHIP-SPV/chipStar) enables HIP/CUDA programs to run on OpenCL and Level Zero devices via SPIR-V. Until now, the HIPSPV toolchain relied exclusively on the external `llvm-spirv` translator for bitcode-to-SPIR-V conversion.
This patch adds native in-tree SPIR-V backend support for chipStar targets (`spirv64*-unknown-chipstar`), removing the hard dependency on `llvm-spirv`.
### Changes
**HIPSPV old driver (`HIPSPV.cpp`):**
- chipStar targets now use `opt` (HipSpvPasses) + `clang -c` (SPIR-V backend) instead of `opt` + `llvm-spirv`
- Non-chipStar HIPSPV targets continue using `llvm-spirv` unchanged
- Remove `HostTC->addClangTargetOptions()` delegation to avoid macOS Darwin flags (`-faligned-alloc-unavailable`) breaking SPIR-V device compilation
**New offload driver (`ClangLinkerWrapper.cpp`):**
- Add chipStar SPIR-V pipeline: `llvm-link` → `opt` (HipSpvPasses) → `clang -c --target=spirv64` with SPIR-V extensions
- Extract `--hip-path` from `--device-compiler=` args for locating the HipSpvPasses plugin and device libraries
- Fall back to `llvm-spirv` translator when available for non-chipStar SPIR-V targets
**SPIR-V toolchain (`SPIRV.cpp`):**
- Enable `NativeLLVMSupport` for chipStar triples so the toolchain does not require an external translator
**SPIR-V backend (`SPIRVSubtarget.cpp`):**
- Set `Kernel` environment for chipStar triples (needed for OpenCL kernel ABI)
**`AlignedAllocation.h`:**
- Add `ChipStar` case to avoid unhandled enum warning
## Test plan
- [ ] `hipspv-toolchain.hip` driver test updated to verify the new in-tree backend pipeline
- [ ] chipStar test suite: 1173/1173 tests pass (100%) on the translator path; 1169/1173 (99.7%) on the native in-tree backend (4 remaining printf failures due to upstream `ExpandVariadics` regression in LLVM 23)
---
Patch is 21.95 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/186972.diff
6 Files Affected:
- (modified) clang/include/clang/Basic/AlignedAllocation.h (+2)
- (modified) clang/lib/Driver/ToolChains/HIPSPV.cpp (+58-25)
- (modified) clang/lib/Driver/ToolChains/SPIRV.cpp (+2-1)
- (modified) clang/test/Driver/hipspv-toolchain.hip (+43-13)
- (modified) clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp (+194-5)
- (modified) llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp (+2-1)
``````````diff
diff --git a/clang/include/clang/Basic/AlignedAllocation.h b/clang/include/clang/Basic/AlignedAllocation.h
index ac26eb4a276da..9b84d07286d52 100644
--- a/clang/include/clang/Basic/AlignedAllocation.h
+++ b/clang/include/clang/Basic/AlignedAllocation.h
@@ -35,6 +35,8 @@ inline llvm::VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) {
return llvm::VersionTuple(4U);
case llvm::Triple::ZOS:
return llvm::VersionTuple(); // All z/OS versions have no support.
+ case llvm::Triple::ChipStar:
+ return llvm::VersionTuple(); // No version constraint for device targets.
}
llvm_unreachable("Unexpected OS");
diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp
index 8bdb7ab042b2b..70f831c3ade87 100644
--- a/clang/lib/Driver/ToolChains/HIPSPV.cpp
+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp
@@ -72,10 +72,56 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand(
tools::constructLLVMLinkCommand(C, *this, JA, Inputs, LinkArgs, Output, Args,
TempFile);
- // Post-link HIP lowering.
+ auto T = getToolChain().getTriple();
+
+ if (T.getOS() == llvm::Triple::ChipStar) {
+ // chipStar: run HipSpvPasses via opt, then use the in-tree SPIR-V backend
+ // for codegen (replaces the external llvm-spirv translator).
+
+ // Run HipSpvPasses plugin via opt (must run on LLVM IR before
+ // the SPIR-V backend lowers to MIR).
+ auto PassPluginPath = findPassPlugin(C.getDriver(), Args);
+ if (!PassPluginPath.empty()) {
+ const char *PassPathCStr = C.getArgs().MakeArgString(PassPluginPath);
+ const char *OptOutput = HIP::getTempFile(C, Name + "-lower", "bc");
+ ArgStringList OptArgs{TempFile, "-load-pass-plugin",
+ PassPathCStr, "-passes=hip-post-link-passes",
+ "-o", OptOutput};
+ const char *Opt =
+ Args.MakeArgString(getToolChain().GetProgramPath("opt"));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::None(), Opt, OptArgs, Inputs,
+ Output));
+ TempFile = OptOutput;
+ }
- // Run LLVM IR passes to lower/expand/emulate HIP code that does not translate
- // to SPIR-V (E.g. dynamic shared memory).
+ // Compile processed bitcode to SPIR-V using the in-tree backend.
+ ArgStringList ClangArgs;
+ ClangArgs.push_back("--no-default-config");
+ ClangArgs.push_back("-c");
+ ClangArgs.push_back(
+ C.getArgs().MakeArgString("--target=" + T.getTriple()));
+
+ ClangArgs.push_back("-mllvm");
+ ClangArgs.push_back("-spirv-ext=+SPV_INTEL_function_pointers"
+ ",+SPV_INTEL_subgroups"
+ ",+SPV_EXT_relaxed_printf_string_address_space"
+ ",+SPV_KHR_bit_instructions"
+ ",+SPV_EXT_shader_atomic_float_add");
+
+ ClangArgs.push_back(TempFile);
+ ClangArgs.push_back("-o");
+ ClangArgs.push_back(Output.getFilename());
+
+ const char *Clang =
+ C.getArgs().MakeArgString(C.getDriver().getClangProgramPath());
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::None(), Clang, ClangArgs, Inputs,
+ Output));
+ return;
+ }
+
+ // Non-chipStar: run HIP passes via opt, then translate with llvm-spirv.
auto PassPluginPath = findPassPlugin(C.getDriver(), Args);
if (!PassPluginPath.empty()) {
const char *PassPathCStr = C.getArgs().MakeArgString(PassPluginPath);
@@ -89,27 +135,11 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand(
TempFile = OptOutput;
}
- // Emit SPIR-V binary.
+ // Emit SPIR-V binary via llvm-spirv translator (non-chipStar targets).
llvm::opt::ArgStringList TrArgs;
- auto T = getToolChain().getTriple();
- bool HasNoSubArch = T.getSubArch() == llvm::Triple::NoSubArch;
- if (T.getOS() == llvm::Triple::ChipStar) {
- // chipStar needs 1.2 for supporting warp-level primitivies via sub-group
- // extensions. Strictly put we'd need 1.3 for the standard non-extension
- // shuffle operations, but it's not supported by any backend driver of the
- // chipStar.
- if (HasNoSubArch)
- TrArgs.push_back("--spirv-max-version=1.2");
- TrArgs.push_back("--spirv-ext=-all"
- // Needed for experimental indirect call support.
- ",+SPV_INTEL_function_pointers"
- // Needed for shuffles below SPIR-V 1.3
- ",+SPV_INTEL_subgroups");
- } else {
- if (HasNoSubArch)
- TrArgs.push_back("--spirv-max-version=1.1");
- TrArgs.push_back("--spirv-ext=+all");
- }
+ if (T.getSubArch() == llvm::Triple::NoSubArch)
+ TrArgs.push_back("--spirv-max-version=1.1");
+ TrArgs.push_back("--spirv-ext=+all");
InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, "");
SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs);
@@ -152,14 +182,17 @@ HIPSPVToolChain::HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple,
void HIPSPVToolChain::addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
-
if (!HostTC) {
assert(DeviceOffloadingKind == Action::OFK_None &&
"Need host toolchain for offloading!");
return;
}
- HostTC->addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
+ // NOTE: Unlike other HIP toolchains, we do NOT delegate to
+ // HostTC.addClangTargetOptions() here. On macOS (Darwin), the host toolchain
+ // adds flags like -faligned-alloc-unavailable that are specific to macOS
+ // libc++ and break SPIR-V device compilation. SPIR-V device code doesn't
+ // have the same stdlib limitations as the host.
assert(DeviceOffloadingKind == Action::OFK_HIP &&
"Only HIP offloading kinds are supported for GPUs.");
diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp
index a59bd05cac0cf..e6a04e00af87b 100644
--- a/clang/lib/Driver/ToolChains/SPIRV.cpp
+++ b/clang/lib/Driver/ToolChains/SPIRV.cpp
@@ -185,7 +185,8 @@ SPIRVToolChain::SPIRVToolChain(const Driver &D, const llvm::Triple &Triple,
: ToolChain(D, Triple, Args) {
// TODO: Revisit need/use of --sycl-link option once SYCL toolchain is
// available and SYCL linking support is moved there.
- NativeLLVMSupport = Args.hasArg(options::OPT_sycl_link) || D.isUsingLTO();
+ NativeLLVMSupport = Args.hasArg(options::OPT_sycl_link) || D.isUsingLTO() ||
+ Triple.getOS() == llvm::Triple::ChipStar;
// Lookup binaries into the driver directory.
getProgramPaths().push_back(getDriver().Dir);
diff --git a/clang/test/Driver/hipspv-toolchain.hip b/clang/test/Driver/hipspv-toolchain.hip
index ae8d65313abfb..9af64ca4bdaa4 100644
--- a/clang/test/Driver/hipspv-toolchain.hip
+++ b/clang/test/Driver/hipspv-toolchain.hip
@@ -59,17 +59,50 @@
// RUN: llvm-offload-binary -o %t.dev.out \
// RUN: --image=file=%t.dev.bc,kind=hip,triple=spirv64-unknown-chipstar,arch=generic
-// RUN: clang-linker-wrapper --dry-run \
+// Test the in-tree SPIR-V backend path (no llvm-spirv available).
+// Run from a directory that doesn't contain llvm-spirv and use
+// --no-canonical-prefixes so getExecutableDir() looks there instead of
+// the build bin dir. Empty PATH ensures PATH lookup also fails.
+// RUN: mkdir -p %t/no-spirv %t/empty
+// RUN: ln -sf clang-linker-wrapper %t/no-spirv/clang-linker-wrapper
+// RUN: env "PATH=%t/empty" %t/no-spirv/clang-linker-wrapper \
+// RUN: --no-canonical-prefixes --dry-run \
// RUN: --device-compiler=spirv64-unknown-chipstar=--hip-path="%S/Inputs/hipspv" \
// RUN: --host-triple=spirv64-unknown-chipstar \
// RUN: --linker-path=clang-offload-bundler \
// RUN: --emit-fatbin-only -o /dev/null %t.dev.out \
// RUN: 2>&1 | FileCheck %s --check-prefix=WRAPPER -DHIP_PATH=%S/Inputs/hipspv
-// WRAPPER: clang{{.*}}" --no-default-config -o {{[^ ]*.img}}
+// The linker wrapper runs opt (HipSpvPasses) then uses the in-tree SPIR-V
+// backend when llvm-spirv is not available.
+// WRAPPER: "{{.*}}opt" {{.*}}-load-pass-plugin
+// WRAPPER-SAME: {{.*}}libLLVMHipSpvPasses.so
+// WRAPPER-SAME: -passes=hip-post-link-passes
+
+// WRAPPER: "{{.*}}clang{{.*}}" --no-default-config -o
// WRAPPER-SAME: --target=spirv64-unknown-chipstar
-// WRAPPER-SAME: {{[^ ]*.o}}
-// WRAPPER-SAME: --hip-path=[[HIP_PATH]]
+// WRAPPER-SAME: -mllvm -spirv-ext=+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_relaxed_printf_string_address_space,+SPV_KHR_bit_instructions,+SPV_EXT_shader_atomic_float_add
+// WRAPPER-SAME: -c -x ir
+
+// Test the llvm-spirv translator path (llvm-spirv available in executable dir).
+// Place a fake llvm-spirv next to the clang-linker-wrapper symlink.
+// RUN: mkdir -p %t/with-spirv
+// RUN: ln -sf clang-linker-wrapper %t/with-spirv/clang-linker-wrapper
+// RUN: touch %t/with-spirv/llvm-spirv && chmod +x %t/with-spirv/llvm-spirv
+// RUN: env "PATH=%t/empty" %t/with-spirv/clang-linker-wrapper \
+// RUN: --no-canonical-prefixes --dry-run \
+// RUN: --device-compiler=spirv64-unknown-chipstar=--hip-path="%S/Inputs/hipspv" \
+// RUN: --host-triple=spirv64-unknown-chipstar \
+// RUN: --linker-path=clang-offload-bundler \
+// RUN: --emit-fatbin-only -o /dev/null %t.dev.out \
+// RUN: 2>&1 | FileCheck %s --check-prefix=WRAPPER-TR
+
+// WRAPPER-TR: "{{.*}}opt" {{.*}}-load-pass-plugin
+// WRAPPER-TR-SAME: {{.*}}libLLVMHipSpvPasses.so
+// WRAPPER-TR-SAME: -passes=hip-post-link-passes
+
+// WRAPPER-TR: "{{.*}}llvm-spirv" {{.*}}--spirv-max-version=1.2
+// WRAPPER-TR-SAME: --spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups
// RUN: touch %t.dummy.o
// RUN: %clang -### --no-default-config -o %t.dummy.img \
@@ -84,8 +117,9 @@
// CHIPSTAR-SAME: "[[HIP_PATH]]/lib/libLLVMHipSpvPasses.so"
// CHIPSTAR-SAME: "-passes=hip-post-link-passes" "-o" [[LOWER_BC:".*bc"]]
-// CHIPSTAR: {{".*llvm-spirv"}} "--spirv-max-version=1.2"
-// CHIPSTAR-SAME: "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups"
+// CHIPSTAR: {{".*clang.*"}} "--no-default-config" "-c"
+// CHIPSTAR-SAME: "--target=spirv64-unknown-chipstar"
+// CHIPSTAR-SAME: "-mllvm" "-spirv-ext=+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_relaxed_printf_string_address_space,+SPV_KHR_bit_instructions,+SPV_EXT_shader_atomic_float_add"
// CHIPSTAR-SAME: [[LOWER_BC]] "-o" "[[SPIRV_OUT:.*img]]"
// RUN: %clang -### --no-default-config -o %t.dummy.img \
@@ -100,8 +134,9 @@
// CHIPSTAR-SUBARCH-SAME: "[[HIP_PATH]]/lib/libLLVMHipSpvPasses.so"
// CHIPSTAR-SUBARCH-SAME: "-passes=hip-post-link-passes" "-o" [[LOWER_BC:".*bc"]]
-// CHIPSTAR-SUBARCH: {{".*llvm-spirv"}}
-// CHIPSTAR-SUBARCH-SAME: "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups"
+// CHIPSTAR-SUBARCH: {{".*clang.*"}} "--no-default-config" "-c"
+// CHIPSTAR-SUBARCH-SAME: "--target=spirv64v1.3-unknown-chipstar"
+// CHIPSTAR-SUBARCH-SAME: "-mllvm" "-spirv-ext=+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_relaxed_printf_string_address_space,+SPV_KHR_bit_instructions,+SPV_EXT_shader_atomic_float_add"
// CHIPSTAR-SUBARCH-SAME: [[LOWER_BC]] "-o" "[[SPIRV_OUT:.*img]]"
//-----------------------------------------------------------------------------
@@ -115,9 +150,4 @@
// RUN: | FileCheck -DVERSION=%llvm-version-major \
// RUN: --check-prefix=VERSIONED %s
-// RUN: env "PATH=%t/versioned" %clang -### --no-default-config \
-// RUN: -o %t.dummy.img --target=spirv64-unknown-chipstar %t.dummy.o \
-// RUN: --hip-path="%S/Inputs/hipspv" -o /dev/null 2>&1 \
-// RUN: | FileCheck -DVERSION=%llvm-version-major --check-prefix=VERSIONED %s
-
// VERSIONED: {{.*}}llvm-spirv-[[VERSION]]
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 9e24a9c26d897..2522d0ac71df1 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -125,6 +125,9 @@ static StringRef ExecutableName;
/// Binary path for the CUDA installation.
static std::string CudaBinaryPath;
+/// HIP installation path.
+static std::string HipPath;
+
/// Mutex lock to protect writes to shared TempFiles in parallel.
static std::mutex TempFilesMutex;
@@ -479,9 +482,25 @@ fatbinary(ArrayRef<std::tuple<StringRef, StringRef, StringRef>> InputFiles,
SmallVector<StringRef> Targets = {
Saver.save("-targets=host-" + HostTriple.normalize())};
for (const auto &[File, TripleRef, Arch] : InputFiles) {
- std::string NormalizedTriple =
- normalizeForBundler(Triple(TripleRef), !Arch.empty());
- Targets.push_back(Saver.save("hip-" + NormalizedTriple + "-" + Arch));
+ llvm::Triple T(TripleRef);
+ // For SPIR-V targets, derive arch from triple if not provided
+ StringRef EffectiveArch = Arch;
+ if (EffectiveArch.empty() && T.isSPIRV()) {
+ EffectiveArch = T.getArchName();
+ }
+ StringRef BundleID;
+ if (EffectiveArch == "amdgcnspirv") {
+ BundleID = Saver.save("hip-spirv64-amd-amdhsa--" + EffectiveArch);
+ } else if (T.isSPIRV()) {
+ // ChipStar and other SPIR-V HIP targets: use hip-spirv64-<vendor>-<os>--<arch>
+ BundleID = Saver.save("hip-spirv64-" + T.getVendorName() + "-" +
+ T.getOSName() + "--" + EffectiveArch);
+ } else {
+ std::string NormalizedTriple =
+ normalizeForBundler(T, !Arch.empty());
+ BundleID = Saver.save("hip-" + NormalizedTriple + "-" + Arch);
+ }
+ Targets.push_back(BundleID);
}
CmdArgs.push_back(Saver.save(llvm::join(Targets, ",")));
@@ -554,7 +573,161 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args,
if (!Triple.isNVPTX() && !Triple.isSPIRV())
CmdArgs.push_back("-Wl,--no-undefined");
- for (StringRef InputFile : InputFiles)
+ // For non-chipStar SPIR-V targets, pass the HIP path to clang so it can
+ // find resources. For chipStar, passes are run via opt separately, so the
+ // inner clang doesn't need --hip-path (it just compiles IR to SPIR-V).
+ if (Triple.isSPIRV() && !HipPath.empty() &&
+ Triple.getOS() != llvm::Triple::ChipStar)
+ CmdArgs.push_back(Args.MakeArgString("--hip-path=" + HipPath));
+
+ // For chipStar targets: llvm-link (merge) → opt (HipSpvPasses) → clang
+ // (SPIR-V backend). The passes must operate on LLVM IR before the backend
+ // lowers to MIR, and all TU bitcode must be merged first for RDC support.
+ SmallVector<StringRef, 16> ProcessedInputFiles;
+ if (Triple.isSPIRV() && Triple.getOS() == llvm::Triple::ChipStar) {
+ // Step 1: Merge all input bitcode files with llvm-link (needed for RDC
+ // where functions can be defined across translation units).
+ StringRef MergedFile;
+ if (InputFiles.size() > 1) {
+ Expected<std::string> LinkPath =
+ findProgram("llvm-link", {getExecutableDir("llvm-link")});
+ if (!LinkPath)
+ return LinkPath.takeError();
+
+ auto LinkOutOrErr = createOutputFile(
+ sys::path::filename(ExecutableName) + ".merged", "bc");
+ if (!LinkOutOrErr)
+ return LinkOutOrErr.takeError();
+
+ SmallVector<StringRef, 16> LinkArgs{*LinkPath};
+ for (StringRef F : InputFiles)
+ LinkArgs.push_back(F);
+ LinkArgs.push_back("-o");
+ LinkArgs.push_back(*LinkOutOrErr);
+
+ if (Error Err = executeCommands(*LinkPath, LinkArgs))
+ return std::move(Err);
+
+ MergedFile = *LinkOutOrErr;
+ } else {
+ MergedFile = InputFiles[0];
+ }
+
+ // Step 2: Run HipSpvPasses via opt on the merged bitcode.
+ SmallString<128> PluginPath;
+ if (!HipPath.empty()) {
+ PluginPath.assign(HipPath);
+ sys::path::append(PluginPath, "lib", "libLLVMHipSpvPasses.so");
+ if (!sys::fs::exists(PluginPath)) {
+ PluginPath.assign(HipPath);
+ sys::path::append(PluginPath, "lib", "llvm",
+ "libLLVMHipSpvPasses.so");
+ }
+ if (!sys::fs::exists(PluginPath))
+ PluginPath.clear();
+ }
+
+ StringRef OptOutputFile = MergedFile;
+ if (!PluginPath.empty()) {
+ Expected<std::string> OptPath =
+ findProgram("opt", {getExecutableDir("opt")});
+ if (!OptPath)
+ return OptPath.takeError();
+
+ auto OptOutOrErr = createOutputFile(
+ sys::path::filename(ExecutableName) + ".lowered", "bc");
+ if (!OptOutOrErr)
+ return OptOutOrErr.takeError();
+
+ SmallVector<StringRef, 16> OptArgs{
+ *OptPath,
+ MergedFile,
+ "-load-pass-plugin",
+ Args.MakeArgString(PluginPath),
+ "-passes=hip-post-link-passes",
+ "-o",
+ *OptOutOrErr,
+ };
+
+ if (Error Err = executeCommands(*OptPath, OptArgs))
+ return std::move(Err);
+
+ OptOutputFile = *OptOutOrErr;
+ }
+
+ // Step 3: Convert processed bitcode to SPIR-V.
+ // Check if llvm-spirv translator is available. If so, use it directly;
+ // otherwise use the in-tree SPIR-V backend via clang.
+ // Use sys::findProgramByName() instead of findProgram() to avoid the
+ // dry-run fallback that always "finds" programs by returning their name.
+ bool UseLLVMSpirvTranslator = false;
+ std::string LLVMSpirvPathStr;
+ {
+ ErrorOr<std::string> LLVMSpirvPath =
+ sys::findProgramByName("llvm-spirv", {getExecutableDir("llvm-spirv")});
+ if (!LLVMSpirvPath)
+ LLVMSpirvPath = sys::findProgramByName("llvm-spirv");
+ if (LLVMSpirvPath) {
+ LLVMSpirvPathStr = *LLVMSpirvPath;
+ UseLLVMSpirvTranslator = true;
+ }
+ }
+ if (UseLLVMSpirvTranslator) {
+ // Use llvm-spirv translator: BC → SPIR-V binary directly.
+ auto SpirvOutOrErr = createOutputFile(
+ sys::path::filename(ExecutableName) + ".spirv", "spv");
+ if (!SpirvOutOrErr)
+ return SpirvOutOrErr.takeError();
+
+ // Derive SPIR-V max version from the triple's sub-arch.
+ // chipStar needs v1.2 for sub-group extensions by default.
+ std::string MaxVerArg;
+ if (Triple.getSubArch() == llvm::Triple::SPIRVSubArch_v13)
+ MaxVerArg = "--spirv-max-version=1.3";
+ else if (Triple.getSubArch() == llvm::Triple::SPIRVSubArch_v12 ||
+ Triple.getOS() == llvm::Triple::ChipStar)
+ MaxVerArg = "--spirv-max-version=1.2";
+ else
+ MaxVerArg = "--spirv-max-version=1.1";
+
+ SmallVector<StringRef, 16> TranslateArgs{
+ LLVMSpirvPathStr,
+ OptOutputFile,
+ Args.MakeArgString(MaxVerArg),
+ "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups",
+ "-o",
+ *SpirvOutOrErr,
+ };
+
+ if (Error Err = executeCommands(LLVMSpirvPathStr, TranslateArgs))
+ return std::move(Err);
+
+ // The SPIR-V binary is the final output; skip the inner clang
+ // compilation by returning it directly as the linked image.
+ return *SpirvOutOrErr;
+ }
+
+ // No llvm-spirv available; use the in-tree SPIR-V backend via clang.
+ ProcessedInputFiles.push_back(OptOutputFile);
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-spirv-ext=+SPV_INTEL_function_pointers"
+ ",+SPV_INTEL_subgroups"
+ ",+SPV_EXT_relaxed_printf_string_address_space"
+ ",+SPV_KHR_bit_instructions"
+ ",+SPV_EXT_shader_atomic_float_add");
+ // The extracted bitcode files have a .o extension which causes the driver
+ // to treat them as pre-compiled objects, skipping the Backend compilation
+ // step. Force the input language to LLVM IR so the SPIR-V backend runs.
+ // Use -c to skip the link phase — the SPIR-V backend output is the final
+ // binary; hitting HIPSPV::Linker would re-run the full pipeline.
+ CmdArgs.push_back("-c");
+ CmdArgs.push_back("-x");
+ CmdArgs.push_back("ir");
+ } else {
+ ProcessedInputFiles.append(InputFiles.begin(), InputFiles.end());
+ }
+
+ for (StringRef InputFile : ProcessedInputFiles)
CmdArgs.push_back(InputFile);
// If this is CPU offloading we copy the input libraries.
@@ -613,8 +786,14 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args,
for (StringRef Arg : Args.getA...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/186972
More information about the cfe-commits
mailing list