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


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to