[clang] 61b4fea - [SPIR-V] Fix enqueue_kernel crash on clang -O0 local sizes (#230924)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 12 02:35:30 PDT 2026
Author: Arseniy Obolenskiy
Date: 2026-10-12T11:35:22+02:00
New Revision: 61b4fea0090f087c65031b0956748edb70811834
URL: https://github.com/llvm/llvm-project/commit/61b4fea0090f087c65031b0956748edb70811834
DIFF: https://github.com/llvm/llvm-project/commit/61b4fea0090f087c65031b0956748edb70811834.diff
LOG: [SPIR-V] Fix enqueue_kernel crash on clang -O0 local sizes (#230924)
Clang -O0 passes local sizes as a pointer to the first element, not to
the array
Added:
clang/test/CodeGenOpenCL/spirv-enqueue-kernel-local-size.cl
Modified:
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
Removed:
################################################################################
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 00000000000000..806cc854582dba
--- /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 245fe1d89ccf5a..43598565561c3b 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 592e387db851b5..b5f17332c98913 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