[llvm] [SPIR-V] Prevent generating OpTypePointer with OpTypeFunction pointee without extension (PR #207347)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 3 01:31:18 PDT 2026


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

Fall back to i8 in getOrCreateSPIRVPointerType when the extension is absent

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

Fall back to i8 in getOrCreateSPIRVPointerType when the extension is absent
---
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 76 ++++++++++---------
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   |  4 +-
 .../pointers/fun-ptr-as-data-load-store.ll    | 50 ++++++++++++
 3 files changed, 93 insertions(+), 37 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..4e490edd03e17 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -201,25 +201,25 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeInt(unsigned Width,
 SPIRVTypeInst
 SPIRVGlobalRegistry::getOpTypeFloat(uint32_t Width,
                                     MachineIRBuilder &MIRBuilder) {
-  return createConstOrTypeAtFunctionEntry(MIRBuilder, [&](MachineIRBuilder
-                                                              &MIRBuilder) {
-    return MIRBuilder.buildInstr(SPIRV::OpTypeFloat)
-        .addDef(createTypeVReg(MIRBuilder))
-        .addImm(Width);
-  });
+  return createConstOrTypeAtFunctionEntry(
+      MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+        return MIRBuilder.buildInstr(SPIRV::OpTypeFloat)
+            .addDef(createTypeVReg(MIRBuilder))
+            .addImm(Width);
+      });
 }
 
 SPIRVTypeInst
 SPIRVGlobalRegistry::getOpTypeFloat(uint32_t Width,
                                     MachineIRBuilder &MIRBuilder,
                                     SPIRV::FPEncoding::FPEncoding FPEncode) {
-  return createConstOrTypeAtFunctionEntry(MIRBuilder, [&](MachineIRBuilder
-                                                              &MIRBuilder) {
-    return MIRBuilder.buildInstr(SPIRV::OpTypeFloat)
-        .addDef(createTypeVReg(MIRBuilder))
-        .addImm(Width)
-        .addImm(FPEncode);
-  });
+  return createConstOrTypeAtFunctionEntry(
+      MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+        return MIRBuilder.buildInstr(SPIRV::OpTypeFloat)
+            .addDef(createTypeVReg(MIRBuilder))
+            .addImm(Width)
+            .addImm(FPEncode);
+      });
 }
 
 SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeVoid(MachineIRBuilder &MIRBuilder) {
@@ -1084,23 +1084,23 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOpTypePointer(
   if (!Reg.isValid())
     Reg = createTypeVReg(MIRBuilder);
 
-  return createConstOrTypeAtFunctionEntry(MIRBuilder, [&](MachineIRBuilder
-                                                              &MIRBuilder) {
-    return MIRBuilder.buildInstr(SPIRV::OpTypePointer)
-        .addDef(Reg)
-        .addImm(static_cast<uint32_t>(SC))
-        .addUse(getSPIRVTypeID(ElemType));
-  });
+  return createConstOrTypeAtFunctionEntry(
+      MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+        return MIRBuilder.buildInstr(SPIRV::OpTypePointer)
+            .addDef(Reg)
+            .addImm(static_cast<uint32_t>(SC))
+            .addUse(getSPIRVTypeID(ElemType));
+      });
 }
 
 SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeForwardPointer(
     SPIRV::StorageClass::StorageClass SC, MachineIRBuilder &MIRBuilder) {
-  return createConstOrTypeAtFunctionEntry(MIRBuilder, [&](MachineIRBuilder
-                                                              &MIRBuilder) {
-    return MIRBuilder.buildInstr(SPIRV::OpTypeForwardPointer)
-        .addUse(createTypeVReg(MIRBuilder))
-        .addImm(static_cast<uint32_t>(SC));
-  });
+  return createConstOrTypeAtFunctionEntry(
+      MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+        return MIRBuilder.buildInstr(SPIRV::OpTypeForwardPointer)
+            .addUse(createTypeVReg(MIRBuilder))
+            .addImm(static_cast<uint32_t>(SC));
+      });
 }
 
 SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeFunction(
@@ -1115,15 +1115,15 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeFunction(
         Fn, "SPIR-V shaders do not support variadic functions",
         MIRBuilder.getDebugLoc()));
   }
-  return createConstOrTypeAtFunctionEntry(MIRBuilder, [&](MachineIRBuilder
-                                                              &MIRBuilder) {
-    auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeFunction)
-                   .addDef(createTypeVReg(MIRBuilder))
-                   .addUse(getSPIRVTypeID(RetType));
-    for (auto &ArgType : ArgTypes)
-      MIB.addUse(getSPIRVTypeID(ArgType));
-    return MIB;
-  });
+  return createConstOrTypeAtFunctionEntry(
+      MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+        auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeFunction)
+                       .addDef(createTypeVReg(MIRBuilder))
+                       .addUse(getSPIRVTypeID(RetType));
+        for (auto &ArgType : ArgTypes)
+          MIB.addUse(getSPIRVTypeID(ArgType));
+        return MIB;
+      });
 }
 
 SPIRVTypeInst SPIRVGlobalRegistry::getOrCreateOpTypeFunctionWithArgs(
@@ -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
+}



More information about the llvm-commits mailing list