[llvm] [SPIR-V] Diagnose function used as data pointer without SPV_INTEL_function_pointers (PR #207347)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 10 04:40:39 PDT 2026


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

>From 114c2b346d825b1835a011e9d44dd1b9fbe7902b Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 3 Jul 2026 10:31:37 +0200
Subject: [PATCH 1/3] [SPIR-V] Prevent generating OpTypePointer with
 OpTypeFunction pointee without extension

---
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp |  6 ++-
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   |  4 +-
 .../pointers/fun-ptr-as-data-load-store.ll    | 50 +++++++++++++++++++
 3 files changed, 58 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 6dd965c266fcb..b507a5cd16921 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -1998,6 +1998,10 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
 SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
     const Type *BaseType, MachineIRBuilder &MIRBuilder,
     SPIRV::StorageClass::StorageClass SC) {
+  if (BaseType->isFunctionTy() &&
+      !cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget())
+           .canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
+    BaseType = Type::getInt8Ty(MIRBuilder.getContext());
   // TODO: Need to check if EmitIr should always be true.
   SPIRVTypeInst SpirvBaseType = getOrCreateSPIRVType(
       BaseType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
@@ -2026,7 +2030,7 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
   assert(!storageClassRequiresExplictLayout(SC));
   SPIRVTypeInst R = getOrCreateSPIRVPointerType(LLVMType, MIRBuilder, SC);
   assert(
-      getPointeeType(R) == BaseType &&
+      (getPointeeType(R) == BaseType || LLVMType->isFunctionTy()) &&
       "The base type was not correctly laid out for the given storage class.");
   return R;
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index a8772abfe4c27..3db324edfa498 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -258,7 +258,9 @@ static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
       Register Source = MI.getOperand(2).getReg();
       Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
       auto SC =
-          isa<FunctionType>(ElemTy)
+          isa<FunctionType>(ElemTy) &&
+                  ST->canUseExtension(
+                      SPIRV::Extension::SPV_INTEL_function_pointers)
               ? SPIRV::StorageClass::CodeSectionINTEL
               : addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST);
       SPIRVTypeInst AssignedPtrType =
diff --git a/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll b/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll
new file mode 100644
index 0000000000000..312b8656fb593
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll
@@ -0,0 +1,50 @@
+; A function used as a data pointer (load/store through @fn) must produce
+; OpTypePointer with an i8 pointee when SPV_INTEL_function_pointers is absent,
+; or a proper OpTypePointer/CodeSectionINTEL to the function type when present.
+
+; Without the extension: pointer pointee must be i8, never OpTypeFunction.
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O2 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O2 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; With the extension: pointer-to-function types and FunctionPointerINTEL constants are emitted.
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefix=CHECK-EXT
+; RUN: llc -verify-machineinstrs -O2 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefix=CHECK-EXT
+
+; CHECK-DAG: %[[#I8:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#]] = OpTypePointer CrossWorkgroup %[[#I8]]
+; CHECK-DAG: %[[#FUNCTY:]] = OpTypeFunction
+; CHECK-NOT: OpTypePointer {{[A-Za-z]+}} %[[#FUNCTY]]{{$}}
+
+; CHECK-EXT-DAG: OpCapability FunctionPointersINTEL
+; CHECK-EXT-DAG: OpExtension "SPV_INTEL_function_pointers"
+; CHECK-EXT-DAG: %[[#I8:]] = OpTypeInt 8 0
+; CHECK-EXT-DAG: %[[#FUNCTY:]] = OpTypeFunction
+; CHECK-EXT-DAG: %[[#PTR_CW:]] = OpTypePointer CrossWorkgroup %[[#FUNCTY]]
+; CHECK-EXT-DAG: %[[#PTR_CS:]] = OpTypePointer CodeSectionINTEL %[[#FUNCTY]]
+; CHECK-EXT-DAG: OpConstantFunctionPointerINTEL %[[#PTR_CS]]
+
+define spir_kernel void @fuzz_kernel_load(ptr addrspace(1) %0, ptr addrspace(1) %1, i32 %2) {
+  %4 = icmp sgt i32 %2, 0
+  br i1 %4, label %5, label %9
+5:
+  %6 = load i32, ptr @fuzz_kernel_load, align 4
+  %7 = mul i32 %2, -1640531527
+  %8 = add i32 %6, %6
+  ret void
+9:
+  unreachable
+}
+
+define spir_kernel void @fuzz_kernel_store(ptr addrspace(1) nofree readnone captures(none) %in,
+                                            ptr addrspace(1) nofree readnone captures(none) %out,
+                                            i32 %n) local_unnamed_addr {
+  %ok = icmp sgt i32 %n, 0
+  br i1 %ok, label %1, label %2
+1:
+  store i32 -1640531527, ptr @fuzz_kernel_store, align 4
+  br label %2
+2:
+  ret void
+}

>From 75e6f713b8233ef29b00f7f7d08b7156829e5777 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 9 Jul 2026 17:23:04 +0200
Subject: [PATCH 2/3] Address comment

---
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 12 ++++++++---
 .../pointers/fun-ptr-as-data-load-store.ll    | 20 +++++++------------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index b507a5cd16921..5dbc25ea09aa3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -2000,8 +2000,14 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
     SPIRV::StorageClass::StorageClass SC) {
   if (BaseType->isFunctionTy() &&
       !cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget())
-           .canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
-    BaseType = Type::getInt8Ty(MIRBuilder.getContext());
+           .canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
+    const Function &F = MIRBuilder.getMF().getFunction();
+    F.getContext().diagnose(
+        DiagnosticInfoUnsupported(F,
+                                  "Function used as a data pointer requires "
+                                  "SPV_INTEL_function_pointers extension",
+                                  DebugLoc(), DS_Error));
+  }
   // TODO: Need to check if EmitIr should always be true.
   SPIRVTypeInst SpirvBaseType = getOrCreateSPIRVType(
       BaseType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
@@ -2030,7 +2036,7 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(
   assert(!storageClassRequiresExplictLayout(SC));
   SPIRVTypeInst R = getOrCreateSPIRVPointerType(LLVMType, MIRBuilder, SC);
   assert(
-      (getPointeeType(R) == BaseType || LLVMType->isFunctionTy()) &&
+      getPointeeType(R) == BaseType &&
       "The base type was not correctly laid out for the given storage class.");
   return R;
 }
diff --git a/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll b/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll
index 312b8656fb593..a111e4efa8ba8 100644
--- a/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll
+++ b/llvm/test/CodeGen/SPIRV/pointers/fun-ptr-as-data-load-store.ll
@@ -1,25 +1,19 @@
-; A function used as a data pointer (load/store through @fn) must produce
-; OpTypePointer with an i8 pointee when SPV_INTEL_function_pointers is absent,
-; or a proper OpTypePointer/CodeSectionINTEL to the function type when present.
+; A function used as a data pointer (load/store through @fn) requires
+; SPV_INTEL_function_pointers, since it needs OpTypePointer with an
+; OpTypeFunction pointee.
 
-; Without the extension: pointer pointee must be i8, never OpTypeFunction.
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: llc -verify-machineinstrs -O2 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-; RUN: %if spirv-tools %{ llc -O2 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; Without the extension: using a function as a data pointer is an error.
+; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+; RUN: not llc -O2 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
 
 ; With the extension: pointer-to-function types and FunctionPointerINTEL constants are emitted.
 ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefix=CHECK-EXT
 ; RUN: llc -verify-machineinstrs -O2 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefix=CHECK-EXT
 
-; CHECK-DAG: %[[#I8:]] = OpTypeInt 8 0
-; CHECK-DAG: %[[#]] = OpTypePointer CrossWorkgroup %[[#I8]]
-; CHECK-DAG: %[[#FUNCTY:]] = OpTypeFunction
-; CHECK-NOT: OpTypePointer {{[A-Za-z]+}} %[[#FUNCTY]]{{$}}
+; CHECK-ERROR: error:{{.*}}Function used as a data pointer requires SPV_INTEL_function_pointers extension
 
 ; CHECK-EXT-DAG: OpCapability FunctionPointersINTEL
 ; CHECK-EXT-DAG: OpExtension "SPV_INTEL_function_pointers"
-; CHECK-EXT-DAG: %[[#I8:]] = OpTypeInt 8 0
 ; CHECK-EXT-DAG: %[[#FUNCTY:]] = OpTypeFunction
 ; CHECK-EXT-DAG: %[[#PTR_CW:]] = OpTypePointer CrossWorkgroup %[[#FUNCTY]]
 ; CHECK-EXT-DAG: %[[#PTR_CS:]] = OpTypePointer CodeSectionINTEL %[[#FUNCTY]]

>From 19166ed64cda73f8d5ccb953b3bcbe95812e105d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 10 Jul 2026 13:40:27 +0200
Subject: [PATCH 3/3] fix testing

---
 .../CodeGen/SPIRV/global-var-intrinsic.ll     |  7 ++++--
 .../transcoding/block_w_struct_return.ll      |  6 +++--
 .../SPIRV/transcoding/enqueue_kernel.ll       | 25 +++++++++++++------
 .../CodeGen/SPIRV/transcoding/global_block.ll |  7 ++++--
 4 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/global-var-intrinsic.ll b/llvm/test/CodeGen/SPIRV/global-var-intrinsic.ll
index 51d96d053947c..2e32cd0730d9f 100644
--- a/llvm/test/CodeGen/SPIRV/global-var-intrinsic.ll
+++ b/llvm/test/CodeGen/SPIRV/global-var-intrinsic.ll
@@ -6,10 +6,13 @@
 ; clang -S -emit-llvm --target=spir example.cpp
 
 ; Test passes if use of "-verify-machineinstrs" doesn't lead to crash.
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - -filetype=obj | spirv-val %}
 ; CHECK: OpFunction
 
+; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+; CHECK-ERROR: Function used as a data pointer requires SPV_INTEL_function_pointers extension
+
 @ptr_0 = dso_local global ptr null, align 4
 @ptr_1 = dso_local global ptr null, align 4
 @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_example.cpp, ptr null }]
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/block_w_struct_return.ll b/llvm/test/CodeGen/SPIRV/transcoding/block_w_struct_return.ll
index 8404a9f16667a..bcc121c0428c7 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/block_w_struct_return.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/block_w_struct_return.ll
@@ -1,5 +1,7 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV,CHECK-SPIRV1_4
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV,CHECK-SPIRV1_4
+
+; RUN: not llc -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+; CHECK-ERROR: Function used as a data pointer requires SPV_INTEL_function_pointers extension
 
 ;; TODO: We cannot check SPIR_V 1.1 and 1.4 simultaneously, implement additional
 ;;       run with CHECK-SPIRV1_1.
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll b/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
index 2053b13882545..1401ba7f8513e 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/enqueue_kernel.ll
@@ -1,5 +1,7 @@
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK
-; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefix=CHECK
+
+; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+; CHECK-ERROR: Function used as a data pointer requires SPV_INTEL_function_pointers extension
 
 ; CHECK: OpCapability Kernel
 ; CHECK-DAG: %[[#typeInt64:]] = OpTypeInt 64 0
@@ -43,6 +45,13 @@
 ; CHECK-DAG: OpName %[[#InvokeKernel5:]] "__device_side_enqueue_block_invoke_5_kernel"
 ; CHECK-DAG: OpName %[[#InvokeKernel6:]] "__device_side_enqueue_block_invoke_6_kernel"
 
+; CHECK-DAG: %[[#InvokeKernel1Ptr:]] = OpConstantFunctionPointerINTEL %[[#]] %[[#InvokeKernel1]]
+; CHECK-DAG: %[[#InvokeKernel2Ptr:]] = OpConstantFunctionPointerINTEL %[[#]] %[[#InvokeKernel2]]
+; CHECK-DAG: %[[#InvokeKernel3Ptr:]] = OpConstantFunctionPointerINTEL %[[#]] %[[#InvokeKernel3]]
+; CHECK-DAG: %[[#InvokeKernel4Ptr:]] = OpConstantFunctionPointerINTEL %[[#]] %[[#InvokeKernel4]]
+; CHECK-DAG: %[[#InvokeKernel5Ptr:]] = OpConstantFunctionPointerINTEL %[[#]] %[[#InvokeKernel5]]
+; CHECK-DAG: %[[#InvokeKernel6Ptr:]] = OpConstantFunctionPointerINTEL %[[#]] %[[#InvokeKernel6]]
+
 ; CHECK-LABEL: ; -- Begin function device_side_enqueue
 
 ; CHECK: %[[#NDRange3sret:]] = OpBuildNDRange %[[#TypeNDRangeStruct]] %[[#]] %[[#]] %[[#]]
@@ -60,7 +69,7 @@
 ;;     const size_t gs[] = {1,2,4};
 ;;
 ;;     // enqueue empty kernel
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue:]] %[[#Num1i32]] %[[#NDRange3]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel1]] %[[#]] %[[#Num16i32]] %[[#Num8i32]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue:]] %[[#Num1i32]] %[[#NDRange3]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel1Ptr]] %[[#]] %[[#Num16i32]] %[[#Num8i32]]
 ;;     enqueue_kernel(default_queue,
 ;;             CLK_ENQUEUE_FLAGS_WAIT_KERNEL,
 ;;             ndrange_3D(gs),
@@ -68,7 +77,7 @@
 ;;             ^(){});
 ;;
 ;;     // no events, no var args
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel2]] %[[#]] %[[#Num29i32]] %[[#Num8i32]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel2Ptr]] %[[#]] %[[#Num29i32]] %[[#Num8i32]]
 ;;     enqueue_kernel(default_queue, flags, ndrange,
 ;;             ^(void) {
 ;;             a[i] = c0;
@@ -77,14 +86,14 @@
 ;;     // event, no var args
 ; CHECK: %[[#event1:]] = OpPtrCastToGeneric %[[#typeEventPtr]] %[[#]]
 ; CHECK-NEXT: %[[#event2:]] = OpPtrCastToGeneric %[[#typeEventPtr]] %[[#]]
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num2i32]] %[[#event1]] %[[#event2]] %[[#InvokeKernel3]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num2i32]] %[[#event1]] %[[#event2]] %[[#InvokeKernel3Ptr]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
 ;;     enqueue_kernel(default_queue, flags, ndrange, 2, &event_wait_list, &clk_event,
 ;;             ^(void) {
 ;;             a[i] = b[i];
 ;;             });
 ;;
 ;;     // events, var arg
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num2i32]] %[[#event_wait_list2:]] %[[#event2]] %[[#InvokeKernel4]] %[[#]] %[[#Num16i32]] %[[#Num8i32]] %[[#]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num2i32]] %[[#event_wait_list2:]] %[[#event2]] %[[#InvokeKernel4Ptr]] %[[#]] %[[#Num16i32]] %[[#Num8i32]] %[[#]]
 ;;     char c;
 ;;     enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event,
 ;;             ^(local void *p) {
@@ -93,7 +102,7 @@
 ;;             c);
 ;;
 ;;     // no events, three var args
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel5]] %[[#]] %[[#Num16i32]] %[[#Num8i32]] %[[#]] %[[#]] %[[#]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#nullPtrEvent]] %[[#InvokeKernel5Ptr]] %[[#]] %[[#Num16i32]] %[[#Num8i32]] %[[#]] %[[#]] %[[#]]
 ;;     enqueue_kernel(default_queue, flags, ndrange,
 ;;             ^(local void *p1, local void *p2, local void *p3) {
 ;;             return;
@@ -101,7 +110,7 @@
 ;;             101, 102, 104);
 ;;
 ;;     // null event, no var args
-; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#event2]] %[[#InvokeKernel6]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
+; CHECK: %[[#]] = OpEnqueueKernel %[[#typeInt32]] %[[#default_queue]] %[[#Num0i32]] %[[#]] %[[#Num0i32]] %[[#nullPtrEvent]] %[[#event2]] %[[#InvokeKernel6Ptr]] %[[#]] %[[#Num36i32]] %[[#Num8i32]]
 ;;     enqueue_kernel(default_queue, flags, ndrange, 0, NULL, &clk_event,
 ;;             ^(void) {
 ;;             a[i] = b[i];
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/global_block.ll b/llvm/test/CodeGen/SPIRV/transcoding/global_block.ll
index 36b3e6614636f..4531003bbe578 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/global_block.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/global_block.ll
@@ -1,7 +1,10 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV,CHECK-SPIRV1_4
-; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV,CHECK-SPIRV1_4
+; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - -filetype=obj | spirv-val %}
 ;; FIXME: spirv-val fails with OpConstantComposite expects i8*
 
+; RUN: not llc -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+; CHECK-ERROR: Function used as a data pointer requires SPV_INTEL_function_pointers extension
+
 ;; There are no blocks in SPIR-V. Therefore they are translated into regular
 ;; functions. An LLVM module which uses blocks, also contains some auxiliary
 ;; block-specific instructions, which are redundant in SPIR-V and should be



More information about the llvm-commits mailing list