[clang] [llvm] [SPIR-V] Fix enqueue_kernel crash on clang -O0 local sizes (PR #230924)
Arseniy Obolenskiy via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 11 01:37:50 PDT 2026
https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/230924
Clang -O0 passes local sizes as a pointer to the first element, not to the array
>From 418a27ab7f6ccb38fd456efd3392f5818d3dc906 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Sun, 11 Oct 2026 10:37:08 +0200
Subject: [PATCH] [SPIR-V] Fix enqueue_kernel crash on clang -O0 local sizes
Clang -O0 passes local sizes as a pointer to the first element, not to the array
---
.../spirv-enqueue-kernel-local-size.cl | 24 +++++++++++++++++++
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 12 ++++++----
.../SPIRV/transcoding/enqueue_kernel.ll | 9 +++++++
3 files changed, 41 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGenOpenCL/spirv-enqueue-kernel-local-size.cl
diff --git a/clang/test/CodeGenOpenCL/spirv-enqueue-kernel-local-size.cl b/clang/test/CodeGenOpenCL/spirv-enqueue-kernel-local-size.cl
new file mode 100644
index 0000000000000..806cc854582db
--- /dev/null
+++ b/clang/test/CodeGenOpenCL/spirv-enqueue-kernel-local-size.cl
@@ -0,0 +1,24 @@
+// REQUIRES: spirv-registered-target
+// RUN: %clang_cc1 -cl-std=CL2.0 -O0 -emit-llvm -o - -triple spirv64-unknown-unknown %s | FileCheck %s
+// RUN: %clang_cc1 -cl-std=CL2.0 -O0 -S -o - -triple spirv64-unknown-unknown -mllvm --spirv-ext=+SPV_INTEL_function_pointers %s | FileCheck %s --check-prefix=SPIRV
+
+// Check that local sizes are passed as a pointer to the first array element
+// and that the SPIR-V backend lowers this form.
+
+typedef struct {int a;} ndrange_t;
+
+kernel void test(queue_t q) {
+ ndrange_t nd;
+// CHECK-LABEL: define {{.*}} void @__clang_ocl_kern_imp_test(
+// CHECK: %[[SIZES:.*]] = alloca [2 x i64]
+// CHECK: %[[ELEM:.*]] = getelementptr [2 x i64], ptr %[[SIZES]], i32 0, i32 0
+// CHECK: call spir_func i32 @__enqueue_kernel_varargs({{.*}}, i32 2, ptr %[[ELEM]])
+
+// SPIRV-DAG: %[[#INT32:]] = OpTypeInt 32 0
+// SPIRV-DAG: %[[#ZERO:]] = OpConstantNull %[[#INT32]]
+// SPIRV: %[[#ELEM:]] = OpPtrAccessChain %[[#]] %[[#]] %[[#ZERO]] %[[#ZERO]]
+// SPIRV: %[[#SIZE0:]] = OpPtrAccessChain %[[#]] %[[#ELEM]] %[[#ZERO]]{{$}}
+// SPIRV-NEXT: %[[#SIZE1:]] = OpPtrAccessChain %[[#]] %[[#ELEM]] %[[#]]{{$}}
+// SPIRV-NEXT: OpEnqueueKernel {{.*}} %[[#SIZE0]] %[[#SIZE1]]{{$}}
+ enqueue_kernel(q, 0, nd, ^(local void *p1, local void *p2){}, 101u, 102u);
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 245fe1d89ccf5..43598565561c3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -3176,16 +3176,20 @@ static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call,
uint64_t NumElem = ConstOp.getCImm()->getValue().getZExtValue();
Register LocalSizeArrayReg = Call->Arguments[LocalSizeElemPtrIdx];
+ SPIRVTypeInst PointeeTy =
+ GR->getPointeeType(GR->getSPIRVTypeForVReg(LocalSizeArrayReg));
+ bool IsArrayPtr = PointeeTy && PointeeTy->getOpcode() == SPIRV::OpTypeArray;
for (unsigned i = 0; i < NumElem; ++i) {
Register Reg = MRI->createVirtualRegister(&SPIRV::pIDRegClass);
auto GEPInst = MIRBuilder.buildIntrinsic(
Intrinsic::spv_gep, ArrayRef<Register>{Reg}, true, false);
GEPInst
- .addImm(0) // In bound.
- .addUse(LocalSizeArrayReg) // Base pointer.
- .addUse(buildConstantIntReg32(0, MIRBuilder, GR)) // Indices.
- .addUse(buildConstantIntReg32(i, MIRBuilder, GR));
+ .addImm(0) // In bound.
+ .addUse(LocalSizeArrayReg); // Base pointer.
+ if (IsArrayPtr)
+ GEPInst.addUse(buildConstantIntReg32(0, MIRBuilder, GR));
+ GEPInst.addUse(buildConstantIntReg32(i, MIRBuilder, GR));
LocalSizes.push_back(Reg);
}
}
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll b/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
index 592e387db851b..b5f17332c9891 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
@@ -110,6 +110,13 @@
;; },
;; 101, 102, 104);
;;
+;; // same, but local sizes passed as a pointer to the first element
+; CHECK: %[[#ElemPtr:]] = OpPtrAccessChain %[[#]] %[[#]] %[[#Num0i32]] %[[#Num0i32]]
+; CHECK: %[[#LocalSize0:]] = OpPtrAccessChain %[[#]] %[[#ElemPtr]] %[[#Num0i32]]{{$}}
+; CHECK-NEXT: %[[#LocalSize1:]] = OpPtrAccessChain %[[#]] %[[#ElemPtr]] %[[#Num1i32]]{{$}}
+; CHECK-NEXT: %[[#LocalSize2:]] = OpPtrAccessChain %[[#]] %[[#ElemPtr]] %[[#Num2i32]]{{$}}
+; CHECK-NEXT: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel5Ptr]] %[[#]] %[[#Num16i32]] %[[#Num8i32]] %[[#LocalSize0]] %[[#LocalSize1]] %[[#LocalSize2]]
+;;
;; // null event, no var args
; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#event2]] %[[#InvokeKernel6Ptr]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
;; enqueue_kernel(default_queue, flags, ndrange, 0, NULL, &clk_event,
@@ -198,6 +205,8 @@ entry:
%10 = getelementptr inbounds i8, ptr %block_sizes15.i, i64 16
store i64 104, ptr %10, align 8
%11 = call spir_func i32 @__enqueue_kernel_varargs(target("spirv.Queue") %default_queue, i32 0, ptr %tmp14.i, ptr addrspace(4) addrspacecast (ptr @__device_side_enqueue_block_invoke_5_kernel to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr addrspace(1) @__block_literal_global.2 to ptr addrspace(4)), i32 3, ptr %block_sizes15.i)
+ %elem_sizes = getelementptr [3 x i64], ptr %block_sizes15.i, i32 0, i32 0
+ %elem_call = call spir_func i32 @__enqueue_kernel_varargs(target("spirv.Queue") %default_queue, i32 0, ptr %tmp14.i, ptr addrspace(4) addrspacecast (ptr @__device_side_enqueue_block_invoke_5_kernel to ptr addrspace(4)), ptr addrspace(4) addrspacecast (ptr addrspace(1) @__block_literal_global.2 to ptr addrspace(4)), i32 3, ptr %elem_sizes)
store i32 36, ptr %block17.i, align 8
%block.align19.i = getelementptr inbounds i8, ptr %block17.i, i64 4
store i32 8, ptr %block.align19.i, align 4
More information about the cfe-commits
mailing list