From 3724d3ced8e15bb17be3d96b634f8d9e9a9daada Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:19:27 +0300 Subject: [PATCH 01/22] llvm-patches: stop preserving device debug info on LLVM 21 and 22 Both SPIR-V producers reachable on LLVM 21 and 22 emit debug info that spirv-val rejects. The SPIRV-LLVM-Translator encodes DebugTypeComposite with a Parent operand, which forms a genuinely cyclic forward reference, and the LLVM 22 SPIR-V backend emits DebugTypePointer with a DebugInfoNone base type. IGC then reports an internal error on Arc. 0002-preserve-device-debug-info was the only thing removing the DebugInfoKind = NoDebugInfo guard from HIPSPVToolChain::adjustDebugInfoKind, so dropping the patch restores stock clang's behaviour: no DICompileUnit is generated at all and nothing downstream can orphan debug metadata. Its other hunk (SPV_KHR_non_semantic_info / SPV_INTEL_optnone / nonsemantic-shader-200 under -g) is dead once debug info is off. Device debug info is delivered on LLVM 23 instead, where the in-tree SPIR-V backend avoids the cycle structurally. Refs: CHIP-SPV/chipStar#1004 --- llvm-patches/README.md | 2 - .../0002-preserve-device-debug-info.patch | 89 ------------------- .../0002-preserve-device-debug-info.patch | 89 ------------------- 3 files changed, 180 deletions(-) delete mode 100644 llvm-patches/llvm-21/llvm/0002-preserve-device-debug-info.patch delete mode 100644 llvm-patches/llvm-22/llvm/0002-preserve-device-debug-info.patch diff --git a/llvm-patches/README.md b/llvm-patches/README.md index ec414784f..73bb43211 100644 --- a/llvm-patches/README.md +++ b/llvm-patches/README.md @@ -70,7 +70,6 @@ Same patch set as llvm-20 (rebased onto `release/21.x`): | Patch | Purpose | Upstream status | |---|---|---| | 0001-spirv-version-and-extensions | As in llvm-20 | Upstreamed in LLVM 23+ behind `Triple::ChipStar` ([llvm#179902](https://github.com/llvm/llvm-project/pull/179902)) | -| 0002-preserve-device-debug-info | As in llvm-20 | Merged upstream ([llvm#210504](https://github.com/llvm/llvm-project/pull/210504)), ships in LLVM 24; matches the final merged form including SPV_INTEL_optnone | | 0003-unbundle-static-device-libraries | As in llvm-20 | Upstream in LLVM 22+ ([llvm#136412](https://github.com/llvm/llvm-project/pull/136412), `ae0614de05ac`) | | 0004-fix-spirv-data-layout | As in llvm-20 | chipStar-local revert of [llvm#110695](https://github.com/llvm/llvm-project/pull/110695), not upstreamable | | 0005-macos-hip-spirv | As in llvm-20 | Upstreamed via [llvm#183991](https://github.com/llvm/llvm-project/pull/183991) + [llvm#206902](https://github.com/llvm/llvm-project/pull/206902) | @@ -95,7 +94,6 @@ upstream in translator 220+. | Patch | Purpose | Upstream status | |---|---|---| | 0001-spirv-version-and-extensions | As in llvm-20 | Upstreamed in LLVM 23+ behind `Triple::ChipStar` ([llvm#179902](https://github.com/llvm/llvm-project/pull/179902)) | -| 0002-preserve-device-debug-info | As in llvm-20 | Merged upstream ([llvm#210504](https://github.com/llvm/llvm-project/pull/210504)), ships in LLVM 24; matches the final merged form including SPV_INTEL_optnone | | 0003-macos-hip-spirv | As in llvm-20 | Upstreamed via [llvm#183991](https://github.com/llvm/llvm-project/pull/183991) + [llvm#206902](https://github.com/llvm/llvm-project/pull/206902) | ### spirv-translator/ diff --git a/llvm-patches/llvm-21/llvm/0002-preserve-device-debug-info.patch b/llvm-patches/llvm-21/llvm/0002-preserve-device-debug-info.patch deleted file mode 100644 index 5aa91987c..000000000 --- a/llvm-patches/llvm-21/llvm/0002-preserve-device-debug-info.patch +++ /dev/null @@ -1,89 +0,0 @@ -From f83dcc1d9f2120758fb75dd990c3d420f305f9a4 Mon Sep 17 00:00:00 2001 -From: chipStar -Date: Sat, 18 Jul 2026 14:18:22 +0300 -Subject: [PATCH 2/5] Preserve device debug info for gdb-oneapi - -HIPSPVToolChain::adjustDebugInfoKind() unconditionally forced NoDebugInfo, -so -g/-O0 produced device SPIR-V with no debug metadata at all. The stated -reason (SPIRV-LLVM-Translator aborting on DW_OP_LLVM_convert) no longer -applies: the translator now lowers it to SPIRVDebug::Convert. - -Stop clobbering the requested debug level, and when -g is given emit the -NonSemantic.Shader.DebugInfo form (--spirv-debug-info-version= -nonsemantic-shader-200 + SPV_KHR_non_semantic_info) that Intel's IGC and -gdb-oneapi consume to resolve source lines and locals in device code. - -Also enable SPV_INTEL_optnone when -g is given: clang emits the optnone -function attribute at -O0, and without the extension the translator drops -it, the device compiler optimizes the kernel anyway, and gdb-oneapi -reports every local as - the exact symptom of #1004. - -Refs: CHIP-SPV/chipStar#1004 -Applies-to: LLVM release/21.x -Upstream-status: upstreamed in llvm/llvm-project#210504 (3093d8c577d7), -first ships in LLVM 24. This patch matches the final merged form, -including the SPV_INTEL_optnone enablement from its second commit -(f44bf2b4ce5c). - ---- - clang/lib/Driver/ToolChains/HIPSPV.cpp | 39 ++++++++++++++++++++++---- - 1 file changed, 33 insertions(+), 6 deletions(-) - -diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp -index a1a7285..2f797d1 100644 ---- a/clang/lib/Driver/ToolChains/HIPSPV.cpp -+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp -@@ -98,8 +98,28 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( - // We need 1.2 when using 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 target yet. -- llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2", -- "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_shader_atomic_float_add"}; -+ std::string SpirvExts = -+ "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups," -+ "+SPV_EXT_shader_atomic_float_add"; -+ llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2"}; -+ // When the user requests debug info (-g, but not -g0), preserve it into the -+ // SPIR-V in the NonSemantic.Shader.DebugInfo form. Intel's IGC and gdb-oneapi -+ // consume this to map device code back to source lines and local variables; -+ // the translator's default OpenCL.DebugInfo.100 form is not sufficient for -+ // that. Emitting the NonSemantic debug instructions requires the -+ // SPV_KHR_non_semantic_info extension, so it is only enabled here on demand -+ // to keep the default (non-debug) SPIR-V output unchanged. -+ // SPV_INTEL_optnone carries the optnone function attribute, which Clang -+ // emits at -O0. Without the extension the translator drops the attribute, -+ // the device compiler optimizes the kernel anyway, and debuggers report -+ // locals as even though line info is present. At -O1 and -+ // above no optnone attribute exists, so the extension has no effect there. -+ if (const Arg *A = Args.getLastArg(options::OPT_g_Group); -+ A && !A->getOption().matches(options::OPT_g0)) { -+ SpirvExts += ",+SPV_KHR_non_semantic_info,+SPV_INTEL_optnone"; -+ TrArgs.push_back("--spirv-debug-info-version=nonsemantic-shader-200"); -+ } -+ TrArgs.push_back(Args.MakeArgString(SpirvExts)); - InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, ""); - SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs); - } -@@ -285,8 +305,15 @@ VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D, - void HIPSPVToolChain::adjustDebugInfoKind( - llvm::codegenoptions::DebugInfoKind &DebugInfoKind, - const llvm::opt::ArgList &Args) const { -- // Debug info generation is disabled for SPIRV-LLVM-Translator -- // which currently aborts on the presence of DW_OP_LLVM_convert. -- // TODO: Enable debug info when the SPIR-V backend arrives. -- DebugInfoKind = llvm::codegenoptions::NoDebugInfo; -+ // Historically device debug info was force-disabled here because the -+ // SPIRV-LLVM-Translator aborted on DW_OP_LLVM_convert debug expressions. -+ // The translator now lowers that operation (SPIRVDebug::Convert), so honor -+ // the debug level the user requested (e.g. via -g) and let it flow into the -+ // emitted SPIR-V. constructLinkAndEmitSpirvCommand() additionally enables the -+ // NonSemantic.Shader.DebugInfo form at translation time so that Intel's IGC -+ // and gdb-oneapi can consume it. Leaving DebugInfoKind untouched keeps the -+ // default (no -g) behavior unchanged, since the driver defaults it to -+ // NoDebugInfo. -+ (void)DebugInfoKind; -+ (void)Args; - } --- -2.43.0 - diff --git a/llvm-patches/llvm-22/llvm/0002-preserve-device-debug-info.patch b/llvm-patches/llvm-22/llvm/0002-preserve-device-debug-info.patch deleted file mode 100644 index bb9e5f137..000000000 --- a/llvm-patches/llvm-22/llvm/0002-preserve-device-debug-info.patch +++ /dev/null @@ -1,89 +0,0 @@ -From b2b3db6a36ebdd3955dce983bb137ae6767c15c2 Mon Sep 17 00:00:00 2001 -From: chipStar -Date: Sat, 18 Jul 2026 14:18:22 +0300 -Subject: [PATCH 2/3] Preserve device debug info for gdb-oneapi - -HIPSPVToolChain::adjustDebugInfoKind() unconditionally forced NoDebugInfo, -so -g/-O0 produced device SPIR-V with no debug metadata at all. The stated -reason (SPIRV-LLVM-Translator aborting on DW_OP_LLVM_convert) no longer -applies: the translator now lowers it to SPIRVDebug::Convert. - -Stop clobbering the requested debug level, and when -g is given emit the -NonSemantic.Shader.DebugInfo form (--spirv-debug-info-version= -nonsemantic-shader-200 + SPV_KHR_non_semantic_info) that Intel's IGC and -gdb-oneapi consume to resolve source lines and locals in device code. - -Also enable SPV_INTEL_optnone when -g is given: clang emits the optnone -function attribute at -O0, and without the extension the translator drops -it, the device compiler optimizes the kernel anyway, and gdb-oneapi -reports every local as - the exact symptom of #1004. - -Refs: CHIP-SPV/chipStar#1004 -Applies-to: LLVM release/22.x -Upstream-status: upstreamed in llvm/llvm-project#210504 (3093d8c577d7), -first ships in LLVM 24. This patch matches the final merged form, -including the SPV_INTEL_optnone enablement from its second commit -(f44bf2b4ce5c). - ---- - clang/lib/Driver/ToolChains/HIPSPV.cpp | 39 ++++++++++++++++++++++---- - 1 file changed, 33 insertions(+), 6 deletions(-) - -diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp -index 4cde8f9..2d24599 100644 ---- a/clang/lib/Driver/ToolChains/HIPSPV.cpp -+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp -@@ -93,8 +93,28 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( - // We need 1.2 when using 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 target yet. -- llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2", -- "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_shader_atomic_float_add"}; -+ std::string SpirvExts = -+ "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups," -+ "+SPV_EXT_shader_atomic_float_add"; -+ llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2"}; -+ // When the user requests debug info (-g, but not -g0), preserve it into the -+ // SPIR-V in the NonSemantic.Shader.DebugInfo form. Intel's IGC and gdb-oneapi -+ // consume this to map device code back to source lines and local variables; -+ // the translator's default OpenCL.DebugInfo.100 form is not sufficient for -+ // that. Emitting the NonSemantic debug instructions requires the -+ // SPV_KHR_non_semantic_info extension, so it is only enabled here on demand -+ // to keep the default (non-debug) SPIR-V output unchanged. -+ // SPV_INTEL_optnone carries the optnone function attribute, which Clang -+ // emits at -O0. Without the extension the translator drops the attribute, -+ // the device compiler optimizes the kernel anyway, and debuggers report -+ // locals as even though line info is present. At -O1 and -+ // above no optnone attribute exists, so the extension has no effect there. -+ if (const Arg *A = Args.getLastArg(options::OPT_g_Group); -+ A && !A->getOption().matches(options::OPT_g0)) { -+ SpirvExts += ",+SPV_KHR_non_semantic_info,+SPV_INTEL_optnone"; -+ TrArgs.push_back("--spirv-debug-info-version=nonsemantic-shader-200"); -+ } -+ TrArgs.push_back(Args.MakeArgString(SpirvExts)); - InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, ""); - SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs); - } -@@ -283,8 +303,15 @@ VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D, - void HIPSPVToolChain::adjustDebugInfoKind( - llvm::codegenoptions::DebugInfoKind &DebugInfoKind, - const llvm::opt::ArgList &Args) const { -- // Debug info generation is disabled for SPIRV-LLVM-Translator -- // which currently aborts on the presence of DW_OP_LLVM_convert. -- // TODO: Enable debug info when the SPIR-V backend arrives. -- DebugInfoKind = llvm::codegenoptions::NoDebugInfo; -+ // Historically device debug info was force-disabled here because the -+ // SPIRV-LLVM-Translator aborted on DW_OP_LLVM_convert debug expressions. -+ // The translator now lowers that operation (SPIRVDebug::Convert), so honor -+ // the debug level the user requested (e.g. via -g) and let it flow into the -+ // emitted SPIR-V. constructLinkAndEmitSpirvCommand() additionally enables the -+ // NonSemantic.Shader.DebugInfo form at translation time so that Intel's IGC -+ // and gdb-oneapi can consume it. Leaving DebugInfoKind untouched keeps the -+ // default (no -g) behavior unchanged, since the driver defaults it to -+ // NoDebugInfo. -+ (void)DebugInfoKind; -+ (void)Args; - } --- -2.43.0 - From cc5558bc1ab51ad2c14999d1b5c29fc6e5f9de02 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:20:23 +0300 Subject: [PATCH 02/22] llvm-patches: add the LLVM 23 patch series LLVM 23 is pinned to the upstream tag llvmorg-23.1.0-rc2 plus two patches; all four patches were verified to apply with git apply against a pristine rc2 checkout and llvm_release_230, and the patched HIPSPV.cpp and SPIRVSubtarget.cpp compile. 0001 backports llvm/llvm-project#213052 (merged 2026-07-31 as 7ef0ca2b13f9, a reland of #206910), which landed after release/23.x was cut. It makes the HIPSPV toolchain emit device SPIR-V with the in-tree SPIR-V backend by default and fall back to llvm-spirv under -fno-integrated-objemitter or when the SPIR-V target was not built. The upstream commit sits on a main that already had the extension list and the debug-info translator flags; release/23.x has neither, so both are folded in and a patched 23 matches main exactly. 0002 honors -g for device code, but only when the in-tree backend is the effective emitter. The translator encodes DebugTypeComposite with a Parent operand, producing a cyclic forward reference that spirv-val rejects and IGC mis-handles, so -g must keep being stripped there. The remaining llvm-21/llvm-22 patches are unnecessary here: the SPIR-V version and extension selection, static device library unbundling, the data layout and the macOS Mach-O support are all already in 23. Refs: CHIP-SPV/chipStar#1004 --- llvm-patches/README.md | 48 +- .../0001-hipspv-in-tree-spirv-backend.patch | 466 ++++++++++++++++++ .../0002-preserve-device-debug-info.patch | 68 +++ ...-pretend-subgroup-caps-are-spirv-1.2.patch | 34 ++ ...-coalesce-duplicate-phi-predecessors.patch | 46 ++ 5 files changed, 656 insertions(+), 6 deletions(-) create mode 100644 llvm-patches/llvm-23/llvm/0001-hipspv-in-tree-spirv-backend.patch create mode 100644 llvm-patches/llvm-23/llvm/0002-preserve-device-debug-info.patch create mode 100644 llvm-patches/llvm-23/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch create mode 100644 llvm-patches/llvm-23/spirv-translator/0002-coalesce-duplicate-phi-predecessors.patch diff --git a/llvm-patches/README.md b/llvm-patches/README.md index 73bb43211..269b42514 100644 --- a/llvm-patches/README.md +++ b/llvm-patches/README.md @@ -11,16 +11,21 @@ llvm-patches/ ├── llvm-21/ │ ├── llvm/ │ └── spirv-translator/ -└── llvm-22/ +├── llvm-22/ +│ ├── llvm/ +│ └── spirv-translator/ +└── llvm-23/ ├── llvm/ └── spirv-translator/ ``` -`scripts/configure_llvm.sh --version <20|21|22>` clones the matching upstream -branches (`release/.x` and `llvm_release_0`) and applies -every patch in the version's directory, in lexicographic (numeric) order, with -`git apply`. There is no per-patch version gating: everything in a version -directory applies to that version, and a failed patch is a hard error. +`scripts/configure_llvm.sh --version <20|21|22|23>` clones the matching +upstream LLVM ref (`release/.x`, except 23 which is pinned to the +tag `llvmorg-23.1.0-rc2`) together with the translator branch +`llvm_release_0`, and applies every patch in the version's +directory, in lexicographic (numeric) order, with `git apply`. There is no +per-patch version gating: everything in a version directory applies to that +version, and a failed patch is a hard error. `--version latest` (experimental) is different: it clones the maintained branch `chipStar-llvm-23` from @@ -36,6 +41,7 @@ the release-pinned versions. | 20 | `llvm/llvm-project` `release/20.x` | `llvm-patches/llvm-20/` | | 21 | `llvm/llvm-project` `release/21.x` | `llvm-patches/llvm-21/` | | 22 | `llvm/llvm-project` `release/22.x` | `llvm-patches/llvm-22/` | +| 23 | `llvm/llvm-project` `llvmorg-23.1.0-rc2` | `llvm-patches/llvm-23/` | | latest (experimental) | `CHIP-SPV/llvm-project` `chipStar-llvm-23` | none | LLVM 17, 18, and 19 support was dropped. @@ -103,6 +109,36 @@ upstream in translator 220+. | 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-20 | Deliberate spec deviation, permanent | | 0002-coalesce-duplicate-phi-predecessors | As in llvm-20 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | +## llvm-23 + +Different in kind from the earlier sets. LLVM 23 already carries the SPIR-V +version/extension selection (upstreamed behind `Triple::ChipStar`), the +static-device-library unbundling, the data layout, and the macOS Mach-O +support, so none of those patches are needed. What it does *not* carry is +[llvm#213052](https://github.com/llvm/llvm-project/pull/213052), which +landed after `release/23.x` was cut. + +### llvm/ + +| Patch | Purpose | Upstream status | +|---|---|---| +| 0001-hipspv-in-tree-spirv-backend | Drive the in-tree SPIR-V backend from the HIPSPV toolchain by default, falling back to `llvm-spirv` under `-fno-integrated-objemitter`; map the `chipstar` OS to the Kernel execution environment | Backport of [llvm#213052](https://github.com/llvm/llvm-project/pull/213052) (`7ef0ca2b13f9`), first ships in LLVM 24 | +| 0002-preserve-device-debug-info | Honor `-g` for device code, but only when the in-tree backend is the effective emitter | The ungated form is upstream ([llvm#210504](https://github.com/llvm/llvm-project/pull/210504)); the backend gate is chipStar-specific | + +The gate in 0002 is why device `-g` works here and nowhere else: the +translator's `DebugTypeComposite` `Parent` operand creates a cyclic forward +reference that `spirv-val` rejects and IGC mis-handles, so `-g` must keep +being stripped whenever the translator is the producer. Because the strip +happens in `HIPSPVToolChain::adjustDebugInfoKind`, clang CodeGen never emits +a `DICompileUnit` on that path. + +### spirv-translator/ + +| Patch | Purpose | Upstream status | +|---|---|---| +| 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-20 | Deliberate spec deviation, permanent | +| 0002-coalesce-duplicate-phi-predecessors | As in llvm-20 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | + ## Removed in the layout change - **archive-data-layout patch** (`llvm-link` empty "ArchiveModule" data layout diff --git a/llvm-patches/llvm-23/llvm/0001-hipspv-in-tree-spirv-backend.patch b/llvm-patches/llvm-23/llvm/0001-hipspv-in-tree-spirv-backend.patch new file mode 100644 index 000000000..de97298a1 --- /dev/null +++ b/llvm-patches/llvm-23/llvm/0001-hipspv-in-tree-spirv-backend.patch @@ -0,0 +1,466 @@ +From 7ef0ca2b13f900000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chipStar +Date: Fri, 31 Jul 2026 00:00:00 +0000 +Subject: [PATCH 1/2] [HIPSPV] Add in-tree SPIR-V backend support for chipStar + +Backport of llvm/llvm-project#213052 (merged 2026-07-31 as 7ef0ca2b13f9, +a reland of #206910). release/23.x branched before it, so a stock LLVM 23 +always emits device SPIR-V through the external SPIRV-LLVM-Translator. + +With this patch the HIPSPV toolchain drives the in-tree SPIR-V backend by +default (clang -cc1 -emit-obj on the lowered bitcode) and falls back to +llvm-spirv when -fno-integrated-objemitter is given or the SPIR-V target +was not built. This matters to chipStar beyond emitter choice: the +translator encodes DebugTypeComposite with a Parent operand, producing a +cyclic forward reference that spirv-val rejects and IGC mis-handles, so +device debug info (-g) only works via the backend. See the companion +0002-preserve-device-debug-info.patch. + +The HipSpvPasses opt invocation is factored into runHipSpvPasses() so both +emitters run it, and SPIRVSubtarget maps the chipstar OS to the Kernel +execution environment. + +Adapted from the upstream commit for release/23.x, which also lacks the +SPIR-V extension list and debug-info flags that main's HIPSPV.cpp had at +the time of the merge; both are folded in here so a patched 23 behaves +exactly like main. + +Applies-to: LLVM llvmorg-23.1.0-rc2 +Upstream-status: merged upstream as 7ef0ca2b13f9, first ships in LLVM 24. +--- +diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp +index d6900c7..98bec18 100644 +--- a/clang/lib/Driver/ToolChains/HIPSPV.cpp ++++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp +@@ -13,6 +13,7 @@ + #include "clang/Driver/Driver.h" + #include "clang/Driver/InputInfo.h" + #include "clang/Options/Options.h" ++#include "llvm/MC/TargetRegistry.h" + #include "llvm/Support/FileSystem.h" + #include "llvm/Support/Path.h" + +@@ -48,6 +49,34 @@ static std::string findPassPlugin(const Driver &D, + return std::string(); + } + ++// Is the in-tree SPIR-V backend built into this clang? ++static bool isSPIRVBackendAvailable(const llvm::Triple &T) { ++ std::string IgnoredError; ++ return llvm::TargetRegistry::lookupTarget(T, IgnoredError); ++} ++ ++// Runs the HipSpvPasses plugin via `opt` on TempFile when the plugin is found. ++// Returns the lowered bitcode path, or TempFile unchanged if no plugin exists. ++static const char *runHipSpvPasses(Compilation &C, const JobAction &JA, ++ const Tool &Creator, const ToolChain &TC, ++ const InputInfoList &Inputs, ++ const InputInfo &Output, ++ const llvm::opt::ArgList &Args, ++ StringRef Name, const char *TempFile) { ++ auto PassPluginPath = findPassPlugin(C.getDriver(), Args); ++ if (PassPluginPath.empty()) ++ return TempFile; ++ const char *PassPathCStr = C.getArgs().MakeArgString(PassPluginPath); ++ const char *OptOutput = HIP::getTempFile(C, Name.str() + "-lower", "bc"); ++ ArgStringList OptArgs{TempFile, "-load-pass-plugin", ++ PassPathCStr, "-passes=hip-post-link-passes", ++ "-o", OptOutput}; ++ const char *Opt = Args.MakeArgString(TC.GetProgramPath("opt")); ++ C.addCommand(std::make_unique( ++ JA, Creator, ResponseFileSupport::None(), Opt, OptArgs, Inputs, Output)); ++ return OptOutput; ++} ++ + void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( + Compilation &C, const JobAction &JA, const InputInfoList &Inputs, + const InputInfo &Output, const llvm::opt::ArgList &Args) const { +@@ -73,44 +102,100 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( + tools::constructLLVMLinkCommand(C, *this, JA, Inputs, LinkArgs, Output, Args, + TempFile); + +- // Post-link HIP lowering. ++ auto T = getToolChain().getTriple(); + +- // Run LLVM IR passes to lower/expand/emulate HIP code that does not translate +- // to SPIR-V (E.g. dynamic shared memory). +- 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")); ++ if (T.getOS() == llvm::Triple::ChipStar) { ++ // chipStar: run HipSpvPasses via opt, then emit SPIR-V with the in-tree ++ // SPIR-V backend by default, or with the external llvm-spirv translator ++ // when -fno-integrated-objemitter is given (or the backend is not built). ++ ++ // Run HipSpvPasses plugin via opt (must run on LLVM IR before ++ // the SPIR-V backend lowers to MIR). ++ TempFile = runHipSpvPasses(C, JA, *this, getToolChain(), Inputs, Output, ++ Args, Name, TempFile); ++ ++ // Note that useIntegratedBackend() is consulted first so that an explicit ++ // -f(no-)integrated-objemitter still gets diagnosed against this toolchain. ++ if (!getToolChain().useIntegratedBackend() || !isSPIRVBackendAvailable(T)) { ++ // External translator path: BC -> SPIR-V via llvm-spirv. ++ llvm::opt::ArgStringList TrArgs; ++ if (T.getSubArch() == llvm::Triple::NoSubArch) ++ TrArgs.push_back("--spirv-max-version=1.2"); ++ // Keep this extension list in sync with the in-tree backend fallback ++ // below. ++ TrArgs.push_back("--spirv-ext=-all" ++ ",+SPV_INTEL_function_pointers" ++ ",+SPV_INTEL_subgroups" ++ ",+SPV_KHR_bit_instructions" ++ ",+SPV_EXT_shader_atomic_float_add"); ++ ++ // Preserve debug info in the NonSemantic.Shader.DebugInfo form. ++ // These flags are passed unconditionally instead of gating on -g: in ++ // RDC-mode links this job runs in a clang invoked by ++ // clang-linker-wrapper where the original -g is not visible, but the ++ // debug info itself travels in the bitcode. SPV_KHR_non_semantic_info ++ // and the debug info version only take effect when the bitcode carries ++ // debug info. SPV_INTEL_optnone is not tied to debug info: clang emits ++ // optnone at -O0 even without -g, and the emitter needs the extension ++ // allowed to encode it. ++ TrArgs.push_back("--spirv-ext=+SPV_KHR_non_semantic_info" ++ ",+SPV_INTEL_optnone"); ++ TrArgs.push_back("--spirv-debug-info-version=nonsemantic-shader-200"); ++ ++ InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, ""); ++ SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs); ++ return; ++ } ++ ++ // Default: compile the lowered bitcode to SPIR-V with the in-tree backend. ++ // Invoke `clang -cc1` directly rather than the clang driver: the driver ++ // would re-run config-file loading, toolchain detection and argument ++ // translation over an input that is already device-compiled and lowered, ++ // which is both wasteful and fragile. This mirrors how HIPAMD drives its ++ // SPIR-V backend emission (see HIPAMD::constructLinkAndEmitSpirvCommand). ++ // Keep the default -O0 backend pipeline (i.e. no -disable-llvm-optzns) so ++ // the mandatory lowering passes still run, matching the previously ++ // validated driver `-c` behavior. ++ ArgStringList Cc1Args; ++ Cc1Args.push_back("-cc1"); ++ Cc1Args.push_back("-triple"); ++ Cc1Args.push_back(C.getArgs().MakeArgString(T.getTriple())); ++ Cc1Args.push_back("-emit-obj"); ++ ++ // SPIR-V extensions the chipStar runtime relies on. Keep in sync with the ++ // llvm-spirv translator path above. SPV_KHR_non_semantic_info and ++ // SPV_INTEL_optnone let the backend emit NonSemantic.Shader.DebugInfo and ++ // the OptNoneINTEL function control when the bitcode carries debug info / ++ // optnone attributes (the backend's debug handler is a no-op otherwise). ++ Cc1Args.push_back("-mllvm"); ++ Cc1Args.push_back("-spirv-ext=+SPV_INTEL_function_pointers" ++ ",+SPV_INTEL_subgroups" ++ ",+SPV_KHR_bit_instructions" ++ ",+SPV_EXT_shader_atomic_float_add" ++ ",+SPV_KHR_non_semantic_info" ++ ",+SPV_INTEL_optnone"); ++ ++ Cc1Args.push_back(TempFile); ++ Cc1Args.push_back("-o"); ++ Cc1Args.push_back(Output.getFilename()); ++ ++ const Driver &Drv = C.getDriver(); ++ const char *Clang = Drv.getDriverProgramPath(); + C.addCommand(std::make_unique( +- JA, *this, ResponseFileSupport::None(), Opt, OptArgs, Inputs, Output)); +- TempFile = OptOutput; ++ JA, *this, ResponseFileSupport::None(), Clang, Cc1Args, Inputs, Output, ++ Drv.getPrependArg())); ++ return; + } + +- // Emit SPIR-V binary. ++ // Non-chipStar: run HIP passes via opt, then translate with llvm-spirv. ++ TempFile = runHipSpvPasses(C, JA, *this, getToolChain(), Inputs, Output, Args, ++ Name, TempFile); ++ ++ // 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); +@@ -150,6 +235,11 @@ HIPSPVToolChain::HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple, + getProgramPaths().push_back(getDriver().Dir); + } + ++bool HIPSPVToolChain::IsIntegratedBackendSupported() const { ++ // The in-tree SPIR-V backend can only be requested when it is built. ++ return isSPIRVBackendAvailable(getTriple()); ++} ++ + void HIPSPVToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + BoundArch BA, Action::OffloadKind DeviceOffloadingKind) const { +diff --git a/clang/lib/Driver/ToolChains/HIPSPV.h b/clang/lib/Driver/ToolChains/HIPSPV.h +index 337c9c9..e38a713 100644 +--- a/clang/lib/Driver/ToolChains/HIPSPV.h ++++ b/clang/lib/Driver/ToolChains/HIPSPV.h +@@ -52,10 +52,18 @@ public: + const llvm::opt::ArgList &Args); + + const llvm::Triple *getAuxTriple() const override { +- assert(HostTC); +- return &HostTC->getTriple(); ++ return HostTC ? &HostTC->getTriple() : nullptr; + } + ++ // Keep IsIntegratedBackendDefault() at the base class' "true": it also ++ // decides whether clang's compile and backend jobs are collapsed into a ++ // single -cc1 invocation, so making it depend on whether the SPIR-V backend ++ // was built would change the device compilation job layout of every HIPSPV ++ // compile. The fallback to the external llvm-spirv translator is decided in ++ // HIPSPV::Linker::constructLinkAndEmitSpirvCommand instead. ++ bool IsIntegratedBackendSupported() const override; ++ bool IsNonIntegratedBackendSupported() const override { return true; } ++ + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, BoundArch BA, +diff --git a/clang/test/Driver/hipspv-link-static-library.hip b/clang/test/Driver/hipspv-link-static-library.hip +index eb114ad..a00f385 100644 +--- a/clang/test/Driver/hipspv-link-static-library.hip ++++ b/clang/test/Driver/hipspv-link-static-library.hip +@@ -49,7 +49,8 @@ + // DELETE-SDL-NEW: "{{.*}}llvm-link" "-o" "{{.*}}.bc" "{{.*}}.o" "{{.*}}.o" + + // SDL-NEW-WRAPPER: clang{{.*}}" --no-default-config -o {{[^ ]*.img}} +-// SDL-NEW-WRAPPER-SAME: {{[^ ]*.o}} {{[^ ]*.o}} ++// SDL-NEW-WRAPPER-SAME: --target=spirv64-unknown-chipstar ++// SDL-NEW-WRAPPER-SAME: {{[^ ]*.o}} + // SDL-NEW-WRAPPER-SAME: --hip-path=[[HIP_PATH]] + + // SDL: "{{.*}}opt" +diff --git a/clang/test/Driver/hipspv-no-spirv-backend.hip b/clang/test/Driver/hipspv-no-spirv-backend.hip +new file mode 100644 +index 0000000..decab84 +--- /dev/null ++++ b/clang/test/Driver/hipspv-no-spirv-backend.hip +@@ -0,0 +1,41 @@ ++// Coverage for HIPSPV behavior that must not depend on whether the in-tree ++// SPIR-V backend was built. Deliberately not guarded by the ++// spirv-registered-target feature, so builders configured without the SPIR-V ++// target (e.g. X86-only bots) exercise it too. ++ ++// UNSUPPORTED: system-windows ++ ++// The device compilation job layout is a property of the driver, not of the ++// registered targets: an RDC device compile stays a single -cc1 invocation ++// that emits the object directly, rather than being split into a separate ++// -emit-llvm-bc job plus a backend job. ++ ++// RUN: %clang -### -x hip --target=x86_64-linux-gnu --offload=spirv64 \ ++// RUN: --no-offload-new-driver -fgpu-rdc --hip-path=%S/Inputs/hipspv \ ++// RUN: -nohipwrapperinc %S/Inputs/hip_multiple_inputs/a.cu \ ++// RUN: 2>&1 | FileCheck --check-prefix=RDC-JOB %s ++ ++// RDC-JOB: "-cc1" "-triple" "spirv64" ++// RDC-JOB-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" ++// RDC-JOB-SAME: "-emit-obj" ++// RDC-JOB-SAME: "-fcuda-is-device" ++ ++// -fno-integrated-objemitter selects the external llvm-spirv translator, and ++// it is accepted in either configuration. ++ ++// RUN: touch %t.o ++// RUN: %clang -### --no-default-config -o %t.img \ ++// RUN: --target=spirv64-unknown-chipstar %t.o --hip-path=%S/Inputs/hipspv \ ++// RUN: -fno-integrated-objemitter \ ++// RUN: 2>&1 | FileCheck --check-prefix=XTOR -DHIP_PATH=%S/Inputs/hipspv %s ++ ++// XTOR: {{".*llvm-link"}} ++// XTOR-SAME: "-o" [[LINK_BC:".*bc"]] "{{[^ ]*.o}}" ++ ++// XTOR: {{".*opt"}} [[LINK_BC]] "-load-pass-plugin" ++// XTOR-SAME: "[[HIP_PATH]]/lib/libLLVMHipSpvPasses.so" ++// XTOR-SAME: "-passes=hip-post-link-passes" "-o" [[LOWER_BC:".*bc"]] ++ ++// XTOR: {{".*llvm-spirv.*"}} "--spirv-max-version=1.2" ++// XTOR-SAME: [[LOWER_BC]] "-o" "{{.*img}}" ++// XTOR-NOT: "-cc1" +diff --git a/clang/test/Driver/hipspv-pass-plugin.hip b/clang/test/Driver/hipspv-pass-plugin.hip +index 3a0979a..ae6194b 100644 +--- a/clang/test/Driver/hipspv-pass-plugin.hip ++++ b/clang/test/Driver/hipspv-pass-plugin.hip +@@ -1,3 +1,4 @@ ++// REQUIRES: spirv-registered-target + // UNSUPPORTED: system-windows + + // RUN: %clang -### -target x86_64-linux-gnu --offload=spirv64 \ +@@ -16,23 +17,24 @@ + // RUN: --no-offload-new-driver -nogpuinc -nogpulib %s \ + // RUN: 2>&1 | FileCheck --check-prefixes=ALL,NO-PLUGIN %s + +-// Run commands for the new offload driver: ++// Run commands for the new offload driver (chipStar uses in-tree SPIR-V ++// backend instead of llvm-spirv): + + // RUN: touch %t.dummy.o +-// RUN: %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ ++// RUN: env "PATH=" %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ + // RUN: %t.dummy.o --hip-path=%S/Inputs/hipspv \ +-// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FROM-HIP-PATH ++// RUN: 2>&1 | FileCheck %s --check-prefixes=CHIPSTAR,FROM-HIP-PATH + +-// RUN: %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ ++// RUN: env "PATH=" %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ + // RUN: %t.dummy.o --hipspv-pass-plugin=%S/Inputs/pass-plugin.so \ +-// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FROM-OPTION ++// RUN: 2>&1 | FileCheck %s --check-prefixes=CHIPSTAR,FROM-OPTION + +-// RUN: not %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ ++// RUN: not env "PATH=" %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ + // RUN: %t.dummy.o --hipspv-pass-plugin=foo.so \ +-// RUN: 2>&1 | FileCheck %s --check-prefixes=ALL,FROM-OPTION-INVALID ++// RUN: 2>&1 | FileCheck %s --check-prefixes=CHIPSTAR,FROM-OPTION-INVALID + +-// RUN: %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ +-// RUN: %t.dummy.o 2>&1 | FileCheck %s --check-prefixes=ALL,NO-PLUGIN ++// RUN: env "PATH=" %clang -### --no-default-config -o /dev/null --target=spirv64-unknown-chipstar \ ++// RUN: %t.dummy.o 2>&1 | FileCheck %s --check-prefixes=CHIPSTAR,NO-PLUGIN + + // FROM-HIP-PATH: {{".*opt"}} {{".*.bc"}} "-load-pass-plugin" + // FROM-HIP-PATH-SAME: {{".*/Inputs/hipspv/lib/libLLVMHipSpvPasses.so"}} +@@ -42,3 +44,5 @@ + // NO-PLUGIN-NOT: {{".*opt"}} {{".*.bc"}} "-load-pass-plugin" + // NO-PLUGIN-NOT: {{".*/Inputs/hipspv/lib/libLLVMHipSpvPasses.so"}} + // ALL: {{".*llvm-spirv[^ ]*"}} ++// CHIPSTAR: {{".*clang.*"}} "-cc1" ++// CHIPSTAR-SAME: "-emit-obj" +diff --git a/clang/test/Driver/hipspv-toolchain.hip b/clang/test/Driver/hipspv-toolchain.hip +index 64d5d22..3a262a2 100644 +--- a/clang/test/Driver/hipspv-toolchain.hip ++++ b/clang/test/Driver/hipspv-toolchain.hip +@@ -60,6 +60,10 @@ + // RUN: llvm-offload-binary -o %t.dev.out \ + // RUN: --image=file=%t.dev.bc,kind=hip,triple=spirv64-unknown-chipstar,arch=generic + ++// The linker wrapper forwards --hip-path from --device-compiler= to the inner ++// clang invocation; the HIPSPV toolchain inside that clang then drives the ++// llvm-link / opt (HipSpvPasses) / SPIR-V backend pipeline (covered by the ++// CHIPSTAR run below). + // RUN: clang-linker-wrapper --dry-run \ + // RUN: --device-compiler=spirv64-unknown-chipstar=--hip-path="%S/Inputs/hipspv" \ + // RUN: --host-triple=spirv64-unknown-chipstar \ +@@ -72,6 +76,8 @@ + // WRAPPER-SAME: {{[^ ]*.o}} + // WRAPPER-SAME: --hip-path=[[HIP_PATH]] + ++// The in-tree SPIR-V backend is the default emitter; PATH content (e.g. a ++// stray llvm-spirv) must not affect the choice. + // RUN: touch %t.dummy.o + // RUN: %clang -### --no-default-config -o %t.dummy.img \ + // RUN: --target=spirv64-unknown-chipstar %t.dummy.o \ +@@ -85,8 +91,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.*"}} "-cc1" "-triple" "spirv64-unknown-chipstar" ++// CHIPSTAR-SAME: "-emit-obj" ++// CHIPSTAR-SAME: "-mllvm" "-spirv-ext=+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_KHR_bit_instructions,+SPV_EXT_shader_atomic_float_add,+SPV_KHR_non_semantic_info,+SPV_INTEL_optnone" + // CHIPSTAR-SAME: [[LOWER_BC]] "-o" "[[SPIRV_OUT:.*img]]" + + // RUN: %clang -### --no-default-config -o %t.dummy.img \ +@@ -101,10 +108,27 @@ + // 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.*"}} "-cc1" "-triple" "spirv64v1.3-unknown-chipstar" ++// CHIPSTAR-SUBARCH-SAME: "-emit-obj" ++// CHIPSTAR-SUBARCH-SAME: "-mllvm" "-spirv-ext=+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_KHR_bit_instructions,+SPV_EXT_shader_atomic_float_add,+SPV_KHR_non_semantic_info,+SPV_INTEL_optnone" + // CHIPSTAR-SUBARCH-SAME: [[LOWER_BC]] "-o" "[[SPIRV_OUT:.*img]]" + ++// -fno-integrated-objemitter selects the external llvm-spirv translator. ++// RUN: %clang -### --no-default-config -o %t.dummy.img \ ++// RUN: --target=spirv64-unknown-chipstar %t.dummy.o \ ++// RUN: --hip-path="%S/Inputs/hipspv" -fno-integrated-objemitter \ ++// RUN: 2>&1 | FileCheck %s --check-prefix=CHIPSTAR-XTOR -DHIP_PATH=%S/Inputs/hipspv ++ ++// CHIPSTAR-XTOR: {{".*opt"}} {{".*bc"}} "-load-pass-plugin" ++// CHIPSTAR-XTOR-SAME: "[[HIP_PATH]]/lib/libLLVMHipSpvPasses.so" ++// CHIPSTAR-XTOR-SAME: "-passes=hip-post-link-passes" "-o" [[LOWER_BC:".*bc"]] ++ ++// CHIPSTAR-XTOR: {{".*llvm-spirv.*"}} "--spirv-max-version=1.2" ++// CHIPSTAR-XTOR-SAME: "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_KHR_bit_instructions,+SPV_EXT_shader_atomic_float_add" ++// CHIPSTAR-XTOR-SAME: "--spirv-ext=+SPV_KHR_non_semantic_info,+SPV_INTEL_optnone" ++// CHIPSTAR-XTOR-SAME: "--spirv-debug-info-version=nonsemantic-shader-200" ++// CHIPSTAR-XTOR-SAME: [[LOWER_BC]] "-o" "{{.*img}}" ++ + // Check unknown linker options are ignored - such as ones that are targeted at + // spirv-link. HIPSPV toolchain does linking via llvm-link. + // RUN: %clang -### --no-default-config -o %t.dummy.img \ +@@ -123,9 +147,21 @@ + // RUN: | FileCheck -DVERSION=%llvm-version-major \ + // RUN: --check-prefix=VERSIONED %s + ++// With -fno-integrated-objemitter the chipStar path must pick the same ++// versioned translator (lookup shared with SPIRV::constructTranslateCommand). + // 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 ++// RUN: -o %t.dummy.img --target=spirv64-unknown-chipstar %t.dummy.o \ ++// RUN: --hip-path="%S/Inputs/hipspv" -fno-integrated-objemitter 2>&1 \ ++// RUN: | FileCheck -DVERSION=%llvm-version-major --check-prefix=VERSIONED %s + + // VERSIONED: {{.*}}llvm-spirv-[[VERSION]] ++ ++//----------------------------------------------------------------------------- ++// The debug-info flags are passed regardless of -g (covered by the ++// CHIPSTAR-XTOR checks above): in RDC-mode links this job runs in a clang ++// invoked by clang-linker-wrapper where the original -g is not visible, but ++// debug info travels in the bitcode and the flags are no-ops without it. ++// RUN: %clang -### --no-default-config -g -o %t.dummy.img \ ++// RUN: --target=spirv64-unknown-chipstar %t.dummy.o \ ++// RUN: --hip-path="%S/Inputs/hipspv" -fno-integrated-objemitter \ ++// RUN: 2>&1 | FileCheck %s --check-prefix=CHIPSTAR-XTOR -DHIP_PATH=%S/Inputs/hipspv +diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +index be14064..5899f60 100644 +--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp ++++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +@@ -91,7 +91,8 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, + if (TargetTriple.getOS() == Triple::Vulkan) + Env = Shader; + else if (TargetTriple.getOS() == Triple::OpenCL || +- TargetTriple.getVendor() == Triple::AMD) ++ TargetTriple.getVendor() == Triple::AMD || ++ TargetTriple.getOS() == Triple::ChipStar) + Env = Kernel; + else + Env = Unknown; +-- +2.43.0 + diff --git a/llvm-patches/llvm-23/llvm/0002-preserve-device-debug-info.patch b/llvm-patches/llvm-23/llvm/0002-preserve-device-debug-info.patch new file mode 100644 index 000000000..c4b1b59a4 --- /dev/null +++ b/llvm-patches/llvm-23/llvm/0002-preserve-device-debug-info.patch @@ -0,0 +1,68 @@ +From b2b3db6a36ebdd3955dce983bb137ae6767c15c2 Mon Sep 17 00:00:00 2001 +From: chipStar +Date: Sat, 18 Jul 2026 14:18:22 +0300 +Subject: [PATCH 2/2] Preserve device debug info when the SPIR-V backend emits + +HIPSPVToolChain::adjustDebugInfoKind() unconditionally forced NoDebugInfo, +so -g/-O0 produced device SPIR-V with no debug metadata at all and +gdb-oneapi could not resolve source lines or locals in device code. + +Honor the requested debug level, but only when the module is actually +emitted by the in-tree SPIR-V backend (see +0001-hipspv-in-tree-spirv-backend.patch). The SPIRV-LLVM-Translator +encodes DebugTypeComposite with a Parent operand, which yields a cyclic +forward reference: spirv-val rejects the result and IGC reports an +internal error, so -g must keep being stripped on that path. The gate +mirrors the emitter choice made in constructLinkAndEmitSpirvCommand(), +which means -fno-integrated-objemitter (and a clang built without the +SPIR-V target) gets the strip too. + +Stripping here rather than at translation time means clang CodeGen never +emits a DICompileUnit, so no downstream pass can orphan debug metadata. + +The translator/backend invocations already request +NonSemantic.Shader.DebugInfo (SPV_KHR_non_semantic_info, +--spirv-debug-info-version=nonsemantic-shader-200) and SPV_INTEL_optnone; +those flags are no-ops when the bitcode carries no debug info. + +Refs: CHIP-SPV/chipStar#1004 +Applies-to: LLVM llvmorg-23.1.0-rc2 +Upstream-status: the unconditional form was upstreamed in +llvm/llvm-project#210504 (3093d8c577d7); the backend gate added here is +chipStar-specific and not upstream. +--- +diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp +index 98bec18..e4aaf79 100644 +--- a/clang/lib/Driver/ToolChains/HIPSPV.cpp ++++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp +@@ -423,10 +423,23 @@ VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D, + void HIPSPVToolChain::adjustDebugInfoKind( + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + const llvm::opt::ArgList &Args) const { +- // Debug info generation is disabled for SPIRV-LLVM-Translator +- // which currently aborts on the presence of DW_OP_LLVM_convert. +- // TODO: Enable debug info when the SPIR-V backend arrives. +- DebugInfoKind = llvm::codegenoptions::NoDebugInfo; ++ // Device debug info is only usable when the in-tree SPIR-V backend emits the ++ // module. The SPIRV-LLVM-Translator encodes DebugTypeComposite with a Parent ++ // operand, which produces a cyclic forward reference that spirv-val rejects ++ // and that device compilers mis-handle (IGC internal errors); the backend ++ // avoids the cycle structurally. So honor the requested debug level only ++ // when the effective emitter is the backend, and otherwise keep forcing ++ // NoDebugInfo. Doing it here rather than at translation time means no debug ++ // metadata is generated at all: the module carries no DICompileUnit, so ++ // nothing downstream can orphan it. ++ // ++ // constructLinkAndEmitSpirvCommand() makes the same ++ // useIntegratedBackend()/isSPIRVBackendAvailable() choice, so a user passing ++ // -fno-integrated-objemitter (or a clang built without the SPIR-V target) ++ // gets the strip as well. ++ if (!useIntegratedBackend() || !isSPIRVBackendAvailable(getTriple())) ++ DebugInfoKind = llvm::codegenoptions::NoDebugInfo; ++ (void)Args; + } + + LTOKind HIPSPVToolChain::getLTOMode(const llvm::opt::ArgList &Args, +-- +2.43.0 + diff --git a/llvm-patches/llvm-23/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch b/llvm-patches/llvm-23/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch new file mode 100644 index 000000000..f107a286b --- /dev/null +++ b/llvm-patches/llvm-23/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch @@ -0,0 +1,34 @@ +From 2f97fcc8ea8ab9f8a417daa679d603158f5ea9ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pekka=20J=C3=A4=C3=A4skel=C3=A4inen?= + +Date: Thu, 15 Dec 2022 19:31:18 +0200 +Subject: [PATCH 1/2] Pretend the SPIR ver needed by shuffles is 1.2 + +In reality the SPIR-V shuffles and ballot operations +require v1.3, but they seem to work with Intel's v1.2 +implementation (likely due to the extensions). + +Until v1.3 support is added to the driver, let's just pretend +these are v1.2 features to allow CHIPSPV warp-level functions +to compile. + +Applies-to: SPIRV-LLVM-Translator llvm_release_230 +Upstream-status: deliberate spec deviation, not upstreamable (the +GroupNonUniform* capabilities genuinely require SPIR-V 1.3 per spec). +--- +diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h +index e3f9448..ba0e673 100644 +--- a/lib/SPIRV/libSPIRV/SPIRVEntry.h ++++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h +@@ -921,7 +921,7 @@ public: + case CapabilityGroupNonUniformShuffle: + case CapabilityGroupNonUniformShuffleRelative: + case CapabilityGroupNonUniformClustered: +- return VersionNumber::SPIRV_1_3; ++ return VersionNumber::SPIRV_1_2; + + case CapabilityFloatControls2: + return VersionNumber::SPIRV_1_2; +-- +2.43.0 + diff --git a/llvm-patches/llvm-23/spirv-translator/0002-coalesce-duplicate-phi-predecessors.patch b/llvm-patches/llvm-23/spirv-translator/0002-coalesce-duplicate-phi-predecessors.patch new file mode 100644 index 000000000..4e78b0330 --- /dev/null +++ b/llvm-patches/llvm-23/spirv-translator/0002-coalesce-duplicate-phi-predecessors.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chipStar +Date: Wed, 18 Jun 2026 00:00:00 +0000 +Subject: [PATCH 2/2] Coalesce duplicate predecessors when emitting OpPhi + +LLVM IR allows a PHI to list the same predecessor block more than once +(e.g. a switch with several cases branching to the same block); the LLVM +verifier guarantees the duplicate entries carry identical incoming values. +SPIR-V's OpPhi requires exactly one (value, parent block) pair per +predecessor, so emitting the duplicates verbatim yields invalid SPIR-V +("OpPhi's number of incoming blocks does not match block's predecessor +count"), which IGC then mis-handles (nondeterministic crash / miscompile). + +Skip duplicate predecessor entries when building the OpPhi operand list. + +Applies-to: SPIRV-LLVM-Translator llvm_release_230 +Upstream-status: same defect fixed upstream-pending in +KhronosGroup/SPIRV-LLVM-Translator#3866 (approved, unmerged). +chipStar regression test: tests/compiler/TestSpirvDuplicatePhiHip.hip. +--- +diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp +index d2b564a..5f44c80 100644 +--- a/lib/SPIRV/SPIRVWriter.cpp ++++ b/lib/SPIRV/SPIRVWriter.cpp +@@ -2645,7 +2645,18 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, + std::vector IncomingPairs; + SPIRVType *Ty = transScavengedType(Phi); + ++ // SPIR-V requires OpPhi to have exactly one (value, parent block) pair per ++ // predecessor block. LLVM IR, however, permits a PHI to list the same ++ // predecessor multiple times (e.g. a switch with several cases branching ++ // to this block); the LLVM verifier guarantees those duplicate entries ++ // carry identical incoming values. Emitting them verbatim produces an ++ // invalid OpPhi (more parent blocks than the block has predecessors), so ++ // coalesce duplicate predecessors to a single entry. ++ SmallPtrSet SeenPreds; + for (size_t I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) { ++ const BasicBlock *IncomingBB = Phi->getIncomingBlock(I); ++ if (!SeenPreds.insert(IncomingBB).second) ++ continue; // duplicate predecessor; value is identical, skip it + SPIRVValue *Val = transValue(Phi->getIncomingValue(I), BB, true, + FuncTransMode::Pointer); + if (Val->getType() != Ty) +-- +2.43.0 + From 08505620196c055388d541d58dd5627e46225c8f Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:21:21 +0300 Subject: [PATCH 03/22] scripts: support --version 23 in configure_llvm.sh 23 maps to the upstream tag llvmorg-23.1.0-rc2 (not release/23.x, which moves) with the translator branch llvm_release_230 and the patches in llvm-patches/llvm-23/. LLVM 23 removed the LLVM_ENABLE_PROJECTS=openmp build mode, so openmp moves to LLVM_ENABLE_RUNTIMES there. This has to stay conditional: 21 and 22 still expect openmp as a project, and CI hard-fails when omp.h is missing from the resulting install. --- scripts/configure_llvm.sh | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/scripts/configure_llvm.sh b/scripts/configure_llvm.sh index e1ef4c21a..8d91ff77c 100755 --- a/scripts/configure_llvm.sh +++ b/scripts/configure_llvm.sh @@ -78,8 +78,9 @@ done # check mandatory argument version if [ -z "$VERSION" ]; then echo "Usage: $0 --version --install-dir --link-type static/dynamic(default) [--variant translator|native] [--with-binutils [path]] [--configure-only] [-N]" - echo "--version: LLVM version 20, 21, 22, or latest" + echo "--version: LLVM version 20, 21, 22, 23, or latest" echo " 20/21/22: upstream release branch plus patches from llvm-patches/llvm-/" + echo " 23: upstream tag llvmorg-23.1.0-rc2 plus patches from llvm-patches/llvm-23/" echo " latest (experimental): CHIP-SPV/llvm-project branch chipStar-llvm-23, maintained" echo " directly with no patches (patches exist only for the release-pinned versions)" echo "--install-dir: installation directory" @@ -99,8 +100,8 @@ fi # validate version argument if [ "$VERSION" != "20" ] && [ "$VERSION" != "21" ] && [ "$VERSION" != "22" ] \ - && [ "$VERSION" != "latest" ]; then - echo "Invalid version '$VERSION'. Must be 20, 21, 22, or latest." + && [ "$VERSION" != "23" ] && [ "$VERSION" != "latest" ]; then + echo "Invalid version '$VERSION'. Must be 20, 21, 22, 23, or latest." echo "(Support for LLVM 17, 18, and 19 has been dropped.)" exit 1 fi @@ -137,12 +138,31 @@ if [ "$VERSION" == "latest" ]; then LLVM_REPO="https://github.com/CHIP-SPV/llvm-project.git" LLVM_BRANCH="chipStar-llvm-23" TRANSLATOR_BRANCH="llvm_release_230" +elif [ "$VERSION" == "23" ]; then + # Pinned to a release candidate tag rather than release/23.x: the branch + # moves, and the llvm-patches/llvm-23 series (in particular the llvm#213052 + # backport) is verified against this exact tree. + LLVM_REPO="https://github.com/llvm/llvm-project.git" + LLVM_BRANCH="llvmorg-23.1.0-rc2" + TRANSLATOR_BRANCH="llvm_release_230" else LLVM_REPO="https://github.com/llvm/llvm-project.git" LLVM_BRANCH="release/${VERSION}.x" TRANSLATOR_BRANCH="llvm_release_${VERSION}0" fi +# LLVM 23 removed the LLVM_ENABLE_PROJECTS=openmp build mode; openmp has to be +# built as a runtime there. Earlier versions still expect it as a project, and +# CI hard-fails when omp.h is missing from the install (TestHipccFopenmp), so +# this has to stay version conditional. +if [ "$VERSION" == "23" ] || [ "$VERSION" == "latest" ]; then + LLVM_PROJECTS="clang;clang-tools-extra" + LLVM_RUNTIMES="openmp" +else + LLVM_PROJECTS="clang;openmp;clang-tools-extra" + LLVM_RUNTIMES="" +fi + export LLVM_DIR=`pwd`/llvm-project/llvm # If we're only emitting the cmake command, skip the git operations @@ -301,7 +321,7 @@ COMMON_CMAKE_OPTIONS=( "-DCMAKE_C_COMPILER=${CC}" "-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}" "-DCMAKE_BUILD_TYPE=Release" - "-DLLVM_ENABLE_PROJECTS=\"clang;openmp;clang-tools-extra\"" + "-DLLVM_ENABLE_PROJECTS=\"${LLVM_PROJECTS}\"" "-DLLVM_TARGETS_TO_BUILD=\"${LLVM_TARGETS}\"" "-DLLVM_ENABLE_ASSERTIONS=On" "-DLLVM_INCLUDE_TESTS=OFF" @@ -310,6 +330,10 @@ COMMON_CMAKE_OPTIONS=( "-DLLVM_INCLUDE_DOCS=OFF" ) +if [ -n "${LLVM_RUNTIMES}" ]; then + COMMON_CMAKE_OPTIONS+=("-DLLVM_ENABLE_RUNTIMES=\"${LLVM_RUNTIMES}\"") +fi + # Linux-specific flags if [[ "$(uname)" != "Darwin" ]]; then COMMON_CMAKE_OPTIONS+=( From 5d7c1cabe718d6561f1af59378232cb1687302e0 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:23:24 +0300 Subject: [PATCH 04/22] Drop LLVM 20 support The supported set becomes 21, 22, and 23. Removes llvm-patches/llvm-20/, the 20 option in configure_llvm.sh, and raises the LLVMCheck.cmake floor to 21.0.0. Documentation examples that named LLVM 20 are moved to 22. llvm-patches/README.md kept describing llvm-20 as the reference set every other version was trimmed down from, so llvm-21 takes that role and its table is spelled out in full. --- MacOS-Issues.md | 2 +- README.md | 22 +-- cmake/LLVMCheck.cmake | 4 +- docs/MacOS.md | 24 +-- llvm-patches/README.md | 58 ++----- .../0001-spirv-version-and-extensions.patch | 51 ------ .../0002-preserve-device-debug-info.patch | 89 ---------- ...003-unbundle-static-device-libraries.patch | 82 --------- .../llvm/0004-fix-spirv-data-layout.patch | 71 -------- .../llvm-20/llvm/0005-macos-hip-spirv.patch | 155 ------------------ ...-pretend-subgroup-caps-are-spirv-1.2.patch | 37 ----- .../0002-fix-loop-merge-placement.patch | 75 --------- .../0003-fix-block-merge-innermost-loop.patch | 53 ------ ...-coalesce-duplicate-phi-predecessors.patch | 48 ------ scripts/configure_llvm.sh | 12 +- 15 files changed, 50 insertions(+), 733 deletions(-) delete mode 100644 llvm-patches/llvm-20/llvm/0001-spirv-version-and-extensions.patch delete mode 100644 llvm-patches/llvm-20/llvm/0002-preserve-device-debug-info.patch delete mode 100644 llvm-patches/llvm-20/llvm/0003-unbundle-static-device-libraries.patch delete mode 100644 llvm-patches/llvm-20/llvm/0004-fix-spirv-data-layout.patch delete mode 100644 llvm-patches/llvm-20/llvm/0005-macos-hip-spirv.patch delete mode 100644 llvm-patches/llvm-20/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch delete mode 100644 llvm-patches/llvm-20/spirv-translator/0002-fix-loop-merge-placement.patch delete mode 100644 llvm-patches/llvm-20/spirv-translator/0003-fix-block-merge-innermost-loop.patch delete mode 100644 llvm-patches/llvm-20/spirv-translator/0004-coalesce-duplicate-phi-predecessors.patch diff --git a/MacOS-Issues.md b/MacOS-Issues.md index 48ba79f53..14f331ba0 100644 --- a/MacOS-Issues.md +++ b/MacOS-Issues.md @@ -110,7 +110,7 @@ For macOS development, use **Option A** (dynamic LLVM). The `configure_llvm.sh` ### Required Dependencies - Homebrew packages: `spirv-tools`, `cmake`, `ninja` -- Environment modules: `llvm/20.0` (or newer), `ocl-icd-loader`, `pocl` +- Environment modules: `llvm/22.0` (or newer), `ocl-icd-loader`, `pocl` ### Build Command ```bash diff --git a/README.md b/README.md index c59e46394..b59188eee 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,11 @@ Release notes for [1.3](docs/release_notes/chipStar_1.3.rst), [1.2](docs/release ## Prerequisites * Cmake >= 3.20.0 -* Clang and LLVM 20, 21, 22 (plus an experimental `latest` option tracking the maintained [chipStar-llvm-23](https://github.com/CHIP-SPV/llvm-project/tree/chipStar-llvm-23) branch) - * Can be installed, for example, by adding the [LLVM's Debian/Ubuntu repository](https://apt.llvm.org/) and installing packages 'clang-20 llvm-20 clang-tools-20'. +* Clang and LLVM 21, 22, 23 (plus an experimental `latest` option tracking the maintained [chipStar-llvm-23](https://github.com/CHIP-SPV/llvm-project/tree/chipStar-llvm-23) branch) + * Can be installed, for example, by adding the [LLVM's Debian/Ubuntu repository](https://apt.llvm.org/) and installing packages 'clang-21 llvm-21 clang-tools-21'. * For the best results, build Clang/LLVM with the chipStar patches applied (from `llvm-patches/llvm-/`). See below for a scripted way to build and install the patched versions. * SPIRV-LLVM-Translator from a branch matching the LLVM major version: - (e.g. llvm\_release\_200 for LLVM 20, llvm\_release\_210 for LLVM 21) + (e.g. llvm\_release\_210 for LLVM 21, llvm\_release\_220 for LLVM 22) , [llvm-spirv](https://github.com/KhronosGroup/SPIRV-LLVM-Translator). * Make sure the built llvm-spirv binary is installed into the same path as clang binary, otherwise clang might find and use a different llvm-spirv, leading to errors. * SPIRV-Tools and SPIRV-Headers: @@ -101,12 +101,12 @@ For this you can use a script included in the chipStar repository: ```bash ./scripts/configure_llvm.sh Usage: ./scripts/configure_llvm.sh --version --install-dir --link-type static/dynamic(default) [--variant translator|native] [--with-binutils [path]] [--configure-only] [-N] ---version: LLVM version 20, 21, 22, or latest (experimental, tracks the maintained chipStar-llvm-23 branch, no patches) +--version: LLVM version 21, 22, 23, or latest (experimental, tracks the maintained chipStar-llvm-23 branch, no patches) --install-dir: installation directory --link-type: static or dynamic (default: dynamic) -./scripts/configure_llvm.sh --version 20 --install-dir /opt/install/llvm/20.0 -cd llvm-project/llvm/build_20 +./scripts/configure_llvm.sh --version 22 --install-dir /opt/install/llvm/22.0 +cd llvm-project/llvm/build_22 make -j 16 make install ``` @@ -114,13 +114,13 @@ make -j 16 Or you can do the steps manually (clone the release branches, apply the patches from `llvm-patches/llvm-/`, then build): ```bash -git clone --depth 1 https://github.com/llvm/llvm-project.git -b release/20.x +git clone --depth 1 https://github.com/llvm/llvm-project.git -b release/22.x cd llvm-project -for p in /path/to/chipStar/llvm-patches/llvm-20/llvm/*.patch; do git apply "$p"; done +for p in /path/to/chipStar/llvm-patches/llvm-22/llvm/*.patch; do git apply "$p"; done cd llvm/projects -git clone --depth 1 https://github.com/KhronosGroup/SPIRV-LLVM-Translator.git -b llvm_release_200 +git clone --depth 1 https://github.com/KhronosGroup/SPIRV-LLVM-Translator.git -b llvm_release_220 cd SPIRV-LLVM-Translator -for p in /path/to/chipStar/llvm-patches/llvm-20/spirv-translator/*.patch; do git apply "$p"; done +for p in /path/to/chipStar/llvm-patches/llvm-22/spirv-translator/*.patch; do git apply "$p"; done cd ../../.. # DLLVM_ENABLE_PROJECTS="clang;openmp" OpenMP is optional but many apps use it @@ -131,7 +131,7 @@ cmake -S llvm -B build \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_ENABLE_PROJECTS="clang;openmp" \ -DLLVM_TARGETS_TO_BUILD=X86 \ - -DCMAKE_INSTALL_PREFIX=$HOME/local/llvm-20 + -DCMAKE_INSTALL_PREFIX=$HOME/local/llvm-22 make -C build -j8 all install ``` diff --git a/cmake/LLVMCheck.cmake b/cmake/LLVMCheck.cmake index dcc6bb77a..2ac892cf1 100644 --- a/cmake/LLVMCheck.cmake +++ b/cmake/LLVMCheck.cmake @@ -1,10 +1,10 @@ if((CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang") OR (CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM")) - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20.0.0) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 21.0.0) message(FATAL_ERROR "Unsupported clang version '${CMAKE_CXX_COMPILER_VERSION}'. " - "chipStar requires clang/LLVM 20, 21, or 22 (or the experimental " + "chipStar requires clang/LLVM 21, 22, or 23 (or the experimental " "'latest' toolchain); see scripts/configure_llvm.sh.") endif() else() diff --git a/docs/MacOS.md b/docs/MacOS.md index 70248e86b..c8ffe51f2 100644 --- a/docs/MacOS.md +++ b/docs/MacOS.md @@ -199,7 +199,7 @@ Note: `coreutils` provides the `nproc` command which will be used throughout thi ## Step 2.5: Install Environment Modules (Optional) -Environment Modules provides a convenient way to manage environment variables for different software versions. If you prefer using `module load llvm/20.0` instead of manually setting PATH variables, install it: +Environment Modules provides a convenient way to manage environment variables for different software versions. If you prefer using `module load llvm/22.0` instead of manually setting PATH variables, install it: ```bash brew install modules @@ -233,7 +233,7 @@ chipStar requires a specific version of LLVM/Clang (20, 21, or 22) with patches. ### Using the chipStar configure script: ```bash -./scripts/configure_llvm.sh --version 20 --install-dir $HOME/install/llvm-20 +./scripts/configure_llvm.sh --version 22 --install-dir $HOME/install/llvm-22 cd llvm-project/llvm/build_20 make -j$(nproc) make install @@ -242,7 +242,7 @@ make install Add LLVM to your PATH: ```bash -echo 'export PATH="$HOME/install/llvm-20/bin:$PATH"' >> ~/.zshrc +echo 'export PATH="$HOME/install/llvm-22/bin:$PATH"' >> ~/.zshrc source ~/.zshrc ``` @@ -269,7 +269,7 @@ spirv-as --version Note: The `spirv-extractor` tool in chipStar expects SPIRV-Tools headers at `/opt/homebrew/include/spirv-tools/` (Apple Silicon) or `/usr/local/include/spirv-tools/` (Intel). -**Note on SPIRV-LLVM-Translator**: The `llvm-spirv` tool is automatically built as part of the LLVM build process since the chipStar configure script clones it into `llvm-project/llvm/projects/SPIRV-LLVM-Translator`. It will be installed in `$HOME/install/llvm-20/bin/`. +**Note on SPIRV-LLVM-Translator**: The `llvm-spirv` tool is automatically built as part of the LLVM build process since the chipStar configure script clones it into `llvm-project/llvm/projects/SPIRV-LLVM-Translator`. It will be installed in `$HOME/install/llvm-22/bin/`. ## Step 5: Build OpenCL Components @@ -320,8 +320,8 @@ mkdir build && cd build cmake .. \ -DCMAKE_INSTALL_PREFIX=$HOME/install \ -DENABLE_SPIR=ON \ - -DLLVM_DIR=$HOME/install/llvm-20/lib/cmake/llvm \ - -DLLVM_CONFIG=$HOME/install/llvm-20/bin/llvm-config + -DLLVM_DIR=$HOME/install/llvm-22/lib/cmake/llvm \ + -DLLVM_CONFIG=$HOME/install/llvm-22/bin/llvm-config make -j$(nproc) && make install cd ../../.. @@ -360,7 +360,7 @@ clinfo -l ```bash mkdir build && cd build cmake .. \ - -DLLVM_CONFIG_BIN=$HOME/install/llvm-20/bin/llvm-config \ + -DLLVM_CONFIG_BIN=$HOME/install/llvm-22/bin/llvm-config \ -DCMAKE_INSTALL_PREFIX=$HOME/install/chipStar \ -GNinja ninja -j$(nproc) all build_tests install @@ -392,9 +392,9 @@ python3 scripts/check.py build pocl opencl ### Installation Locations All dependencies are installed to `$HOME/install`: -- **LLVM/Clang**: `$HOME/install/llvm-20/` +- **LLVM/Clang**: `$HOME/install/llvm-22/` - **SPIRV-Tools**: `/opt/homebrew/` or `/usr/local/` (via Homebrew) -- **SPIRV-LLVM-Translator**: `$HOME/install/llvm-20/` +- **SPIRV-LLVM-Translator**: `$HOME/install/llvm-22/` - **OpenCL Headers**: `$HOME/install/include/CL/` - **OpenCL ICD Loader**: `$HOME/install/lib/libOpenCL.dylib` - **PoCL**: `$HOME/install/lib/pocl/` or `$HOME/install/lib/` @@ -412,9 +412,9 @@ All dependencies are installed to `$HOME/install`: Add these to your `~/.zshrc`: ```bash -export PATH="$HOME/install/llvm-20/bin:$PATH" +export PATH="$HOME/install/llvm-22/bin:$PATH" export PATH="$HOME/install/bin:$PATH" -export LLVM_DIR="$HOME/install/llvm-20/lib/cmake/llvm" +export LLVM_DIR="$HOME/install/llvm-22/lib/cmake/llvm" export LD_LIBRARY_PATH="$HOME/install/lib:$LD_LIBRARY_PATH" export DYLD_LIBRARY_PATH="$HOME/install/lib:$DYLD_LIBRARY_PATH" @@ -460,7 +460,7 @@ which llvm-config-20 If not found, add to your `~/.zshrc`: ```bash -export PATH="$HOME/install/llvm-20/bin:$PATH" +export PATH="$HOME/install/llvm-22/bin:$PATH" source ~/.zshrc ``` diff --git a/llvm-patches/README.md b/llvm-patches/README.md index 269b42514..8641a4ed2 100644 --- a/llvm-patches/README.md +++ b/llvm-patches/README.md @@ -5,12 +5,9 @@ a small set of patches, kept in one directory per supported LLVM version: ``` llvm-patches/ -├── llvm-20/ +├── llvm-21/ │ ├── llvm/ patches applied in the llvm-project checkout │ └── spirv-translator/ patches applied in the SPIRV-LLVM-Translator checkout -├── llvm-21/ -│ ├── llvm/ -│ └── spirv-translator/ ├── llvm-22/ │ ├── llvm/ │ └── spirv-translator/ @@ -19,7 +16,7 @@ llvm-patches/ └── spirv-translator/ ``` -`scripts/configure_llvm.sh --version <20|21|22|23>` clones the matching +`scripts/configure_llvm.sh --version <21|22|23>` clones the matching upstream LLVM ref (`release/.x`, except 23 which is pinned to the tag `llvmorg-23.1.0-rc2`) together with the translator branch `llvm_release_0`, and applies every patch in the version's @@ -38,22 +35,24 @@ the release-pinned versions. | LLVM Version | Source | Patches | |---|---|---| -| 20 | `llvm/llvm-project` `release/20.x` | `llvm-patches/llvm-20/` | | 21 | `llvm/llvm-project` `release/21.x` | `llvm-patches/llvm-21/` | | 22 | `llvm/llvm-project` `release/22.x` | `llvm-patches/llvm-22/` | | 23 | `llvm/llvm-project` `llvmorg-23.1.0-rc2` | `llvm-patches/llvm-23/` | | latest (experimental) | `CHIP-SPV/llvm-project` `chipStar-llvm-23` | none | -LLVM 17, 18, and 19 support was dropped. +LLVM 17 through 20 support was dropped. + +## llvm-21 -## llvm-20 +The reference set the later versions are trimmed down from. The numbering +gap is deliberate: 0002-preserve-device-debug-info was removed, since both +SPIR-V producers reachable on 21 emit debug info that `spirv-val` rejects. ### llvm/ | Patch | Purpose | Upstream status | |---|---|---| | 0001-spirv-version-and-extensions | Enable SPIR-V 1.2 (warp-level primitives via subgroup extensions) and restrict `--spirv-ext` to only the required extensions | Upstreamed in LLVM 23+ behind `Triple::ChipStar` ([llvm#179902](https://github.com/llvm/llvm-project/pull/179902)) | -| 0002-preserve-device-debug-info | Keep debug info intact through the HIP SPIR-V device pipeline | Merged upstream ([llvm#210504](https://github.com/llvm/llvm-project/pull/210504)), ships in LLVM 24; matches the final merged form including SPV_INTEL_optnone | | 0003-unbundle-static-device-libraries | Enable RDC linking with static libraries containing device code | Upstream in LLVM 22+ ([llvm#136412](https://github.com/llvm/llvm-project/pull/136412), commit `ae0614de05ac`) | | 0004-fix-spirv-data-layout | Revert the `-n8:16:32:64` data layout change to avoid bitcode linking mismatches | chipStar-local revert of [llvm#110695](https://github.com/llvm/llvm-project/pull/110695), not upstreamable | | 0005-macos-hip-spirv | HIP SPIR-V compilation on macOS (Mach-O sections, Darwin toolchain guards, skip host stdlib for device) | Upstreamed via [llvm#183991](https://github.com/llvm/llvm-project/pull/183991) + [llvm#206902](https://github.com/llvm/llvm-project/pull/206902) | @@ -67,47 +66,26 @@ LLVM 17, 18, and 19 support was dropped. | 0003-fix-block-merge-innermost-loop | Fix block merging in innermost loops | Upstream in translator 220+ ([KhronosGroup#3280](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3280)) | | 0004-coalesce-duplicate-phi-predecessors | Coalesce duplicate phi predecessors during translation | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | -## llvm-21 - -Same patch set as llvm-20 (rebased onto `release/21.x`): - -### llvm/ - -| Patch | Purpose | Upstream status | -|---|---|---| -| 0001-spirv-version-and-extensions | As in llvm-20 | Upstreamed in LLVM 23+ behind `Triple::ChipStar` ([llvm#179902](https://github.com/llvm/llvm-project/pull/179902)) | -| 0003-unbundle-static-device-libraries | As in llvm-20 | Upstream in LLVM 22+ ([llvm#136412](https://github.com/llvm/llvm-project/pull/136412), `ae0614de05ac`) | -| 0004-fix-spirv-data-layout | As in llvm-20 | chipStar-local revert of [llvm#110695](https://github.com/llvm/llvm-project/pull/110695), not upstreamable | -| 0005-macos-hip-spirv | As in llvm-20 | Upstreamed via [llvm#183991](https://github.com/llvm/llvm-project/pull/183991) + [llvm#206902](https://github.com/llvm/llvm-project/pull/206902) | - -### spirv-translator/ - -| Patch | Purpose | Upstream status | -|---|---|---| -| 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-20 | Deliberate spec deviation, permanent | -| 0002-fix-loop-merge-placement | As in llvm-20 | Upstream in translator 220+ ([KhronosGroup#3277](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3277)) | -| 0003-fix-block-merge-innermost-loop | As in llvm-20 | Upstream in translator 220+ ([KhronosGroup#3280](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3280)) | -| 0004-coalesce-duplicate-phi-predecessors | As in llvm-20 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | - ## llvm-22 Smaller set: the unbundle-SDL fix is already upstream in LLVM 22, the data layout revert is no longer needed, and the loop/block merge fixes are already -upstream in translator 220+. +upstream in translator 220+. As in llvm-21, the numbering gap is +0002-preserve-device-debug-info, which was removed. ### llvm/ | Patch | Purpose | Upstream status | |---|---|---| -| 0001-spirv-version-and-extensions | As in llvm-20 | Upstreamed in LLVM 23+ behind `Triple::ChipStar` ([llvm#179902](https://github.com/llvm/llvm-project/pull/179902)) | -| 0003-macos-hip-spirv | As in llvm-20 | Upstreamed via [llvm#183991](https://github.com/llvm/llvm-project/pull/183991) + [llvm#206902](https://github.com/llvm/llvm-project/pull/206902) | +| 0001-spirv-version-and-extensions | As in llvm-21 | Upstreamed in LLVM 23+ behind `Triple::ChipStar` ([llvm#179902](https://github.com/llvm/llvm-project/pull/179902)) | +| 0003-macos-hip-spirv | As in llvm-21 | Upstreamed via [llvm#183991](https://github.com/llvm/llvm-project/pull/183991) + [llvm#206902](https://github.com/llvm/llvm-project/pull/206902) | ### spirv-translator/ | Patch | Purpose | Upstream status | |---|---|---| -| 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-20 | Deliberate spec deviation, permanent | -| 0002-coalesce-duplicate-phi-predecessors | As in llvm-20 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | +| 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-21 | Deliberate spec deviation, permanent | +| 0002-coalesce-duplicate-phi-predecessors | As in llvm-21 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | ## llvm-23 @@ -136,13 +114,13 @@ a `DICompileUnit` on that path. | Patch | Purpose | Upstream status | |---|---|---| -| 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-20 | Deliberate spec deviation, permanent | -| 0002-coalesce-duplicate-phi-predecessors | As in llvm-20 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | +| 0001-pretend-subgroup-caps-are-spirv-1.2 | As in llvm-21 | Deliberate spec deviation, permanent | +| 0002-coalesce-duplicate-phi-predecessors | As in llvm-21 | Pending upstream ([KhronosGroup#3866](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/3866)) | ## Removed in the layout change - **archive-data-layout patch** (`llvm-link` empty "ArchiveModule" data layout fix): deleted; a no-op versus the upstream IRMover behavior. - **fp_fast_mode test patch** (translator): deleted; a no-op. -- **LLVM 17/18/19 support** and their version-specific patch variants were - dropped. +- **LLVM 17 through 20 support** and their version-specific patch variants + were dropped. diff --git a/llvm-patches/llvm-20/llvm/0001-spirv-version-and-extensions.patch b/llvm-patches/llvm-20/llvm/0001-spirv-version-and-extensions.patch deleted file mode 100644 index 73bbc1656..000000000 --- a/llvm-patches/llvm-20/llvm/0001-spirv-version-and-extensions.patch +++ /dev/null @@ -1,51 +0,0 @@ -From d3e5d75098f16e05d660fe736223f4b97dbf2371 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pekka=20J=C3=A4=C3=A4skel=C3=A4inen?= - -Date: Thu, 15 Dec 2022 19:23:56 +0200 -Subject: [PATCH 1/5] Allow SPIR-V 1.2 and restrict extensions to the necessary - set - -Raise the HIPSPV translator invocation's --spirv-max-version from 1.1 to -1.2 to support warp-level primitives (shuffles, ballots) via the -subgroup extensions. Strictly the non-extension shuffle operations would -require v1.3, but it's not supported by any target yet. - -At the same time, replace --spirv-ext=+all with an explicit allowlist of -only the extensions chipStar needs: SPV_INTEL_function_pointers, -SPV_INTEL_subgroups and SPV_EXT_shader_atomic_float_add. "+all" lets -the translator emit extensions that consuming drivers reject. - -This squashes the two historical chipStar patches -(0001-Allow-up-to-v1.2-SPIR-V-features and 0004-only-necessary-exts) -into a single hunk. - -Applies-to: LLVM release/20.x -Upstream-status: upstreamed in LLVM 23+ behind the chipStar toolchain -detection (Triple::ChipStar), llvm/llvm-project#179902, commit -0c8b435c57f6. Still needed as a patch on release/20.x. ---- - clang/lib/Driver/ToolChains/HIPSPV.cpp | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp -index bdbcf91..9e1a4b1 100644 ---- a/clang/lib/Driver/ToolChains/HIPSPV.cpp -+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp -@@ -96,9 +96,11 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( - } - - // Emit SPIR-V binary. -- -- llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.1", -- "--spirv-ext=+all"}; -+ // We need 1.2 when using 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 target yet. -+ llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2", -+ "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_shader_atomic_float_add"}; - InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, ""); - SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs); - } --- -2.43.0 - diff --git a/llvm-patches/llvm-20/llvm/0002-preserve-device-debug-info.patch b/llvm-patches/llvm-20/llvm/0002-preserve-device-debug-info.patch deleted file mode 100644 index b8074ed0b..000000000 --- a/llvm-patches/llvm-20/llvm/0002-preserve-device-debug-info.patch +++ /dev/null @@ -1,89 +0,0 @@ -From fcd464ddd71c33203aa31e382715adc965338f91 Mon Sep 17 00:00:00 2001 -From: chipStar -Date: Sat, 18 Jul 2026 14:18:22 +0300 -Subject: [PATCH 2/5] Preserve device debug info for gdb-oneapi - -HIPSPVToolChain::adjustDebugInfoKind() unconditionally forced NoDebugInfo, -so -g/-O0 produced device SPIR-V with no debug metadata at all. The stated -reason (SPIRV-LLVM-Translator aborting on DW_OP_LLVM_convert) no longer -applies: the translator now lowers it to SPIRVDebug::Convert. - -Stop clobbering the requested debug level, and when -g is given emit the -NonSemantic.Shader.DebugInfo form (--spirv-debug-info-version= -nonsemantic-shader-200 + SPV_KHR_non_semantic_info) that Intel's IGC and -gdb-oneapi consume to resolve source lines and locals in device code. - -Also enable SPV_INTEL_optnone when -g is given: clang emits the optnone -function attribute at -O0, and without the extension the translator drops -it, the device compiler optimizes the kernel anyway, and gdb-oneapi -reports every local as - the exact symptom of #1004. - -Refs: CHIP-SPV/chipStar#1004 -Applies-to: LLVM release/20.x -Upstream-status: upstreamed in llvm/llvm-project#210504 (3093d8c577d7), -first ships in LLVM 24. This patch matches the final merged form, -including the SPV_INTEL_optnone enablement from its second commit -(f44bf2b4ce5c). - ---- - clang/lib/Driver/ToolChains/HIPSPV.cpp | 39 ++++++++++++++++++++++---- - 1 file changed, 33 insertions(+), 6 deletions(-) - -diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp -index 9e1a4b1..e8a0ccb 100644 ---- a/clang/lib/Driver/ToolChains/HIPSPV.cpp -+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp -@@ -99,8 +99,28 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( - // We need 1.2 when using 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 target yet. -- llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2", -- "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups,+SPV_EXT_shader_atomic_float_add"}; -+ std::string SpirvExts = -+ "--spirv-ext=-all,+SPV_INTEL_function_pointers,+SPV_INTEL_subgroups," -+ "+SPV_EXT_shader_atomic_float_add"; -+ llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.2"}; -+ // When the user requests debug info (-g, but not -g0), preserve it into the -+ // SPIR-V in the NonSemantic.Shader.DebugInfo form. Intel's IGC and gdb-oneapi -+ // consume this to map device code back to source lines and local variables; -+ // the translator's default OpenCL.DebugInfo.100 form is not sufficient for -+ // that. Emitting the NonSemantic debug instructions requires the -+ // SPV_KHR_non_semantic_info extension, so it is only enabled here on demand -+ // to keep the default (non-debug) SPIR-V output unchanged. -+ // SPV_INTEL_optnone carries the optnone function attribute, which Clang -+ // emits at -O0. Without the extension the translator drops the attribute, -+ // the device compiler optimizes the kernel anyway, and debuggers report -+ // locals as even though line info is present. At -O1 and -+ // above no optnone attribute exists, so the extension has no effect there. -+ if (const Arg *A = Args.getLastArg(options::OPT_g_Group); -+ A && !A->getOption().matches(options::OPT_g0)) { -+ SpirvExts += ",+SPV_KHR_non_semantic_info,+SPV_INTEL_optnone"; -+ TrArgs.push_back("--spirv-debug-info-version=nonsemantic-shader-200"); -+ } -+ TrArgs.push_back(Args.MakeArgString(SpirvExts)); - InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, ""); - SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs); - } -@@ -283,8 +303,15 @@ VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D, - void HIPSPVToolChain::adjustDebugInfoKind( - llvm::codegenoptions::DebugInfoKind &DebugInfoKind, - const llvm::opt::ArgList &Args) const { -- // Debug info generation is disabled for SPIRV-LLVM-Translator -- // which currently aborts on the presence of DW_OP_LLVM_convert. -- // TODO: Enable debug info when the SPIR-V backend arrives. -- DebugInfoKind = llvm::codegenoptions::NoDebugInfo; -+ // Historically device debug info was force-disabled here because the -+ // SPIRV-LLVM-Translator aborted on DW_OP_LLVM_convert debug expressions. -+ // The translator now lowers that operation (SPIRVDebug::Convert), so honor -+ // the debug level the user requested (e.g. via -g) and let it flow into the -+ // emitted SPIR-V. constructLinkAndEmitSpirvCommand() additionally enables the -+ // NonSemantic.Shader.DebugInfo form at translation time so that Intel's IGC -+ // and gdb-oneapi can consume it. Leaving DebugInfoKind untouched keeps the -+ // default (no -g) behavior unchanged, since the driver defaults it to -+ // NoDebugInfo. -+ (void)DebugInfoKind; -+ (void)Args; - } --- -2.43.0 - diff --git a/llvm-patches/llvm-20/llvm/0003-unbundle-static-device-libraries.patch b/llvm-patches/llvm-20/llvm/0003-unbundle-static-device-libraries.patch deleted file mode 100644 index 4b4c06032..000000000 --- a/llvm-patches/llvm-20/llvm/0003-unbundle-static-device-libraries.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 32e60e3ac258e3b4da0e1cc849533a8a62b3eb9f Mon Sep 17 00:00:00 2001 -From: Paulius Velesko -Date: Mon, 28 Jul 2025 21:22:23 +0300 -Subject: [PATCH 3/5] HIPSPV: Unbundle SDL (#136412) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This fixes the issue of rdc linking static libraries with device code - -https://github.com/CHIP-SPV/chipStar/issues/984 - -Applies-to: LLVM release/20.x -Upstream-status: merged upstream in LLVM 22+ as commit ae0614de05ac -(llvm/llvm-project#136412); backports to release branches were declined. - -Co-authored-by: Henry Linjamäki ---- - clang/lib/Driver/ToolChains/HIPSPV.cpp | 9 ++++++ - .../Driver/hipspv-link-static-library.hip | 28 +++++++++++++++++++ - 2 files changed, 37 insertions(+) - create mode 100644 clang/test/Driver/hipspv-link-static-library.hip - -diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp -index 2c46d12..e7aad1b 100644 ---- a/clang/lib/Driver/ToolChains/HIPSPV.cpp -+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp -@@ -70,8 +70,17 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( - - // Link LLVM bitcode. - ArgStringList LinkArgs{}; -+ - for (auto Input : Inputs) - LinkArgs.push_back(Input.getFilename()); -+ -+ // Add static device libraries using the common helper function. -+ // This handles unbundling archives (.a) containing bitcode bundles. -+ StringRef Arch = getToolChain().getTriple().getArchName(); -+ StringRef Target = -+ "generic"; // SPIR-V is generic, no specific target ID like -mcpu -+ tools::AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LinkArgs, Arch, -+ Target, /*IsBitCodeSDL=*/true); - LinkArgs.append({"-o", TempFile}); - const char *LlvmLink = - Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); -diff --git a/clang/test/Driver/hipspv-link-static-library.hip b/clang/test/Driver/hipspv-link-static-library.hip -new file mode 100644 -index 0000000..03126ae ---- /dev/null -+++ b/clang/test/Driver/hipspv-link-static-library.hip -@@ -0,0 +1,28 @@ -+// Test HIPSPV static device library linking -+// REQUIRES: system-linux -+// UNSUPPORTED: system-windows -+ -+// Create a dummy archive to test SDL linking -+// RUN: rm -rf %t && mkdir %t -+// RUN: touch %t/dummy.bc -+// RUN: llvm-ar cr %t/libSDL.a %t/dummy.bc -+ -+// Test that -l options are passed to llvm-link for --offload=spirv64 -+// RUN: %clang -### --target=x86_64-linux-gnu --offload=spirv64 \ -+// RUN: --hip-path=%S/Inputs/hipspv -nohipwrapperinc %s \ -+// RUN: -L%t -lSDL \ -+// RUN: 2>&1 | FileCheck -check-prefix=SDL-LINK %s -+ -+// Test that .a files are properly unbundled and passed to llvm-link -+// RUN: %clang -### --target=x86_64-linux-gnu --offload=spirv64 \ -+// RUN: --hip-path=%S/Inputs/hipspv -nohipwrapperinc %s \ -+// RUN: %t/libSDL.a \ -+// RUN: 2>&1 | FileCheck -check-prefix=SDL-ARCHIVE %s -+ -+// Verify that the input files are added before the SDL files in llvm-link command -+// This tests the ordering fix to match HIPAMD behavior -+// SDL-LINK: "{{.*}}clang-offload-bundler" "-unbundle" "-type=a" "-input={{.*}}libSDL.a" "-targets=hip-spirv64-unknown-unknown-unknown-generic" "-output=[[SDL_A:.*\.a]]" "-allow-missing-bundles" -+// SDL-LINK: "{{.*}}llvm-link" "{{.*}}.bc" "[[SDL_A]]" "-o" -+ -+// SDL-ARCHIVE: "{{.*}}clang-offload-bundler" "-unbundle" "-type=a" "-input={{.*}}libSDL.a" "-targets=hip-spirv64-unknown-unknown-unknown-generic" "-output=[[SDL_A:.*\.a]]" "-allow-missing-bundles" -+// SDL-ARCHIVE: "{{.*}}llvm-link" "{{.*}}.bc" "[[SDL_A]]" "-o" --- -2.43.0 - diff --git a/llvm-patches/llvm-20/llvm/0004-fix-spirv-data-layout.patch b/llvm-patches/llvm-20/llvm/0004-fix-spirv-data-layout.patch deleted file mode 100644 index 350a4a714..000000000 --- a/llvm-patches/llvm-20/llvm/0004-fix-spirv-data-layout.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 2024372ae80dad7011beb2835982a7ef305b34f8 Mon Sep 17 00:00:00 2001 -From: Paulius Velesko -Date: Tue, 6 May 2025 19:36:56 +0300 -Subject: [PATCH 4/5] fix SPIR-V data layout - -Drop the "n8:16:32:64" native integer widths from the SPIR-V data -layout strings so optimizations do not create integer types that SPIR-V -consumers cannot handle. - -Applies-to: LLVM release/20.x -Upstream-status: chipStar-local revert of llvm/llvm-project#110695; -not upstreamable. ---- - clang/lib/Basic/Targets/SPIR.h | 6 +++--- - llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 4 ++-- - 2 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h -index c0849b6..33ed81a 100644 ---- a/clang/lib/Basic/Targets/SPIR.h -+++ b/clang/lib/Basic/Targets/SPIR.h -@@ -313,7 +313,7 @@ public: - // SPIR-V IDs are represented with a single 32-bit word. - SizeType = TargetInfo::UnsignedInt; - resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" -- "v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); -+ "v256:256-v512:512-v1024:1024-G1"); - } - ArrayRef getTargetBuiltins() const override; - void getTargetDefines(const LangOptions &Opts, -@@ -337,7 +337,7 @@ public: - // we take the maximum because it's possible the Host supports wider types. - MaxAtomicInlineWidth = std::max(MaxAtomicInlineWidth, 32); - resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-" -- "v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); -+ "v192:256-v256:256-v512:512-v1024:1024-G1"); - } - - void getTargetDefines(const LangOptions &Opts, -@@ -361,7 +361,7 @@ public: - // we take the maximum because it's possible the Host supports wider types. - MaxAtomicInlineWidth = std::max(MaxAtomicInlineWidth, 64); - resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" -- "v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); -+ "v256:256-v512:512-v1024:1024-G1"); - } - - void getTargetDefines(const LangOptions &Opts, -diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp -index 098c7a6..eba2003 100644 ---- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp -+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp -@@ -60,13 +60,13 @@ static std::string computeDataLayout(const Triple &TT) { - // mean anything. - if (Arch == Triple::spirv32) - return "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" -- "v256:256-v512:512-v1024:1024-n8:16:32:64-G1"; -+ "v256:256-v512:512-v1024:1024-G1"; - if (TT.getVendor() == Triple::VendorType::AMD && - TT.getOS() == Triple::OSType::AMDHSA) - return "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-" - "v512:512-v1024:1024-n32:64-S32-G1-P4-A0"; - return "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-" -- "v512:512-v1024:1024-n8:16:32:64-G1"; -+ "v512:512-v1024:1024-G1"; - } - - static Reloc::Model getEffectiveRelocModel(std::optional RM) { --- -2.43.0 - diff --git a/llvm-patches/llvm-20/llvm/0005-macos-hip-spirv.patch b/llvm-patches/llvm-20/llvm/0005-macos-hip-spirv.patch deleted file mode 100644 index 4ea7816ee..000000000 --- a/llvm-patches/llvm-20/llvm/0005-macos-hip-spirv.patch +++ /dev/null @@ -1,155 +0,0 @@ -From fd93b63ac292e9f4a068c863b9d0eabf7df40b29 Mon Sep 17 00:00:00 2001 -From: Paulius Velesko -Date: Fri, 1 Aug 2025 12:00:00 +0300 -Subject: [PATCH 5/5] Fix HIP SPIR-V compilation on macOS hosts - -Make HIP offloading to SPIR-V work when the host toolchain is Darwin: - -- AlignedAllocation.h: return an empty version tuple for unknown OS - types (e.g. SPIRV device targets) instead of hitting llvm_unreachable. -- CGCUDANV: use Mach-O "segment,section" names for the HIP fatbin - sections on macOS. -- Darwin toolchain: guard addClangWarningOptions, CheckObjCARC and - getSupportedSanitizers against an uninitialized target, which happens - when Darwin serves as the host toolchain for HIP offloading. -- HIPSPV: do not delegate addClangTargetOptions to the host toolchain; - on Darwin it injects macOS libc++-specific flags such as - -faligned-alloc-unavailable that break SPIR-V device compilation. -- HIPUtility: emit the Mach-O section directive for the fatbin symbol. - -Applies-to: LLVM release/20.x -Upstream-status: upstreamed via llvm/llvm-project#183991 and -llvm/llvm-project#206902; still needed on 20.x. ---- - clang/include/clang/Basic/AlignedAllocation.h | 6 +++--- - clang/lib/CodeGen/CGCUDANV.cpp | 10 +++++++--- - clang/lib/Driver/ToolChains/Darwin.cpp | 15 +++++++++++++++ - clang/lib/Driver/ToolChains/HIPSPV.cpp | 6 +++++- - clang/lib/Driver/ToolChains/HIPUtility.cpp | 7 +++++-- - 5 files changed, 35 insertions(+), 9 deletions(-) - -diff --git a/clang/include/clang/Basic/AlignedAllocation.h b/clang/include/clang/Basic/AlignedAllocation.h -index ac26eb4..21bb7e2 100644 ---- a/clang/include/clang/Basic/AlignedAllocation.h -+++ b/clang/include/clang/Basic/AlignedAllocation.h -@@ -24,7 +24,9 @@ namespace clang { - inline llvm::VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) { - switch (OS) { - default: -- break; -+ // For unknown/unsupported OS types (e.g. SPIRV, CUDA device targets), -+ // return empty version tuple indicating aligned alloc is always available. -+ return llvm::VersionTuple(); - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: // Earliest supporting version is 10.13. - return llvm::VersionTuple(10U, 13U); -@@ -36,8 +38,6 @@ inline llvm::VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) { - case llvm::Triple::ZOS: - return llvm::VersionTuple(); // All z/OS versions have no support. - } -- -- llvm_unreachable("Unexpected OS"); - } - - } // end namespace clang -diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp -index e8d2dca..4333cd0 100644 ---- a/clang/lib/CodeGen/CGCUDANV.cpp -+++ b/clang/lib/CodeGen/CGCUDANV.cpp -@@ -820,10 +820,14 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { - llvm::Constant *FatBinStr; - unsigned FatMagic; - if (IsHIP) { -- FatbinConstantName = ".hip_fatbin"; -- FatbinSectionName = ".hipFatBinSegment"; -+ // On macOS (Mach-O), section names must be in "segment,section" format. -+ FatbinConstantName = -+ CGM.getTriple().isMacOSX() ? "__HIP,__hip_fatbin" : ".hip_fatbin"; -+ FatbinSectionName = -+ CGM.getTriple().isMacOSX() ? "__HIP,__fatbin" : ".hipFatBinSegment"; - -- ModuleIDSectionName = "__hip_module_id"; -+ ModuleIDSectionName = -+ CGM.getTriple().isMacOSX() ? "__HIP,__module_id" : "__hip_module_id"; - ModuleIDPrefix = "__hip_"; - - if (CudaGpuBinary) { -diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp -index 55c55ba..856b023 100644 ---- a/clang/lib/Driver/ToolChains/Darwin.cpp -+++ b/clang/lib/Driver/ToolChains/Darwin.cpp -@@ -1201,6 +1201,12 @@ void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { - CC1Args.push_back("-Werror=undef-prefix"); - - // For modern targets, promote certain warnings to errors. -+ // Guard against uninitialized target (e.g. when Darwin is used as host -+ // toolchain for HIP/CUDA offloading where the target platform may not -+ // have been fully set up). -+ if (!isTargetInitialized()) -+ return; -+ - if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { - // Always enable -Wdeprecated-objc-isa-usage and promote it - // to an error. -@@ -3593,6 +3599,10 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, - } - - void Darwin::CheckObjCARC() const { -+ // Guard against uninitialized target (e.g. when Darwin is used as host -+ // toolchain for HIP/CUDA offloading). -+ if (!isTargetInitialized()) -+ return; - if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetXROS() || - (isTargetMacOSBased() && !isMacosxVersionLT(10, 6))) - return; -@@ -3612,6 +3622,11 @@ SanitizerMask Darwin::getSupportedSanitizers() const { - Res |= SanitizerKind::FuzzerNoLink; - Res |= SanitizerKind::ObjCCast; - -+ // Guard against uninitialized target (e.g. when Darwin is used as host -+ // toolchain for HIP/CUDA offloading). Return base sanitizers only. -+ if (!isTargetInitialized()) -+ return Res; -+ - // Prior to 10.9, macOS shipped a version of the C++ standard library without - // C++11 support. The same is true of iOS prior to version 5. These OS'es are - // incompatible with -fsanitize=vptr. -diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp -index e7aad1b..362a49b 100644 ---- a/clang/lib/Driver/ToolChains/HIPSPV.cpp -+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp -@@ -157,7 +157,11 @@ 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 { -- 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/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp -index dfe9acc..49d5f59 100644 ---- a/clang/lib/Driver/ToolChains/HIPUtility.cpp -+++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp -@@ -426,9 +426,12 @@ void HIP::constructGenerateObjFileFromHIPFatBinary( - } - if (FoundPrimaryHipFatbinSymbol) { - // Define the first fatbin symbol -- if (HostTriple.isWindowsMSVCEnvironment()) -+ if (HostTriple.isWindowsMSVCEnvironment()) { - ObjStream << " .section .hip_fatbin,\"dw\"\n"; -- else { -+ } else if (HostTriple.isMacOSX()) { -+ // Mach-O requires "segment,section" format -+ ObjStream << " .section __HIP,__hip_fatbin\n"; -+ } else { - ObjStream << " .protected " << PrimaryHipFatbinSymbol << "\n"; - ObjStream << " .type " << PrimaryHipFatbinSymbol << ",@object\n"; - ObjStream << " .section .hip_fatbin,\"a\",@progbits\n"; --- -2.43.0 - diff --git a/llvm-patches/llvm-20/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch b/llvm-patches/llvm-20/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch deleted file mode 100644 index 0c667c897..000000000 --- a/llvm-patches/llvm-20/spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 64c91bf3410bba6a06472ae0f79b398200cbf6a5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pekka=20J=C3=A4=C3=A4skel=C3=A4inen?= - -Date: Thu, 15 Dec 2022 19:31:18 +0200 -Subject: [PATCH 1/4] Pretend the SPIR ver needed by shuffles is 1.2 - -In reality the SPIR-V shuffles and ballot operations -require v1.3, but they seem to work with Intel's v1.2 -implementation (likely due to the extensions). - -Until v1.3 support is added to the driver, let's just pretend -these are v1.2 features to allow CHIPSPV warp-level functions -to compile. - -Applies-to: SPIRV-LLVM-Translator llvm_release_200 -Upstream-status: deliberate deviation from the SPIR-V specification; -permanently downstream. ---- - lib/SPIRV/libSPIRV/SPIRVEntry.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h -index 409990e..1d44ef9 100644 ---- a/lib/SPIRV/libSPIRV/SPIRVEntry.h -+++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h -@@ -889,7 +889,7 @@ public: - case CapabilityGroupNonUniformShuffle: - case CapabilityGroupNonUniformShuffleRelative: - case CapabilityGroupNonUniformClustered: -- return VersionNumber::SPIRV_1_3; -+ return VersionNumber::SPIRV_1_2; - - case CapabilityNamedBarrier: - case CapabilitySubgroupDispatch: --- -2.43.0 - diff --git a/llvm-patches/llvm-20/spirv-translator/0002-fix-loop-merge-placement.patch b/llvm-patches/llvm-20/spirv-translator/0002-fix-loop-merge-placement.patch deleted file mode 100644 index 131aa36bf..000000000 --- a/llvm-patches/llvm-20/spirv-translator/0002-fix-loop-merge-placement.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 81472dfb51524335f829fe941b508b098709941f Mon Sep 17 00:00:00 2001 -From: Paulius Velesko -Date: Wed, 23 Jul 2025 13:33:02 +0300 -Subject: [PATCH 2/4] Fix LoopMerge error - -Insert OpLoopMerge and OpLoopControlINTEL immediately before the block's -branch terminator only when that terminator actually is OpBranch or -OpBranchConditional; otherwise append them at the end of the block. -This fixes "OpLoopMerge must appear immediately before the branch" -validation errors. - -Applies-to: SPIRV-LLVM-Translator llvm_release_200 -Upstream-status: merged upstream in llvm_release_220+ as commit 691d303a -(KhronosGroup/SPIRV-LLVM-Translator#3277, Paulius Velesko). ---- - lib/SPIRV/libSPIRV/SPIRVModule.cpp | 36 ++++++++++++++++++++++++------ - 1 file changed, 29 insertions(+), 7 deletions(-) - -diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/lib/SPIRV/libSPIRV/SPIRVModule.cpp -index 5fa2b29..81899a5 100644 ---- a/lib/SPIRV/libSPIRV/SPIRVModule.cpp -+++ b/lib/SPIRV/libSPIRV/SPIRVModule.cpp -@@ -1869,10 +1869,22 @@ SPIRVInstruction *SPIRVModuleImpl::addSelectionMergeInst( - SPIRVInstruction *SPIRVModuleImpl::addLoopMergeInst( - SPIRVId MergeBlock, SPIRVId ContinueTarget, SPIRVWord LoopControl, - std::vector LoopControlParameters, SPIRVBasicBlock *BB) { -- return addInstruction( -- new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, -- LoopControlParameters, BB), -- BB, const_cast(BB->getTerminateInstr())); -+ SPIRVInstruction *TermInst = const_cast(BB->getTerminateInstr()); -+ // OpLoopMerge must be the second-to-last instruction in the block, -+ // immediately preceding the branch instruction (OpBranch or OpBranchConditional) -+ if (TermInst && (TermInst->getOpCode() == OpBranch || -+ TermInst->getOpCode() == OpBranchConditional)) { -+ return addInstruction( -+ new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, -+ LoopControlParameters, BB), -+ BB, TermInst); -+ } else { -+ // If there's no proper terminator, add at the end -+ return addInstruction( -+ new SPIRVLoopMerge(MergeBlock, ContinueTarget, LoopControl, -+ LoopControlParameters, BB), -+ BB); -+ } - } - - SPIRVInstruction *SPIRVModuleImpl::addLoopControlINTELInst( -@@ -1880,9 +1892,19 @@ SPIRVInstruction *SPIRVModuleImpl::addLoopControlINTELInst( - SPIRVBasicBlock *BB) { - addCapability(CapabilityUnstructuredLoopControlsINTEL); - addExtension(ExtensionID::SPV_INTEL_unstructured_loop_controls); -- return addInstruction( -- new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB, -- const_cast(BB->getTerminateInstr())); -+ SPIRVInstruction *TermInst = const_cast(BB->getTerminateInstr()); -+ // OpLoopControlINTEL must be the second-to-last instruction in the block, -+ // immediately preceding the branch instruction (OpBranch or OpBranchConditional) -+ if (TermInst && (TermInst->getOpCode() == OpBranch || -+ TermInst->getOpCode() == OpBranchConditional)) { -+ return addInstruction( -+ new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB, -+ TermInst); -+ } else { -+ // If there's no proper terminator, add at the end -+ return addInstruction( -+ new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB); -+ } - } - - SPIRVInstruction *SPIRVModuleImpl::addFixedPointIntelInst( --- -2.43.0 - diff --git a/llvm-patches/llvm-20/spirv-translator/0003-fix-block-merge-innermost-loop.patch b/llvm-patches/llvm-20/spirv-translator/0003-fix-block-merge-innermost-loop.patch deleted file mode 100644 index 4287f31d0..000000000 --- a/llvm-patches/llvm-20/spirv-translator/0003-fix-block-merge-innermost-loop.patch +++ /dev/null @@ -1,53 +0,0 @@ -From f30637700557e86fbfece6795ded2b20018c8769 Mon Sep 17 00:00:00 2001 -From: Paulius Velesko -Date: Wed, 23 Jul 2025 17:10:08 +0300 -Subject: [PATCH 3/4] fix blockMerge - -When deciding where to place OpLoopMerge for a conditional branch, use -the innermost loop containing the branch's basic block -(LoopInfo::getLoopFor) instead of iterating over all loops in preorder, -and only emit a merge when one of the branch successors is that loop's -header. - -Applies-to: SPIRV-LLVM-Translator llvm_release_200 -Upstream-status: merged upstream in llvm_release_220+ as commit 9e823ad4 -(KhronosGroup/SPIRV-LLVM-Translator#3280, Paulius Velesko). ---- - lib/SPIRV/SPIRVWriter.cpp | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp -index 9d056b2..b930794 100644 ---- a/lib/SPIRV/SPIRVWriter.cpp -+++ b/lib/SPIRV/SPIRVWriter.cpp -@@ -2492,7 +2492,11 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, - Function *Fun = Branch->getFunction(); - DominatorTree DomTree(*Fun); - LoopInfo LI(DomTree); -- for (const auto *LoopObj : LI.getLoopsInPreorder()) { -+ // Find the innermost loop that contains the current basic block -+ BasicBlock *CurrentBB = Branch->getParent(); -+ const Loop *ContainingLoop = LI.getLoopFor(CurrentBB); -+ -+ if (ContainingLoop) { - // Check whether SuccessorFalse or SuccessorTrue is the loop header BB. - // For example consider following LLVM IR: - // br i1 %compare, label %for.body, label %for.end -@@ -2501,12 +2505,12 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, - // <- SuccessorTrue is 'for.end' aka successor(1) - // meanwhile the true successor (by definition) should be a loop header - // aka 'for.body' -- if (LoopObj->getHeader() == Branch->getSuccessor(1)) -+ if (ContainingLoop->getHeader() == Branch->getSuccessor(1)) - // SuccessorFalse is the loop header BB. - BM->addLoopMergeInst(SuccessorTrue->getId(), // Merge Block - BB->getId(), // Continue Target - LoopControl, Parameters, SuccessorFalse); -- else -+ else if (ContainingLoop->getHeader() == Branch->getSuccessor(0)) - // SuccessorTrue is the loop header BB. - BM->addLoopMergeInst(SuccessorFalse->getId(), // Merge Block - BB->getId(), // Continue Target --- -2.43.0 - diff --git a/llvm-patches/llvm-20/spirv-translator/0004-coalesce-duplicate-phi-predecessors.patch b/llvm-patches/llvm-20/spirv-translator/0004-coalesce-duplicate-phi-predecessors.patch deleted file mode 100644 index f8317e7ea..000000000 --- a/llvm-patches/llvm-20/spirv-translator/0004-coalesce-duplicate-phi-predecessors.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 97622ab4a4cfc1714f21d13591e60eb8f6f0f7ad Mon Sep 17 00:00:00 2001 -From: chipStar -Date: Thu, 18 Jun 2026 00:00:00 +0000 -Subject: [PATCH 4/4] Coalesce duplicate predecessors when emitting OpPhi - -LLVM IR allows a PHI to list the same predecessor block more than once -(e.g. a switch with several cases branching to the same block); the LLVM -verifier guarantees the duplicate entries carry identical incoming values. -SPIR-V's OpPhi requires exactly one (value, parent block) pair per -predecessor, so emitting the duplicates verbatim yields invalid SPIR-V -("OpPhi's number of incoming blocks does not match block's predecessor -count"), which IGC then mis-handles (nondeterministic crash / miscompile). - -Skip duplicate predecessor entries when building the OpPhi operand list. - -Applies-to: SPIRV-LLVM-Translator llvm_release_200 -Upstream-status: pending upstream via -KhronosGroup/SPIRV-LLVM-Translator#3866. ---- - lib/SPIRV/SPIRVWriter.cpp | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp -index b930794..8dd064e 100644 ---- a/lib/SPIRV/SPIRVWriter.cpp -+++ b/lib/SPIRV/SPIRVWriter.cpp -@@ -2526,7 +2526,18 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, - std::vector IncomingPairs; - SPIRVType *Ty = transScavengedType(Phi); - -+ // SPIR-V requires OpPhi to have exactly one (value, parent block) pair per -+ // predecessor block. LLVM IR, however, permits a PHI to list the same -+ // predecessor multiple times (e.g. a switch with several cases branching -+ // to this block); the LLVM verifier guarantees those duplicate entries -+ // carry identical incoming values. Emitting them verbatim produces an -+ // invalid OpPhi (more parent blocks than the block has predecessors), so -+ // coalesce duplicate predecessors to a single entry. -+ SmallPtrSet SeenPreds; - for (size_t I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) { -+ const BasicBlock *IncomingBB = Phi->getIncomingBlock(I); -+ if (!SeenPreds.insert(IncomingBB).second) -+ continue; // duplicate predecessor; value is identical, skip it - SPIRVValue *Val = transValue(Phi->getIncomingValue(I), BB, true, - FuncTransMode::Pointer); - if (Val->getType() != Ty) --- -2.43.0 - diff --git a/scripts/configure_llvm.sh b/scripts/configure_llvm.sh index 8d91ff77c..81df2f677 100755 --- a/scripts/configure_llvm.sh +++ b/scripts/configure_llvm.sh @@ -78,8 +78,8 @@ done # check mandatory argument version if [ -z "$VERSION" ]; then echo "Usage: $0 --version --install-dir --link-type static/dynamic(default) [--variant translator|native] [--with-binutils [path]] [--configure-only] [-N]" - echo "--version: LLVM version 20, 21, 22, 23, or latest" - echo " 20/21/22: upstream release branch plus patches from llvm-patches/llvm-/" + echo "--version: LLVM version 21, 22, 23, or latest" + echo " 21/22: upstream release branch plus patches from llvm-patches/llvm-/" echo " 23: upstream tag llvmorg-23.1.0-rc2 plus patches from llvm-patches/llvm-23/" echo " latest (experimental): CHIP-SPV/llvm-project branch chipStar-llvm-23, maintained" echo " directly with no patches (patches exist only for the release-pinned versions)" @@ -99,10 +99,10 @@ if [ -z "$INSTALL_DIR" ]; then fi # validate version argument -if [ "$VERSION" != "20" ] && [ "$VERSION" != "21" ] && [ "$VERSION" != "22" ] \ - && [ "$VERSION" != "23" ] && [ "$VERSION" != "latest" ]; then - echo "Invalid version '$VERSION'. Must be 20, 21, 22, 23, or latest." - echo "(Support for LLVM 17, 18, and 19 has been dropped.)" +if [ "$VERSION" != "21" ] && [ "$VERSION" != "22" ] && [ "$VERSION" != "23" ] \ + && [ "$VERSION" != "latest" ]; then + echo "Invalid version '$VERSION'. Must be 21, 22, 23, or latest." + echo "(Support for LLVM 17 through 20 has been dropped.)" exit 1 fi From 34ff7f4e1c135b0af81000c722c8711ca6ca35be Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:23:34 +0300 Subject: [PATCH 05/22] docs: state where device debug info actually works Profiling.md claimed the preserve-device-debug-info patch is applied for every supported LLVM. It is now applied only on 23, and there only when the in-tree SPIR-V backend is the effective emitter. --- docs/Profiling.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/Profiling.md b/docs/Profiling.md index efa456651..3b0a1a249 100644 --- a/docs/Profiling.md +++ b/docs/Profiling.md @@ -12,10 +12,15 @@ vary by installation. | In-kernel debugging, line info + breakpoints | `-g -O0` | — | | In-kernel debugging, readable locals | `-g -O0` | `CHIP_JIT_FLAGS="-cl-opt-disable"` | -Device debug info requires LLVM built with chipStar's +Device debug info requires LLVM 23 built by +`scripts/configure_llvm.sh --version 23`, which applies chipStar's `preserve-device-debug-info` patch (upstream from LLVM 24, -[llvm#210504](https://github.com/llvm/llvm-project/pull/210504)); -`scripts/configure_llvm.sh` applies it for LLVM 20-22. +[llvm#210504](https://github.com/llvm/llvm-project/pull/210504)) on top of +the in-tree SPIR-V backend backport. On LLVM 21 and 22, and on 23 when +`-fno-integrated-objemitter` selects the SPIRV-LLVM-Translator, device +debug info is stripped: the translator emits a cyclic +`DebugTypeComposite` `Parent` reference that `spirv-val` rejects and IGC +mis-handles. ## Compile time vs JIT time From eb05c96f90f5b16b2866f7134e330d410e8f2e91 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:48:45 +0300 Subject: [PATCH 06/22] unit_tests.sh: select the LLVM 23 SPIR-V producer with a flag, not a module LLVM 22 has no in-tree HIPSPV backend support, so its two producers need two separate toolchains and --variant picks between the llvm/22.0-translator and llvm/22.0-native modules. From LLVM 23 on chipStar patches in llvm#213052, so one toolchain built with the SPIRV target serves both: the translator is built either way and the producer is chosen per compilation. There is a single llvm/23.0 module and --variant becomes -DCHIP_LLVM_USE_INTERGRATED_SPIRV instead of a different module name. Also drop llvm-20 from the version error message. --- scripts/unit_tests.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/scripts/unit_tests.sh b/scripts/unit_tests.sh index c01fc73fa..d841dbc41 100755 --- a/scripts/unit_tests.sh +++ b/scripts/unit_tests.sh @@ -44,7 +44,7 @@ build_type=$(echo "$1" | tr '[:lower:]' '[:upper:]') # Check if the second argument starts with "llvm-" and is followed by a valid version number if [[ ! "$2" =~ ^llvm-(1[6-9]|[2-9][0-9])$ ]]; then - echo "Error: Invalid LLVM version. Must be llvm-20, llvm-21, llvm-22, or higher." + echo "Error: Invalid LLVM version. Must be llvm-21, llvm-22, llvm-23, or higher." exit 1 fi @@ -133,13 +133,29 @@ detect_build_tool() { echo "Detected CMake generator: $generator, using build tool: $BUILD_TOOL" } -# For LLVM 22+ with variant, use module name llvm/22.0-translator or llvm/22.0-native +# How --variant selects the SPIR-V producer depends on the LLVM version. +# +# LLVM 22 has no in-tree HIPSPV backend support (llvm#213052 landed after the 23 +# branch was cut), so the two producers need two separate toolchains and the +# variant picks between the modules llvm/22.0-translator and llvm/22.0-native. +# +# From LLVM 23 on, chipStar patches in llvm#213052, so a single toolchain built +# with the SPIRV target serves both: the translator is built either way, and the +# producer is chosen per compilation by -f[no-]integrated-objemitter. One module, +# llvm/23.0, and the variant becomes a compile flag. +VARIANT_OPTS="" if [[ -n "$variant" ]]; then if [[ "$llvm_version" -lt 22 ]]; then echo "Error: --variant is only supported for LLVM 22 and later." exit 1 fi - CLANG="llvm/${llvm_version}.0-${variant}" + if [[ "$llvm_version" -lt 23 ]]; then + CLANG="llvm/${llvm_version}.0-${variant}" + elif [[ "$variant" == "native" ]]; then + VARIANT_OPTS="-DCHIP_LLVM_USE_INTERGRATED_SPIRV=ON" + else + VARIANT_OPTS="-DCHIP_LLVM_USE_INTERGRATED_SPIRV=OFF" + fi fi # Print out the arguments @@ -230,7 +246,7 @@ else echo "building with $CLANG" LLVM_CONFIG_BIN=$(module show $CLANG 2>&1 | grep -E 'prepend-path\s+PATH' | awk '{print $NF}' | head -1)/llvm-config - cmake ../ -DLLVM_CONFIG_BIN=$LLVM_CONFIG_BIN -DCMAKE_BUILD_TYPE="$build_type" ${CHIP_OPTIONS} + cmake ../ -DLLVM_CONFIG_BIN=$LLVM_CONFIG_BIN -DCMAKE_BUILD_TYPE="$build_type" ${CHIP_OPTIONS} ${VARIANT_OPTS} detect_build_tool $BUILD_TOOL all install -j $(nproc) #&> /dev/null $BUILD_TOOL build_tests install -j $(nproc) #&> /dev/null From 7f8495d58a6fd5048a06303ccc7c25dc5369aa52 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 13:50:20 +0300 Subject: [PATCH 07/22] ci: build and install LLVM 23, drop LLVM 20 Adds an LLVM 23 row to all three matrices in test-llvm-patches.yml and removes the LLVM 20 rows. LLVM 23 needs only one build. chipStar patches in llvm#213052, so a toolchain built with the SPIRV target also carries the translator and the producer is selected per compilation by -f[no-]integrated-objemitter. Hence a single module-name of 23.0 rather than the -native/-translator pair LLVM 22 needs. The omp.h guard in step2 resolves lib/clang/23/include/omp.h, which the LLVM_ENABLE_RUNTIMES=openmp build installs. --- .github/workflows/test-llvm-patches.yml | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test-llvm-patches.yml b/.github/workflows/test-llvm-patches.yml index eb0a5ca15..018b3fc25 100644 --- a/.github/workflows/test-llvm-patches.yml +++ b/.github/workflows/test-llvm-patches.yml @@ -28,10 +28,6 @@ jobs: strategy: matrix: include: - - llvm-version: 20 - build-id: "20" - install-suffix: "" - variant-flag: "" - llvm-version: 21 build-id: "21" install-suffix: "" @@ -44,6 +40,13 @@ jobs: build-id: "22-native" install-suffix: "-native" variant-flag: "--variant native" + # LLVM 23 needs only one build: chipStar patches in llvm#213052, so the + # SPIRV-target build also serves the translator and the producer is + # chosen per compilation by -f[no-]integrated-objemitter. + - llvm-version: 23 + build-id: "23" + install-suffix: "" + variant-flag: "--variant native" fail-fast: true steps: - uses: actions/checkout@v3 @@ -82,9 +85,6 @@ jobs: strategy: matrix: include: - - llvm-version: 20 - build-id: "20" - install-suffix: "" - llvm-version: 21 build-id: "21" install-suffix: "" @@ -94,6 +94,9 @@ jobs: - llvm-version: 22 build-id: "22-native" install-suffix: "-native" + - llvm-version: 23 + build-id: "23" + install-suffix: "" fail-fast: false steps: - uses: actions/checkout@v3 @@ -233,10 +236,6 @@ jobs: strategy: matrix: include: - - llvm-version: 20 - build-id: "20" - install-suffix: "" - module-name: "20.0" - llvm-version: 21 build-id: "21" install-suffix: "" @@ -249,6 +248,10 @@ jobs: build-id: "22-native" install-suffix: "-native" module-name: "22.0-native" + - llvm-version: 23 + build-id: "23" + install-suffix: "" + module-name: "23.0" fail-fast: false steps: - name: Install LLVM ${{ matrix.build-id }} From 86808a217f89f5ab81f03eb9408e5bc588a6d0e7 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 15:41:55 +0300 Subject: [PATCH 08/22] ci: move the remaining LLVM 20 references off 20 configure_llvm.sh no longer accepts --version 20, so presubmit.yml's matrix still asking for it fails at configure time. Move its three pins to 21, the new oldest supported version. Also drop the unit-tests-llvm-20-debug and unit-tests-llvm-20-release jobs from the x86 workflow. They are workflow_dispatch only so they did not fail on a PR, but they call unit_tests.sh with llvm-20 and nothing depends on them. --- .github/workflows/presubmit.yml | 6 ++--- .github/workflows/x86-intel-gpu-ci.yml | 32 -------------------------- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml index 38e6b1983..397d8c576 100644 --- a/.github/workflows/presubmit.yml +++ b/.github/workflows/presubmit.yml @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - llvm-version: [20] + llvm-version: [21] fail-fast: false steps: - uses: actions/checkout@v3 @@ -127,7 +127,7 @@ jobs: matrix: include: - pocl-version: "7.1" - llvm-version: 20 + llvm-version: 21 fail-fast: false steps: - uses: actions/checkout@v3 @@ -202,7 +202,7 @@ jobs: # PoCL backend with specific version combinations - backend: pocl pocl-version: "7.1" - llvm-version: 20 + llvm-version: 21 extra_exclude: "" fail-fast: false steps: diff --git a/.github/workflows/x86-intel-gpu-ci.yml b/.github/workflows/x86-intel-gpu-ci.yml index 85826c354..7da4cfe50 100644 --- a/.github/workflows/x86-intel-gpu-ci.yml +++ b/.github/workflows/x86-intel-gpu-ci.yml @@ -474,38 +474,6 @@ jobs: # debug builds. These run ONLY on a manual workflow_dispatch, not on every # PR, to keep automatic CI fast. Automatic PRs cover llvm-22 native-release # (Stage 1, above) and llvm-22 translator-release (below). - unit-tests-llvm-20-debug: - needs: build-and-test-libceed - if: ${{ !cancelled() && github.event_name == 'workflow_dispatch' }} - runs-on: [self-hosted, Linux, X64] - env: - CHIP_MODULE_CACHE_DIR: "" - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - fetch-depth: 0 - submodules: 'recursive' - - name: Run unit test checking script - run: ./scripts/unit_tests.sh debug llvm-20 - shell: bash - - unit-tests-llvm-20-release: - needs: build-and-test-libceed - if: ${{ !cancelled() && github.event_name == 'workflow_dispatch' }} - runs-on: [self-hosted, Linux, X64] - env: - CHIP_MODULE_CACHE_DIR: "" - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - fetch-depth: 0 - submodules: 'recursive' - - name: Run unit test checking script - run: ./scripts/unit_tests.sh release llvm-20 - shell: bash - unit-tests-llvm-21-debug: needs: build-and-test-libceed if: ${{ !cancelled() && github.event_name == 'workflow_dispatch' }} From f5f55314c3b92db6dc295e55ed9303126acb4321 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 17:49:32 +0300 Subject: [PATCH 09/22] ci: test the LLVM toolchain that was just built, not the installed one configure_llvm.sh builds LLVM with LLVM_LINK_LLVM_DYLIB=ON and CMAKE_INSTALL_RPATH pinned to the final install prefix. The staged (DESTDIR) binaries are therefore thin drivers whose RUNPATH points at $HOME/install/llvm//lib, so a staged clang loads libclang-cpp and libLLVM from the previously installed toolchain. Since essentially all driver logic lives in those libraries, the "Build LLVM N and test chipStar" lanes were exercising the installed compiler while reporting on the newly patched one. That makes the workflow structurally unable to validate a change to llvm-patches/, which is the only reason it exists. It also explains why these lanes went red without any corresponding change to their inputs: the installed toolchains changed underneath them. Verified on meatloaf with the staged LLVM 21 from this branch. The same clang binary, compiling a HIP device TU with -g: default (installed libs): -debug-info-kind=constructor emitted staged libs pinned: no -debug-info-kind emitted Pin the loader to the stage and persist it to the test steps, and fail the Linux lane loudly if the pin does not take effect rather than silently validating the wrong toolchain again. The macOS side gets the same pin as a diagnostic, since its linkage layout is not verified here. --- .github/workflows/test-llvm-patches.yml | 40 +++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-llvm-patches.yml b/.github/workflows/test-llvm-patches.yml index 018b3fc25..c5893e2b2 100644 --- a/.github/workflows/test-llvm-patches.yml +++ b/.github/workflows/test-llvm-patches.yml @@ -142,8 +142,30 @@ jobs: # install-only runtime headers such as omp.h, which made # TestHipccFopenmp fail with "'omp.h' file not found". LLVM_PREFIX="$HOME/install/llvm/${{ matrix.llvm-version }}.0${{ matrix.install-suffix }}" - LLVM_BIN="$HOME/llvm-stage/${{ matrix.build-id }}${LLVM_PREFIX}/bin" + LLVM_STAGE="$HOME/llvm-stage/${{ matrix.build-id }}${LLVM_PREFIX}" + LLVM_BIN="${LLVM_STAGE}/bin" test -f "${LLVM_BIN}/clang" || exit 1 + + # The staged binaries are thin drivers; all the driver logic lives in + # libclang-cpp.so / libLLVM.so. Their RUNPATH points at the *final* + # install prefix ($HOME/install/llvm/), not at the stage, so by + # default the staged clang loads the previously installed libraries + # and silently runs old code. That makes this lane test the installed + # toolchain rather than the one just built from llvm-patches/, which + # is precisely what this workflow exists to validate. Pin the loader + # to the stage, and persist it to the test steps via GITHUB_ENV since + # chipStar invokes clang again at test time. + export LD_LIBRARY_PATH="${LLVM_STAGE}/lib:${LLVM_STAGE}/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" + echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" >> "$GITHUB_ENV" + + # Fail loudly if the pin did not take effect, rather than silently + # validating the wrong toolchain again. + RESOLVED=$(ldd "${LLVM_BIN}/clang" 2>/dev/null | awk '/libclang-cpp/{print $3}') + case "$RESOLVED" in + "${LLVM_STAGE}"/*) echo "OK: clang resolves libclang-cpp from the stage" ;; + "") echo "NOTE: clang does not link libclang-cpp dynamically; nothing to pin" ;; + *) echo "ERROR: clang resolves libclang-cpp from '$RESOLVED', not the stage"; exit 1 ;; + esac test -f "${LLVM_BIN}/../lib/clang/${{ matrix.llvm-version }}/include/omp.h" \ || { echo "ERROR: omp.h missing from LLVM install toolchain at ${LLVM_BIN}"; exit 1; } cd ${{ github.workspace }} @@ -418,11 +440,25 @@ jobs: # the build tree, which lacks install-only runtime headers such as # omp.h (breaks TestHipccFopenmp with "'omp.h' file not found"). LLVM_PREFIX="$HOME/install/llvm/22.0-${{ matrix.variant }}" - LLVM_BIN="$HOME/llvm-stage/22-${{ matrix.variant }}${LLVM_PREFIX}/bin" + LLVM_STAGE="$HOME/llvm-stage/22-${{ matrix.variant }}${LLVM_PREFIX}" + LLVM_BIN="${LLVM_STAGE}/bin" test -f "${LLVM_BIN}/clang" || exit 1 test -f "${LLVM_BIN}/../lib/clang/22/include/omp.h" \ || { echo "ERROR: omp.h missing from LLVM install toolchain at ${LLVM_BIN}"; exit 1; } + # configure_llvm.sh builds with LLVM_LINK_LLVM_DYLIB=ON and + # CMAKE_INSTALL_RPATH pinned to the final install prefix, so a staged + # (DESTDIR) clang resolves libclang-cpp/libLLVM from the previously + # installed toolchain and runs old driver code. Pin the loader to the + # stage so this lane tests what it just built. DYLD_LIBRARY_PATH (not + # DYLD_FALLBACK_LIBRARY_PATH) is required: fallback is consulted only + # after @rpath resolution fails, and here it succeeds with the wrong + # library. Diagnostic only, not fatal, since the macOS linkage layout + # is not verified here the way the Linux one is. + export DYLD_LIBRARY_PATH="${LLVM_STAGE}/lib${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}" + echo "clang links against:" + otool -L "${LLVM_BIN}/clang" 2>/dev/null | grep -iE "clang-cpp|libLLVM" || true + export PATH="/Users/paulius/.pyenv/shims:/opt/homebrew/bin:/opt/homebrew/sbin:$PATH" export CHIP_DEVICE_TYPE=pocl export OCL_ICD_VENDORS=/Users/paulius/install/pocl/etc/OpenCL/vendors/ From ce2fedaabfbdd2f2e76cf5c05719b0dba4b16920 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Mon, 3 Aug 2026 20:40:03 +0300 Subject: [PATCH 10/22] llvm-patches: let the SPIR-V backend emit subgroup ops at SPIR-V 1.2 chipStar targets spirv64v1.2, and on LLVM 23 the integrated SPIR-V backend is the default producer. The backend refuses to emit the GroupNonUniform* capabilities below SPIR-V 1.3, so any warp-level primitive kills the whole compilation: GroupNonUniformShuffle(65) requires SPIR-V version 1.3 or later fatal error: error in backend: Unable to meet SPIR-V requirements for this target. This is the same deviation the SPIRV-LLVM-Translator has carried for years via spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch; the backend simply never had an equivalent, which is why LLVM 23 was the first configuration to hit it. Reproduced in isolation on LLVM main, no chipStar involved: spirv64v1.2 + sub_group_shuffle -> Unable to meet SPIR-V requirements spirv64v1.3 + sub_group_shuffle -> ok The backend gates these capabilities in two independent places and both must be relaxed; relaxing only the .td leaves them unavailable and fails identically. The whole GroupNonUniform family is relaxed because chipStar emits shuffle, shuffle-relative, ballot, arithmetic min/max and quad ops, and all of them also require the parent GroupNonUniform capability, which is itself gated at 1.3. --- .../0003-subgroup-caps-are-spirv-1.2.patch | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 llvm-patches/llvm-23/llvm/0003-subgroup-caps-are-spirv-1.2.patch diff --git a/llvm-patches/llvm-23/llvm/0003-subgroup-caps-are-spirv-1.2.patch b/llvm-patches/llvm-23/llvm/0003-subgroup-caps-are-spirv-1.2.patch new file mode 100644 index 000000000..bf3ac2c21 --- /dev/null +++ b/llvm-patches/llvm-23/llvm/0003-subgroup-caps-are-spirv-1.2.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chipStar +Date: Sun, 3 Aug 2026 20:40:00 +0300 +Subject: [PATCH 3/3] Pretend the SPIR-V ver needed by subgroup ops is 1.2 + +Mirror of the SPIRV-LLVM-Translator patch +spirv-translator/0001-pretend-subgroup-caps-are-spirv-1.2.patch, for the +in-tree SPIR-V backend. + +chipStar targets spirv64v1.2 (OFFLOAD_TRIPLE spirv64v1.2-unknown-chipstar +on LLVM 23+). The GroupNonUniform* capabilities genuinely require SPIR-V +1.3 per spec, but they work on the v1.2 implementations we target, which +is why the translator has carried the same deviation for years. + +Without this the backend cannot emit chipStar's warp-level primitives and +aborts the whole compilation (seen building TestBoolParamShuffle): + + GroupNonUniformShuffle(65) requires SPIR-V version 1.3 or later + fatal error: error in backend: Unable to meet SPIR-V requirements + for this target. + +The backend gates these capabilities in two independent places, so both +have to be relaxed: + + 1. SPIRVSymbolicOperands.td, the per-capability minVersion (0x10300). + 2. SPIRVModuleAnalysis.cpp initAvailableCapabilities(), which only makes + the capabilities available at all when the subtarget is >= 1.3. + Relaxing only (1) leaves them unavailable and fails identically. + +The whole GroupNonUniform family is relaxed rather than only Shuffle, +because chipStar emits Shuffle/ShuffleXor (65), ShuffleUp/ShuffleDown +(66), Ballot (64), the arithmetic min/max ops (63) and the Quad ops (68), +and every one of them additionally requires the parent GroupNonUniform +(61), which is itself gated at 1.3. Relaxing only the capability named in +the first diagnostic just moves the error to the next one. + +GroupNonUniformRotateKHR (6026) needs no change: it is gated by +SPV_KHR_subgroup_rotate rather than by a minimum version. + +The initAvailableCapabilities() change is shared with the Vulkan path, +which is harmless here because chipStar only ever builds for the OpenCL +kernel environment, and Vulkan targets separately add GroupNonUniform via +the "Core in Vulkan 1.1 and earlier" block. + +Applies-to: llvm-project llvmorg-23.1.0-rc2 +Upstream-status: deliberate spec deviation, not upstreamable (these +capabilities genuinely require SPIR-V 1.3 per spec). +--- +diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp ++++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +@@ -958,7 +958,7 @@ + addAvailableCaps({Capability::Shader, Capability::Linkage, Capability::Int8, + Capability::Int16}); + +- if (ST.isAtLeastSPIRVVer(VersionTuple(1, 3))) ++ if (ST.isAtLeastSPIRVVer(VersionTuple(1, 2))) + addAvailableCaps({Capability::GroupNonUniform, + Capability::GroupNonUniformVote, + Capability::GroupNonUniformArithmetic, +diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td ++++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +@@ -489,14 +489,14 @@ + defm SubgroupDispatch : CapabilityOperand<58, 0x10100, 0, [], [DeviceEnqueue]>; + defm NamedBarrier : CapabilityOperand<59, 0x10100, 0, [], [Kernel]>; + defm PipeStorage : CapabilityOperand<60, 0x10100, 0, [], [Pipes]>; +-defm GroupNonUniform : CapabilityOperand<61, 0x10300, 0, [], []>; +-defm GroupNonUniformVote : CapabilityOperand<62, 0x10300, 0, [], [GroupNonUniform]>; +-defm GroupNonUniformArithmetic : CapabilityOperand<63, 0x10300, 0, [], [GroupNonUniform]>; +-defm GroupNonUniformBallot : CapabilityOperand<64, 0x10300, 0, [], [GroupNonUniform]>; +-defm GroupNonUniformShuffle : CapabilityOperand<65, 0x10300, 0, [], [GroupNonUniform]>; +-defm GroupNonUniformShuffleRelative : CapabilityOperand<66, 0x10300, 0, [], [GroupNonUniform]>; +-defm GroupNonUniformClustered : CapabilityOperand<67, 0x10300, 0, [], [GroupNonUniform]>; +-defm GroupNonUniformQuad : CapabilityOperand<68, 0x10300, 0, [], [GroupNonUniform]>; ++defm GroupNonUniform : CapabilityOperand<61, 0x10200, 0, [], []>; ++defm GroupNonUniformVote : CapabilityOperand<62, 0x10200, 0, [], [GroupNonUniform]>; ++defm GroupNonUniformArithmetic : CapabilityOperand<63, 0x10200, 0, [], [GroupNonUniform]>; ++defm GroupNonUniformBallot : CapabilityOperand<64, 0x10200, 0, [], [GroupNonUniform]>; ++defm GroupNonUniformShuffle : CapabilityOperand<65, 0x10200, 0, [], [GroupNonUniform]>; ++defm GroupNonUniformShuffleRelative : CapabilityOperand<66, 0x10200, 0, [], [GroupNonUniform]>; ++defm GroupNonUniformClustered : CapabilityOperand<67, 0x10200, 0, [], [GroupNonUniform]>; ++defm GroupNonUniformQuad : CapabilityOperand<68, 0x10200, 0, [], [GroupNonUniform]>; + defm SubgroupBallotKHR : CapabilityOperand<4423, 0, 0, [SPV_KHR_shader_ballot], []>; + defm DrawParameters : CapabilityOperand<4427, 0x10300, 0, [SPV_KHR_shader_draw_parameters], [Shader]>; + defm SubgroupVoteKHR : CapabilityOperand<4431, 0, 0, [SPV_KHR_subgroup_vote], []>; +-- +2.43.0 From dc9de3b74ecd7e1de886aec980a3a5d88bb4832e Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Thu, 12 Mar 2026 12:42:21 +0200 Subject: [PATCH 11/22] Fix remaining isZeroValue() in HipPrintf for LLVM 23 Commit 0947b0eeceaf fixed two occurrences but missed line 136. LLVM 23 removed Constant::isZeroValue(); use isNullValue() which is equivalent. (cherry picked from commit a127229e5ba19aca93f3bdf4086a0462df926d40) --- llvm_passes/HipPrintf.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/llvm_passes/HipPrintf.cpp b/llvm_passes/HipPrintf.cpp index 7702ec000..18a71fc40 100644 --- a/llvm_passes/HipPrintf.cpp +++ b/llvm_passes/HipPrintf.cpp @@ -133,11 +133,7 @@ getFormatStringPieces(Value *FmtStrArg, unsigned &NumberOfFormatSpecs) { dyn_cast(OrigFmtStr->getInitializer()); if (FmtStrData == nullptr) { -#if LLVM_VERSION_MAJOR >= 23 assert(OrigFmtStr->getInitializer()->isNullValue()); -#else - assert(OrigFmtStr->getInitializer()->isZeroValue()); -#endif FmtStrPieces.push_back(""); NumberOfFormatSpecs = 0; return FmtStrPieces; From 5efa684d848b06c7242c7c39965be51d4410f8fc Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 22 Jul 2026 12:28:07 +0300 Subject: [PATCH 12/22] Pass -fno-integrated-objemitter in translator mode on LLVM 23 LLVM 23's HIPSPV toolchain now defaults to the in-tree SPIR-V backend when built, so translator mode must request llvm-spirv explicitly. (cherry picked from commit 9c740105cc6ac1a13f5c7b506d170b661e3dc4e4) --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8220a4705..b9ef865b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,6 +381,10 @@ endif() set(SPIRV_EMITTER_OPTS "") if(CHIP_LLVM_USE_INTERGRATED_SPIRV) set(SPIRV_EMITTER_OPTS "-fintegrated-objemitter") +elseif(LLVM_VERSION_MAJOR GREATER_EQUAL 23) + # LLVM 23's HIPSPV toolchain defaults to the in-tree SPIR-V backend when it + # is built; explicitly request the llvm-spirv translator. + set(SPIRV_EMITTER_OPTS "-fno-integrated-objemitter") endif() if(CHIP_VERBOSE) From 8c3a28aa27d03a02189dd635421f80cbaebae764 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 11 Mar 2026 09:53:37 +0200 Subject: [PATCH 13/22] Fix use-after-free in per-thread queue teardown CHIPUninitializeCallOnce accessed PerThreadDefaultQueue (a thread_local unique_ptr) from an atexit handler. TLS destruction order relative to atexit is implementation-defined; with clang 23 the unique_ptr is already destroyed, causing a SEGFAULT on the dangling pointer. Remove the per-thread queue sync since TLS destruction handles cleanup. (cherry picked from commit 74aed1ed7363630368295da14337fd4e5642f8e3) --- src/CHIPDriver.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/CHIPDriver.cc b/src/CHIPDriver.cc index 903488fec..33998a2e2 100644 --- a/src/CHIPDriver.cc +++ b/src/CHIPDriver.cc @@ -230,12 +230,13 @@ void CHIPUninitializeCallOnce() { if (LegacyQueue) { LegacyQueue->finish(); } - if (Dev->isPerThreadStreamUsed()) { - auto PerThreadQueue = Dev->getPerThreadDefaultQueue(); - if (PerThreadQueue) { - PerThreadQueue->finish(); - } - } + // Note: We intentionally do NOT sync the per-thread default queue + // here. PerThreadDefaultQueue is a thread_local unique_ptr whose + // destructor may have already run by the time this atexit handler + // executes (TLS destruction order vs atexit order is + // implementation-defined). Accessing destroyed TLS is UB and + // causes a SEGFAULT with some compilers (e.g. clang 23). The + // per-thread queue will be cleaned up by its own TLS destructor. } // call deallocateDeviceVariables on all devices. From 65025d699baf31d20a30b3d9a0719ebdf27bf7d9 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Sun, 14 Jun 2026 13:35:18 +0300 Subject: [PATCH 14/22] HipPrintf: lower single device printf (fixes device-side assert) The early-out in HipPrintfToOpenCLPrintfPass treated *any* module with a single printf use as already-lowered ("only used by _cl_printf"). That is only true once the pass has created its _cl_print_str helper. A module whose sole printf call is a genuine, not-yet-lowered call -- e.g. the device-side __assert_fail printf from spirv_hip.hh, which is the only printf in a kernel that just uses assert() -- also has exactly one use, so the pass skipped it. Skipping leaves that printf's format string in a non-constant address space. The SPIR-V translator must then emit SPV_EXT_relaxed_printf_string_address_space, which the runtime consumer (IGC on Intel GPUs, the llvm-spirv reverse path on macOS/pocl) rejects with "InvalidModule ... disabled by --spirv-ext option". The kernel module fails to load and the assert test hangs (200s timeout). Only short-circuit when the _cl_print_str helper already exists. With the helper absent, fall through and lower the printf so its format string ends up in the constant address space and the extension is no longer required. Fixes Unit_Assert_Positive_Basic_KernelPass_AssertionTest timing out on LLVM 21 / 22-native (Linux, Intel Arc B570) and LLVM 22 native/translator (macOS). Verified end-to-end on a B570: the test now passes and device-side assert prints its message and aborts correctly. (cherry picked from commit d043503846518a53727aee182787d1dab2144d9e) --- llvm_passes/HipPrintf.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/llvm_passes/HipPrintf.cpp b/llvm_passes/HipPrintf.cpp index 18a71fc40..d07b0dcea 100644 --- a/llvm_passes/HipPrintf.cpp +++ b/llvm_passes/HipPrintf.cpp @@ -426,9 +426,22 @@ PreservedAnalyses HipPrintfToOpenCLPrintfPass::run(Module &Mod, GlobalValue *Printf = Mod.getNamedValue("printf"); GlobalValue *HipPrintf = Mod.getNamedValue(ORIG_PRINTF_FUNC_NAME); - // No printf decl in the module, no printf calls to handle. - // 1 use if the "printf" is only used by "_cl_printf" - if (Printf == nullptr || Printf->getNumUses() == 1) + // No printf decl in the module: no printf calls to handle. + if (Printf == nullptr) + return PreservedAnalyses::all(); + + // If the pass already ran on this module it created the "_cl_print_str" + // helper, whose body contains the only remaining printf("%c", ...) call. + // In that case the single printf use is already in the lowered (constant + // address space) form and there is nothing more to do. We must NOT use a + // bare "getNumUses() == 1" test here: a module with exactly one *genuine* + // printf call and no _cl_print_str yet (e.g. only the device-side + // __assert_fail printf) also has a single use, and skipping it would leave + // the format string in a non-constant address space. That forces the + // SPIR-V translator to emit SPV_EXT_relaxed_printf_string_address_space, + // which the consumer (e.g. IGC) then rejects at module load time. + if (Mod.getNamedValue(ORIG_PRINT_STRING_FUNC_NAME) != nullptr && + Printf->getNumUses() == 1) return PreservedAnalyses::all(); LLVM_DEBUG(dbgs() << "Found printf decl: "; Printf->dump()); From 7f682bddebc65a58dd2f578d68258c0d09763c64 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Tue, 4 Aug 2026 08:48:01 +0300 Subject: [PATCH 15/22] bitcode: emit rtdevlib SPIR-V with a plain spirv64 triple embed_spirv_in_cpp() compiled the rtdevlib bitcode with --target=spirv64v${MAX_SPIRV_VERSION}-unknown-chipstar. The "chipstar" OS component selects the HIPSPV toolchain, whose -c action emits LLVM bitcode for the offload driver to link later rather than SPIR-V. clang exits 0 and writes the file, so every rtdevlib ".spv" silently contained LLVM bitcode ("BC\xc0\xde") instead of SPIR-V ("\x03\x02\x23\x07"), and that bitcode was embedded into libCHIP and handed to the OpenCL driver: clLinkProgram failed: -17 CL_LINK_PROGRAM_FAILURE (Intel GPU) clLinkProgram failed: -44 CL_INVALID_PROGRAM (Intel CPU) "Device library link step failed." Measured with the LLVM 23 toolchain: --target=spirv64v1.2-unknown-chipstar -> 4243c0de (LLVM bitcode) --target=spirv64v1.2 -> 03022307 (SPIR-V) Only LLVM 23 is affected: OFFLOAD_TRIPLE has no "chipstar" OS component before 23, so the rtdevlib was built correctly there. This is why the 21 and 22 lanes are green while every LLVM 23 test that links the rtdevlib (ballot, atomics, printf) failed. Verified on meatloaf against the LLVM 23 toolchain: all rtdevlib modules now carry the SPIR-V magic and pass spirv-val, and the previously failing ballot and atomics tests pass on both Intel GPU and Intel CPU OpenCL with no clLinkProgram errors. --- bitcode/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bitcode/CMakeLists.txt b/bitcode/CMakeLists.txt index 276db6599..8b8e1f911 100644 --- a/bitcode/CMakeLists.txt +++ b/bitcode/CMakeLists.txt @@ -205,8 +205,15 @@ function(embed_spirv_in_cpp OUTPUT "${OUTPUT_SOURCE}" "${OUTPUT_HEADER}" DEPENDS "${BC_SOURCE}" BYPRODUCTS "${SPIR_BINARY}" + # NOTE: the triple must NOT carry the "chipstar" OS component here. + # spirv64vX-unknown-chipstar selects the HIPSPV toolchain, whose -c + # action emits LLVM bitcode for the offload driver to link later; it + # exits 0, so the ".spv" silently contains "BC\xc0\xde" instead of + # SPIR-V and every clLinkProgram() of the rtdevlib fails with + # CL_LINK_PROGRAM_FAILURE / CL_INVALID_PROGRAM. The plain spirv64vX + # triple selects the SPIRV toolchain, which emits SPIR-V directly. COMMAND "${CMAKE_CXX_COMPILER}" - --target=spirv64v${MAX_SPIRV_VERSION}-unknown-chipstar + --target=spirv64v${MAX_SPIRV_VERSION} -mllvm -spirv-ext=${SPIRV_EXTENSIONS} -c -x ir "${BC_SOURCE}" -o "${SPIR_BINARY}" From 7650b7704a89d84208caadf8943ccb2a8ac23377 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Tue, 4 Aug 2026 09:40:36 +0300 Subject: [PATCH 16/22] ci: use the fixed IGC build for the LLVM patch test lanes IGC's optimizer miscompiles chipStar kernels, which TestSnakeMiscompileO2 catches. The failure is not in chipStar or in LLVM: the same chipStar build, the same LLVM 23 toolchain and the same SPIR-V module produce the correct answer on the Intel CPU runtime and on any Intel GPU when IGC's optimizer is disabled, and the wrong answer otherwise. Measured, varying only the IGC library: IGC 2.36.3 (meatloaf, latest in apt) Arc A380 FAIL IGC 2.38.2 (cupcake stock) Arc B570 FAIL IGC 2.38.2 (cupcake stock) UHD 770 FAIL igc/all-fixes-2026.07.30 Arc A380 PASS igc/all-fixes-2026.07.30 Arc B570 PASS igc/all-fixes-2026.07.30 UHD 770 PASS IGC 2.38.2 + -cl-opt-disable Arc B570 PASS Intel CPU OpenCL runtime (same spv) PASS The bug is unfixed in both released IGCs, so load the local build that carries the fixes. Full dGPU OpenCL suite on meatloaf with LLVM 23 and this IGC: 100% tests passed, 0 failed out of 974. The module is installed at ~/modulefiles/igc/all-fixes-2026.07.30 on the Linux X64 runner and only prepends LD_LIBRARY_PATH and PATH, so it is scoped to these steps and does not disturb the system driver. --- .github/workflows/test-llvm-patches.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/test-llvm-patches.yml b/.github/workflows/test-llvm-patches.yml index c5893e2b2..2030a9039 100644 --- a/.github/workflows/test-llvm-patches.yml +++ b/.github/workflows/test-llvm-patches.yml @@ -187,6 +187,9 @@ jobs: elif [ -f /etc/profile.d/lmod.sh ]; then source /etc/profile.d/lmod.sh &> /dev/null else source /etc/profile.d/modules.sh &> /dev/null; fi module use ~/modulefiles + # IGC 2.36.3/2.38.2 miscompile chipStar kernels under their + # optimizer (TestSnakeMiscompileO2); this build carries the fix. + module load igc/all-fixes-2026.07.30 module load opencl/igpu cd ${{ github.workspace }}/build-llvm${{ matrix.build-id }} ../scripts/check.py ./ igpu opencl @@ -200,6 +203,9 @@ jobs: elif [ -f /etc/profile.d/lmod.sh ]; then source /etc/profile.d/lmod.sh &> /dev/null else source /etc/profile.d/modules.sh &> /dev/null; fi module use ~/modulefiles + # IGC 2.36.3/2.38.2 miscompile chipStar kernels under their + # optimizer (TestSnakeMiscompileO2); this build carries the fix. + module load igc/all-fixes-2026.07.30 module load level-zero/igpu cd ${{ github.workspace }}/build-llvm${{ matrix.build-id }} ../scripts/check.py ./ igpu level0 @@ -212,6 +218,9 @@ jobs: elif [ -f /etc/profile.d/lmod.sh ]; then source /etc/profile.d/lmod.sh &> /dev/null else source /etc/profile.d/modules.sh &> /dev/null; fi module use ~/modulefiles + # IGC 2.36.3/2.38.2 miscompile chipStar kernels under their + # optimizer (TestSnakeMiscompileO2); this build carries the fix. + module load igc/all-fixes-2026.07.30 module load level-zero/dgpu cd ${{ github.workspace }}/build-llvm${{ matrix.build-id }} ../scripts/check.py ./ dgpu level0 @@ -224,6 +233,9 @@ jobs: elif [ -f /etc/profile.d/lmod.sh ]; then source /etc/profile.d/lmod.sh &> /dev/null else source /etc/profile.d/modules.sh &> /dev/null; fi module use ~/modulefiles + # IGC 2.36.3/2.38.2 miscompile chipStar kernels under their + # optimizer (TestSnakeMiscompileO2); this build carries the fix. + module load igc/all-fixes-2026.07.30 module load opencl/dgpu cd ${{ github.workspace }}/build-llvm${{ matrix.build-id }} ../scripts/check.py ./ dgpu opencl @@ -236,6 +248,9 @@ jobs: elif [ -f /etc/profile.d/lmod.sh ]; then source /etc/profile.d/lmod.sh &> /dev/null else source /etc/profile.d/modules.sh &> /dev/null; fi module use ~/modulefiles + # IGC 2.36.3/2.38.2 miscompile chipStar kernels under their + # optimizer (TestSnakeMiscompileO2); this build carries the fix. + module load igc/all-fixes-2026.07.30 module load opencl/cpu cd ${{ github.workspace }}/build-llvm${{ matrix.build-id }} ../scripts/check.py ./ cpu opencl --num-tries=3 From b8b19f877947888ebb68426b99af073b2710ba23 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Tue, 4 Aug 2026 12:03:35 +0300 Subject: [PATCH 17/22] llvm-patches: backport ExpandVariadics printf fix to LLVM 23 Backport of llvm/llvm-project#206998, merged upstream 2026-07-21 as b1d21c6d3121, after release/23.x was cut and therefore missing from llvmorg-23.1.0-rc2. LLVM 23 runs ExpandVariadics in the SPIR-V backend IR pipeline for non-shader targets, i.e. OpenCL kernels. Its guard skips SPIR-V builtins by testing the demangled name against the prefix "printf(", but an unmangled C printf demangles to plain "printf" with no argument list, so OpenCL/HIP printf slipped through and had its arguments packed into a vararg buffer: LLVM 22: %87 = OpExtInst %uint %1 printf %fmt %arg0 %arg1 %arg2 LLVM 23: %99 = OpExtInst %uint %1 printf %fmt %vararg_buffer Device printf then printed garbage and crashed, on Intel dGPU, iGPU and the Intel CPU OpenCL runtime alike, unaffected by -cl-opt-disable. This is what cuda-simplePrintf and PrintfDynamic were catching on the LLVM 23 lane; chipStar's own printf lowering is correct and the IR reaching the backend is identical on LLVM 22 and 23. Drop this patch once release/23.x picks the fix up. --- ...ariadics-dont-lower-unmangled-printf.patch | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 llvm-patches/llvm-23/llvm/0004-expandvariadics-dont-lower-unmangled-printf.patch diff --git a/llvm-patches/llvm-23/llvm/0004-expandvariadics-dont-lower-unmangled-printf.patch b/llvm-patches/llvm-23/llvm/0004-expandvariadics-dont-lower-unmangled-printf.patch new file mode 100644 index 000000000..32308d9df --- /dev/null +++ b/llvm-patches/llvm-23/llvm/0004-expandvariadics-dont-lower-unmangled-printf.patch @@ -0,0 +1,60 @@ +From b1d21c6d3121000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulius Velesko +Date: Tue, 21 Jul 2026 12:39:16 +0000 +Subject: [PATCH 4/4] [ExpandVariadics] Don't lower unmangled C printf on SPIR-V + +Backport of llvm/llvm-project#206998 +(https://github.com/llvm/llvm-project/pull/206998), merged to main on +2026-07-21 as b1d21c6d3121, after the release/23.x branch was cut. It is +therefore missing from llvmorg-23.1.0-rc2. + +LLVM 23 runs ExpandVariadics in the SPIR-V backend's IR pipeline for +non-shader targets, i.e. for OpenCL kernels. The pass already skips +SPIR-V builtins, but its guard tests the *demangled* name against the +prefix "printf(" and an unmangled C printf demangles to plain "printf", +with no argument list, so the guard misses it. OpenCL/HIP printf is +emitted unmangled, so it was lowered: the arguments got packed into a +Function-storage buffer and a single pointer was passed to the OpenCL.std +printf extended instruction. + + LLVM 22: %87 = OpExtInst %uint %1 printf %fmt %arg0 %arg1 %arg2 + LLVM 23: %99 = OpExtInst %uint %1 printf %fmt %vararg_buffer + +Every device-side printf then printed garbage and crashed. With chipStar's +samples/cuda_samples/0_Simple/simplePrintf, whose kernel prints +"[%d, %d]:\t\tValue is:%d\n": + + expected [0, 0]: Value is:10 + LLVM 23 dGPU [-4120576, ]: Value is: (then SIGSEGV) + LLVM 23 CPU OpenCL [540685652, 0]: Value is:0 + +Independent of device and of IGC: it reproduced on Intel dGPU, iGPU and +the Intel CPU OpenCL runtime, and -cl-opt-disable did not change it. +chipStar's own printf lowering is correct and the IR reaching the backend +is identical on LLVM 22 and 23; feeding that same IR to both backends +produces the two forms above. + +Applies-to: llvm-project llvmorg-23.1.0-rc2 +Upstream-status: merged upstream, drop this patch once release/23.x picks +it up. +--- +diff --git a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp +--- a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp ++++ b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp +@@ -1067,8 +1067,13 @@ + StringRef DemangledName(Demangled); + + // Skip any SPIR-V builtins. ++ // Note: an unmangled C `printf` declaration demangles to "printf" with no ++ // argument list, so the "printf(" prefix check below misses it. Match the ++ // bare name as well so OpenCL/HIP printf (emitted unmangled) is left as a ++ // variadic call for the backend's OpenCL.std printf lowering to expand ++ // inline, rather than being packed into a vararg buffer here. + if (DemangledName.starts_with("__spirv_") || +- DemangledName.starts_with("printf(")) ++ DemangledName.starts_with("printf(") || F->getName() == "printf") + return true; + + return false; +-- +2.43.0 From 367795d769528564b63dd9f2bb82a8594fce6db9 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Tue, 4 Aug 2026 12:56:45 +0300 Subject: [PATCH 18/22] llvm-patches: guard SPIRVEmitIntrinsics getArg for variadic callees SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr() bounds its operand loop by the call's argument count while indexing the callee's declared parameters: for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) ... Argument *CalledArg = CalledF->getArg(OpIdx); For a variadic callee those counts differ and getArg() asserts: Function.h:861: llvm::Function::getArg(unsigned): Assertion `i < NumArgs && "getArg() out of range!"' failed. getArg() is only reached for pointer-typed operands that are neither Instructions nor Arguments, i.e. pointer constants, so triggering it needs a variadic call whose variadic argument is a constant pointer. OpenCL printf with a "%s" argument is exactly that: printf declares one parameter and the call carries several, the extra one pointing at a string literal. It does not reproduce while ExpandVariadics lowers printf away before this pass runs, which is why it only appeared after backporting llvm/llvm-project#206998 (patch 0004). Reproducer: chipStar's hip-tests catch/unit/printf/printfFlags_exe.cc, which crashed clang during hipspv-link. The same unguarded indexing is present on llvm-project main, so a kernel calling printf("%s", ...) should assert there too; this needs reporting upstream rather than being a release-branch gap. --- ...rv-guard-getarg-for-variadic-callees.patch | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 llvm-patches/llvm-23/llvm/0005-spirv-guard-getarg-for-variadic-callees.patch diff --git a/llvm-patches/llvm-23/llvm/0005-spirv-guard-getarg-for-variadic-callees.patch b/llvm-patches/llvm-23/llvm/0005-spirv-guard-getarg-for-variadic-callees.patch new file mode 100644 index 000000000..d4a47bc2e --- /dev/null +++ b/llvm-patches/llvm-23/llvm/0005-spirv-guard-getarg-for-variadic-callees.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: chipStar +Date: Mon, 4 Aug 2026 12:30:00 +0300 +Subject: [PATCH 5/5] [SPIRV] Don't index formal args past a variadic callee + +SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr() walks the operands +of a call with + + for (unsigned OpIdx = 0; OpIdx < CI->arg_size(); OpIdx++) + ... + Argument *CalledArg = CalledF->getArg(OpIdx); + +bounding the loop by the *call's* operand count while indexing the +*callee's* declared parameters. For a variadic callee those differ, and +getArg() asserts: + + Function.h:861: llvm::Function::getArg(unsigned): + Assertion `i < NumArgs && "getArg() out of range!"' failed. + +getArg() is only reached for pointer-typed operands that are not +Instructions or Arguments, i.e. pointer constants, so it needs a variadic +call whose variadic argument is a constant pointer. OpenCL printf with a +"%s" argument is exactly that: the callee declares one parameter (the +format string) and the call carries several, the extra one being a +pointer to a string literal. + +This does not reproduce while ExpandVariadics lowers printf away before +this pass runs. It surfaces once printf is correctly left variadic for +the backend's OpenCL.std lowering (llvm/llvm-project#206998), which is +why chipStar hit it when backporting that fix onto llvmorg-23.1.0-rc2. +The same unguarded indexing is present on main, so a kernel calling +printf("%s", ...) should assert there too. + +Reproducer: chipStar's hip-tests catch/unit/printf/printfFlags_exe.cc, +which crashes clang during hipspv-link. + +Applies-to: llvm-project llvmorg-23.1.0-rc2 +Upstream-status: not yet reported; the same code is on main and looks +like a genuine latent bug rather than a release-branch gap. +--- +diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp ++++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +@@ -2361,6 +2361,13 @@ + // However, we may have assumptions about the formal argument's type and + // may have a need to insert a ptr cast for the actual parameter of this + // call. ++ // A variadic callee has fewer declared parameters than the call has ++ // operands, so OpIdx can address a variadic argument for which no ++ // formal Argument exists. OpenCL kernels reach this with printf, whose ++ // pointer-typed variadic arguments (e.g. "%s") are constants: the ++ // callee declares one parameter but the call carries several. ++ if (OpIdx >= CalledF->arg_size()) ++ continue; + Argument *CalledArg = CalledF->getArg(OpIdx); + if (!GR->findDeducedElementType(CalledArg)) + continue; +-- +2.43.0 From d269ed06ea827e6db406444f7a879f6efa2ea7a2 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 5 Aug 2026 09:49:59 +0300 Subject: [PATCH 19/22] Strip device debug info with an LLVM pass, opt out with CHIP_KEEP_KERNEL_DEBUG_INFO No SPIR-V producer emits debug information that validates: the translator emits a cyclic DebugTypeComposite reference and the in-tree backend emits a DebugCompilationUnit whose DWARF version operand is not a 32-bit unsigned OpConstant. Only IGC on Intel Data Center GPU Max tolerates it, which is what makes gdb-oneapi work on Aurora. Drop the debug metadata at the head of the link-time pipeline instead, so the question is settled in IR where LLVM already has StripDebugInfo(), and set -DCHIP_KEEP_KERNEL_DEBUG_INFO=ON on Aurora to keep it. --- CMakeLists.txt | 1 + llvm_passes/CMakeLists.txt | 5 ++-- llvm_passes/HipPasses.cpp | 12 +++++++++- llvm_passes/HipStripDebugInfo.cpp | 40 +++++++++++++++++++++++++++++++ llvm_passes/HipStripDebugInfo.h | 25 +++++++++++++++++++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 llvm_passes/HipStripDebugInfo.cpp create mode 100644 llvm_passes/HipStripDebugInfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b9ef865b9..677cf8fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,7 @@ option(CHIP_VERBOSE "Verbose compilation" OFF) option(CHIP_BUILD_SHARED_LIBS "Build chipStar as a shared library" ON) option(CHIP_BUILD_DOCS "Build doxygen documentation" OFF) option(CHIP_LLVM_USE_INTERGRATED_SPIRV "Use LLVM's intergrated SPIR-V backend for emitting device binary instead of SPIR-V translator. Auto-detected from LLVM targets when LLVM >= 22." OFF) +option(CHIP_KEEP_KERNEL_DEBUG_INFO "Keep device debug info in kernels. No SPIR-V producer emits debug info that validates, and only IGC on Intel Data Center GPU Max tolerates it, so this is off by default and should only be enabled for that device." OFF) option(CHIP_SET_RPATH "Add CMAKE_INSTALL_PREFIX/lib to the RPATH for chipStar executables" ON) option(CHIP_ENABLE_UNCOMPILABLE_TESTS "Enable tests which are known to not compile" OFF) option(CHIP_BUILD_TESTS "Enable build_tests target" ON) diff --git a/llvm_passes/CMakeLists.txt b/llvm_passes/CMakeLists.txt index 609bfbc56..f1e2d366a 100644 --- a/llvm_passes/CMakeLists.txt +++ b/llvm_passes/CMakeLists.txt @@ -98,7 +98,7 @@ endif() add_library(LLVMHipStripUsedIntrinsics MODULE HipStripUsedIntrinsics.cpp) add_library(LLVMHipDefrost MODULE HipDefrost.cpp) add_library(LLVMHipPasses MODULE HipPasses.cpp - HipDynMem.cpp HipStripUsedIntrinsics.cpp HipDefrost.cpp + HipDynMem.cpp HipStripUsedIntrinsics.cpp HipStripDebugInfo.cpp HipDefrost.cpp HipPrintf.cpp HipGlobalVariables.cpp HipCleanup.cpp HipTextureLowering.cpp HipAbort.cpp HipEmitLoweredNames.cpp HipWarps.cpp HipKernelArgSpiller.cpp HipLowerZeroLengthArrays.cpp HipSanityChecks.cpp HipLowerSwitch.cpp @@ -139,7 +139,8 @@ endif() # validation pipeline runs automatically (see HipVerify.cpp::getVerificationMode). # Release builds keep it off due to the compile-time cost (CHIP-SPV/chipStar#1047). target_compile_definitions(LLVMHipPasses PRIVATE - $<$:CHIP_DEBUG_BUILD>) + $<$:CHIP_DEBUG_BUILD> + $<$:CHIP_KEEP_KERNEL_DEBUG_INFO>) # If trying to recompile with LLVM unloaded, the inlcude path is not found target_compile_options(LLVMHipDynMem PRIVATE -I/${LLVM_INCLUDE_DIRS}) diff --git a/llvm_passes/HipPasses.cpp b/llvm_passes/HipPasses.cpp index 3a8055688..e6c1eec19 100644 --- a/llvm_passes/HipPasses.cpp +++ b/llvm_passes/HipPasses.cpp @@ -18,6 +18,7 @@ #include "HipCleanup.h" #include "HipDefrost.h" #include "HipDynMem.h" +#include "HipStripDebugInfo.h" #include "HipStripUsedIntrinsics.h" #include "HipWarps.h" #include "HipPrintf.h" @@ -125,7 +126,16 @@ addPassWithVerification(ModulePassManager &MPM, PassT &&P, static void addFullLinkTimePasses(ModulePassManager &MPM) { MPM.addPass(HipFixOpenCLMDPass()); // must be first or else we get OCL Version mismatch - + +#ifndef CHIP_KEEP_KERNEL_DEBUG_INFO + // No SPIR-V producer emits debug information our consumers accept, so drop it + // up front unless the build opted in (-DCHIP_KEEP_KERNEL_DEBUG_INFO=ON, which + // only makes sense on Intel Data Center GPU Max). Doing it here also spares + // the passes below from keeping debug metadata consistent as they erase + // globals and functions. See HipStripDebugInfo.cpp. + MPM.addPass(HipStripDebugInfoPass()); +#endif + // Clear any previous results at the start of a new pipeline HipVerifyPass::clearResults(); diff --git a/llvm_passes/HipStripDebugInfo.cpp b/llvm_passes/HipStripDebugInfo.cpp new file mode 100644 index 000000000..c0f6a762c --- /dev/null +++ b/llvm_passes/HipStripDebugInfo.cpp @@ -0,0 +1,40 @@ +//===- HipStripDebugInfo.cpp ----------------------------------------------===// +// +// Part of the chipStar Project, under the Apache License v2.0 with LLVM +// Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// LLVM pass removing debug information from HIP device code modules. +// +// Neither SPIR-V producer emits debug information our consumers accept: the +// SPIRV-LLVM-Translator emits a cyclic DebugTypeComposite reference which +// spirv-val rejects, and the in-tree SPIR-V backend emits a DebugCompilationUnit +// whose DWARF version operand is not a 32-bit unsigned OpConstant. The spec +// answer for the former, SPV_KHR_relaxed_extended_instruction, is implemented by +// none of the drivers chipStar targets. +// +// Only IGC on Intel Data Center GPU Max tolerates the malformed result, which is +// what makes gdb-oneapi usable on Aurora. Everywhere else the invalid SPIR-V +// either fails validation or makes the device compiler ICE, so the debug +// information has to go. Configure with -DCHIP_KEEP_KERNEL_DEBUG_INFO=ON to keep +// it (see llvm_passes/CMakeLists.txt); the default is to strip. +// +// Stripping here, at the head of the link-time pipeline, also means none of the +// HIP lowering passes has to keep debug metadata consistent while it erases +// globals and functions. +//===----------------------------------------------------------------------===// + +#include "HipStripDebugInfo.h" + +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +PreservedAnalyses HipStripDebugInfoPass::run(Module &M, + ModuleAnalysisManager &AM) { + return StripDebugInfo(M) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/llvm_passes/HipStripDebugInfo.h b/llvm_passes/HipStripDebugInfo.h new file mode 100644 index 000000000..020a2ef55 --- /dev/null +++ b/llvm_passes/HipStripDebugInfo.h @@ -0,0 +1,25 @@ +//===- HipStripDebugInfo.h ------------------------------------------------===// +// +// Part of the chipStar Project, under the Apache License v2.0 with LLVM +// Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// LLVM pass removing debug information from HIP device code modules. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PASSES_HIP_STRIP_DEBUG_INFO_H +#define LLVM_PASSES_HIP_STRIP_DEBUG_INFO_H + +#include "llvm/IR/PassManager.h" + +using namespace llvm; + +class HipStripDebugInfoPass : public PassInfoMixin { +public: + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + static bool isRequired() { return true; } +}; + +#endif From d52e29e0ff16ff8b1fde63c6f37076d77d64d883 Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 5 Aug 2026 09:50:31 +0300 Subject: [PATCH 20/22] docs: document CHIP_KEEP_KERNEL_DEBUG_INFO --- docs/Profiling.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/Profiling.md b/docs/Profiling.md index 3b0a1a249..395fe0bdf 100644 --- a/docs/Profiling.md +++ b/docs/Profiling.md @@ -12,15 +12,19 @@ vary by installation. | In-kernel debugging, line info + breakpoints | `-g -O0` | — | | In-kernel debugging, readable locals | `-g -O0` | `CHIP_JIT_FLAGS="-cl-opt-disable"` | -Device debug info requires LLVM 23 built by -`scripts/configure_llvm.sh --version 23`, which applies chipStar's -`preserve-device-debug-info` patch (upstream from LLVM 24, -[llvm#210504](https://github.com/llvm/llvm-project/pull/210504)) on top of -the in-tree SPIR-V backend backport. On LLVM 21 and 22, and on 23 when -`-fno-integrated-objemitter` selects the SPIRV-LLVM-Translator, device -debug info is stripped: the translator emits a cyclic -`DebugTypeComposite` `Parent` reference that `spirv-val` rejects and IGC -mis-handles. +Device debug info is stripped by default. No SPIR-V producer emits debug +information that `spirv-val` accepts: the SPIRV-LLVM-Translator emits a +cyclic type reference, and the in-tree SPIR-V backend emits a +`DebugCompilationUnit` whose DWARF version operand is not a 32-bit +unsigned `OpConstant`. Only IGC on Intel Data Center GPU Max tolerates +the result, so chipStar drops the debug metadata in an LLVM pass at +device link time. + +To keep it, build chipStar with `-DCHIP_KEEP_KERNEL_DEBUG_INFO=ON` and an +LLVM 23 toolchain from `scripts/configure_llvm.sh --version 23`, which +applies chipStar's `preserve-device-debug-info` patch (upstream from LLVM +24, [llvm#210504](https://github.com/llvm/llvm-project/pull/210504)). That +combination is only expected to work on Intel Data Center GPU Max. ## Compile time vs JIT time From 11d049d73c39df37366b6e470587baefac4ea86c Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 5 Aug 2026 10:17:58 +0300 Subject: [PATCH 21/22] samples: drop the unnecessary -fsycl from the interop link line The hip_sycl_interop[_no_buffers] executables contain no SYCL device code; it all lives in the onemkl_gemm_wrapper libraries that icpx builds. The SYCL runtime they need is already on the link line twice: INTEL_LIBS ends with -lsycl, and libonemkl_gemm_wrapper.so carries the MKL and SYCL libraries in its own DT_NEEDED. -fsycl is a driver mode switch rather than a -l shortcut, so it routed the link through clang-linker-wrapper. From LLVM 23 on that wrapper adds libLLVMSYCL.so, which only exists in an LLVM built with the SYCL project, and the link failed with cannot find libLLVMSYCL.so. --- samples/hip_sycl_interop/CMakeLists.txt | 9 ++++++++- samples/hip_sycl_interop_no_buffers/CMakeLists.txt | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/samples/hip_sycl_interop/CMakeLists.txt b/samples/hip_sycl_interop/CMakeLists.txt index 3bf39be57..949b4aab2 100644 --- a/samples/hip_sycl_interop/CMakeLists.txt +++ b/samples/hip_sycl_interop/CMakeLists.txt @@ -2,7 +2,14 @@ add_subdirectory(onemkl_gemm_wrapper) add_chip_binary(hip_sycl_interop hip_sycl_interop.cpp) add_dependencies(samples hip_sycl_interop) -target_link_options(hip_sycl_interop PRIVATE -fsycl -L${MKL_ROOT}/lib -L${CMAKE_BINARY_DIR} ${INTEL_LIBS} -Wl,-rpath=${CMAKE_BINARY_DIR}:${CMAKE_CURRENT_BINARY_DIR}/onemkl_gemm_wrapper:${ICPX_CORE_LIBDIR}:${ICPX_SYCL_LIBDIR}) + +# No -fsycl here: this executable has no SYCL device code (all of it lives in +# onemkl_gemm_wrapper, built by icpx), and INTEL_LIBS already supplies -lsycl. +# -fsycl is a driver mode switch, not a -l shortcut: it routes the link through +# clang-linker-wrapper, which from LLVM 23 on adds libLLVMSYCL.so to the link. +# That library only exists in an LLVM built with the SYCL project, which +# chipStar's is not, so the link fails with "cannot find libLLVMSYCL.so". +target_link_options(hip_sycl_interop PRIVATE -L${MKL_ROOT}/lib -L${CMAKE_BINARY_DIR} ${INTEL_LIBS} -Wl,-rpath=${CMAKE_BINARY_DIR}:${CMAKE_CURRENT_BINARY_DIR}/onemkl_gemm_wrapper:${ICPX_CORE_LIBDIR}:${ICPX_SYCL_LIBDIR}) target_link_libraries(hip_sycl_interop onemkl_gemm_wrapper -L${CMAKE_BINARY_DIR} -lCHIP ${LevelZero_LIBRARY} -pthread) target_include_directories(hip_sycl_interop PUBLIC ${CHIP_SRC_DIR}/HIP/include ${CHIP_SRC_DIR}/include) diff --git a/samples/hip_sycl_interop_no_buffers/CMakeLists.txt b/samples/hip_sycl_interop_no_buffers/CMakeLists.txt index 5c364911d..fe404a4d5 100644 --- a/samples/hip_sycl_interop_no_buffers/CMakeLists.txt +++ b/samples/hip_sycl_interop_no_buffers/CMakeLists.txt @@ -2,7 +2,9 @@ add_subdirectory(onemkl_gemm_wrapper_no_buffers) add_chip_binary(hip_sycl_interop_no_buffers hip_sycl_interop.cpp) add_dependencies(samples hip_sycl_interop_no_buffers) -target_link_options(hip_sycl_interop_no_buffers PRIVATE -fsycl -L${MKL_ROOT}/lib -L${CMAKE_BINARY_DIR} ${INTEL_LIBS} -Wl,-rpath=${CMAKE_BINARY_DIR}:${CMAKE_CURRENT_BINARY_DIR}/onemkl_gemm_wrapper_no_buffers:${ICPX_CORE_LIBDIR}:${ICPX_SYCL_LIBDIR}) + +# No -fsycl here; see the comment in ../hip_sycl_interop/CMakeLists.txt. +target_link_options(hip_sycl_interop_no_buffers PRIVATE -L${MKL_ROOT}/lib -L${CMAKE_BINARY_DIR} ${INTEL_LIBS} -Wl,-rpath=${CMAKE_BINARY_DIR}:${CMAKE_CURRENT_BINARY_DIR}/onemkl_gemm_wrapper_no_buffers:${ICPX_CORE_LIBDIR}:${ICPX_SYCL_LIBDIR}) target_link_libraries(hip_sycl_interop_no_buffers onemkl_gemm_wrapper_no_buffers) add_test(NAME "hip_sycl_interop_no_buffers" From 8aa7932db4439e48e17f0dd67f4bb05a3d6679ea Mon Sep 17 00:00:00 2001 From: Paulius Velesko Date: Wed, 5 Aug 2026 10:40:08 +0300 Subject: [PATCH 22/22] Correct the per-thread queue teardown comment The old comment said the queue would be cleaned up by its own TLS destructor, which is true of deallocation but implies a synchronization that never happens: ~Queue() is empty, ~CHIPQueueOpenCL() only logs, and ~CHIPQueueLevel0() skips finish() deliberately. Say so, and point at issue #1439 for the fix. --- src/CHIPDriver.cc | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/CHIPDriver.cc b/src/CHIPDriver.cc index 33998a2e2..80faba594 100644 --- a/src/CHIPDriver.cc +++ b/src/CHIPDriver.cc @@ -230,13 +230,19 @@ void CHIPUninitializeCallOnce() { if (LegacyQueue) { LegacyQueue->finish(); } - // Note: We intentionally do NOT sync the per-thread default queue - // here. PerThreadDefaultQueue is a thread_local unique_ptr whose - // destructor may have already run by the time this atexit handler - // executes (TLS destruction order vs atexit order is - // implementation-defined). Accessing destroyed TLS is UB and - // causes a SEGFAULT with some compilers (e.g. clang 23). The - // per-thread queue will be cleaned up by its own TLS destructor. + // Note: the per-thread default queue is deliberately NOT synced here. + // PerThreadDefaultQueue is a thread_local unique_ptr whose destructor + // may already have run by the time this atexit handler executes (TLS + // destruction order versus atexit order is implementation-defined). + // Reading destroyed TLS is UB and segfaults with some compilers (e.g. + // clang 23). A null check cannot help: it reads the same destroyed + // storage. + // + // Nothing else syncs it either. ~Queue() is empty, ~CHIPQueueOpenCL() + // only logs, and ~CHIPQueueLevel0() skips finish() on purpose because + // the Level Zero context may already be gone. So in-flight work on a + // per-thread stream is not awaited at exit. Fixing that needs a + // non-TLS registry of the per-thread queues; see issue #1439. } // call deallocateDeviceVariables on all devices.