[llvm] [SPIR-V] Fix i8 pointer type for NULL events in OpEnqueueKernel (PR #201125)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 07:06:56 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/201125

>From d4e96f1d123c9e60c50598370fb79a07c356f39d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 2 Jun 2026 16:03:54 +0200
Subject: [PATCH] [SPIR-V] Fix i8 pointer type for NULL events in
 OpEnqueueKernel

---
 llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp       | 38 +++++++++++++------
 .../SPIRV/transcoding/enqueue_kernel.ll       |  6 +--
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 9bc29dd0103a6..7c32914e609eb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -2975,27 +2975,41 @@ static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call,
   // 2. Process all arguments which requered preparation.
   // 2.1 Events - use Call arguments, or use dummy nulls in case of absence of
   // events
+
+  // Per SPIR-V spec, OpEnqueueKernel's Wait Events / Ret Event operands
+  // must be pointers to OpTypeDeviceEvent. Build the LLVM TargetExtType
+  // for spirv.DeviceEvent so getOrCreateSPIRVPointerType can register
+  // both the SPIR-V type and the LLVM-side mapping; deriving the pointer
+  // from an opaque LLVM PointerType would lose the pointee and deduce
+  // to <Generic i8*>.
+  auto BuildDeviceEventNullPtr = [&]() {
+    LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
+    Type *DeviceEventTy = TargetExtType::get(Ctx, "spirv.DeviceEvent");
+    SPIRVTypeInst DeviceEventPtrTy = GR->getOrCreateSPIRVPointerType(
+        DeviceEventTy, MIRBuilder, SPIRV::StorageClass::Generic);
+    return GR->getOrCreateConstNullPtr(MIRBuilder, DeviceEventPtrTy);
+  };
+
   Register NumEventsReg;
   Register WaitEventsReg;
   Register RetEventReg;
   if (HasEvents) {
+    auto IsNullEvent = [&](Register R) {
+      MachineInstr *Def = getDefInstrMaybeConstant(R, MRI);
+      return Def->getOpcode() == TargetOpcode::G_CONSTANT &&
+             Def->getOperand(1).getCImm()->isZero();
+    };
+
     NumEventsReg = Call->Arguments[NumEventsIdx];
     WaitEventsReg = Call->Arguments[WaitEventsIdx];
     RetEventReg = Call->Arguments[RetEventIdx];
+    if (IsNullEvent(WaitEventsReg))
+      WaitEventsReg = BuildDeviceEventNullPtr();
+    if (IsNullEvent(RetEventReg))
+      RetEventReg = BuildDeviceEventNullPtr();
   } else {
     NumEventsReg = buildConstantIntReg32(0, MIRBuilder, GR);
-    // Per SPIR-V spec, OpEnqueueKernel's Wait Events / Ret Event operands
-    // must be pointers to OpTypeDeviceEvent. Build the LLVM TargetExtType
-    // for spirv.DeviceEvent so getOrCreateSPIRVPointerType can register
-    // both the SPIR-V type and the LLVM-side mapping; deriving the pointer
-    // from an opaque LLVM PointerType would lose the pointee and deduce
-    // to <Generic i8*>.
-    LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
-    Type *DeviceEventTy = TargetExtType::get(Ctx, "spirv.DeviceEvent");
-    SPIRVTypeInst DeviceEventPtrTy = GR->getOrCreateSPIRVPointerType(
-        DeviceEventTy, MIRBuilder, SPIRV::StorageClass::Generic);
-    Register NullPtr =
-        GR->getOrCreateConstNullPtr(MIRBuilder, DeviceEventPtrTy);
+    Register NullPtr = BuildDeviceEventNullPtr();
     WaitEventsReg = NullPtr;
     RetEventReg = NullPtr;
   }
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll b/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
index 2d7e73d71094e..2053b13882545 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
@@ -24,7 +24,6 @@
 ; CHECK-DAG: %[[#TypeNDRangeStruct:]] = OpTypeStruct %[[#typeInt32]] %[[#Array3x64]] %[[#Array3x64]] %[[#Array3x64]]
 
 ; CHECK-DAG: %[[#pointerInt8:]] = OpTypePointer Generic %[[#typeInt8]]
-; CHECK-DAG: %[[#nullPtrInt8:]] = OpConstantNull %[[#pointerInt8]]
 ; CHECK-DAG: %[[#nullArray3x64:]] = OpConstantNull %[[#Array3x64]]
 
 ; CHECK-DAG: %[[#typeEvent:]] = OpTypeDeviceEvent
@@ -60,9 +59,8 @@
 ;;
 ;;     const size_t gs[] = {1,2,4};
 ;;
-; TODO: Fix int8 type came from clang in case of NULL events passed in opencl's enqueue_kernel.
 ;;     // enqueue empty kernel
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue:]] %[[#Num1i32]] %[[#NDRange3]] %[[#Num0i32]] %[[#nullPtrInt8]] %[[#nullPtrInt8]] %[[#InvokeKernel1]] %[[#]] %[[#Num16i32]] %[[#Num8i32]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue:]] %[[#Num1i32]] %[[#NDRange3]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel1]] %[[#]] %[[#Num16i32]] %[[#Num8i32]]
 ;;     enqueue_kernel(default_queue,
 ;;             CLK_ENQUEUE_FLAGS_WAIT_KERNEL,
 ;;             ndrange_3D(gs),
@@ -103,7 +101,7 @@
 ;;             101, 102, 104);
 ;;
 ;;     // null event, no var args
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrInt8]] %[[#event2]] %[[#InvokeKernel6]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#event2]] %[[#InvokeKernel6]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
 ;;     enqueue_kernel(default_queue, flags, ndrange, 0, NULL, &clk_event,
 ;;             ^(void) {
 ;;             a[i] = b[i];



More information about the llvm-commits mailing list