[llvm] [SPIRV] Add intrinsic for OpGenericCastToPtrExplicit (PR #137626)

Victor Lomuller via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 28 09:35:29 PDT 2025


https://github.com/Naghasan updated https://github.com/llvm/llvm-project/pull/137626

>From 57e1c906793e1314a72ee964f9a563df759b85fa Mon Sep 17 00:00:00 2001
From: Victor Lomuller <victor at codeplay.com>
Date: Mon, 28 Apr 2025 12:12:48 +0100
Subject: [PATCH] [SPIRV] Add intrinsic for OpGenericCastToPtrExplicit

The patch adds an intrinsic to encode
OpGenericCastToPtrExplicit and the associated lowering logic.
---
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |  7 +++
 llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp |  4 ++
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 15 +++++++
 .../pointers/generic_cast_to_ptr_explicit.ll  | 44 +++++++++++++++++++
 4 files changed, 70 insertions(+)
 create mode 100644 llvm/test/CodeGen/SPIRV/pointers/generic_cast_to_ptr_explicit.ll

diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 77cca0a58424f..404467781b4d0 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -10,6 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+def generic_ptr_ty : LLVMQualPointerType<4>;
+
 let TargetPrefix = "spv" in {
   def int_spv_assign_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
   def int_spv_assign_ptr_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
@@ -146,4 +148,9 @@ let TargetPrefix = "spv" in {
 
   // FPMaxErrorDecorationINTEL
   def int_spv_assign_fpmaxerror_decoration: Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
+
+  // Convert between the generic storage class and a concrete one.
+  def int_spv_generic_cast_to_ptr_explicit
+    : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [generic_ptr_ty],
+       [IntrNoMem, NoUndef<RetIndex>]>;
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 6205dfedb79fb..4325023406c7c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -680,6 +680,10 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
       } else {
         llvm_unreachable("Unknown handle type for spv_resource_getpointer.");
       }
+    } else if (II && II->getIntrinsicID() ==
+                         Intrinsic::spv_generic_cast_to_ptr_explicit) {
+      Ty = deduceElementTypeHelper(CI->getArgOperand(0), Visited,
+                                   UnknownElemTypeI8);
     } else if (Function *CalledF = CI->getCalledFunction()) {
       std::string DemangledName =
           getOclOrSpirvBuiltinDemangledName(CalledF->getName());
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 8304077f049a3..0f6e9fe9154dc 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3120,6 +3120,21 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
                .addUse(MemSemReg)
                .constrainAllUses(TII, TRI, RBI);
   }
+  case Intrinsic::spv_generic_cast_to_ptr_explicit: {
+    Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 1).getReg();
+    SPIRV::StorageClass::StorageClass ResSC =
+        GR.getPointerStorageClass(ResType);
+    if (isGenericCastablePtr(ResSC))
+      report_fatal_error("The target storage class is not castable from the "
+                         "Generic storage class");
+    return BuildMI(BB, I, I.getDebugLoc(),
+                   TII.get(SPIRV::OpGenericCastToPtrExplicit))
+        .addDef(ResVReg)
+        .addUse(GR.getSPIRVTypeID(ResType))
+        .addUse(PtrReg)
+        .addImm(ResSC)
+        .constrainAllUses(TII, TRI, RBI);
+  }
   case Intrinsic::spv_lifetime_start:
   case Intrinsic::spv_lifetime_end: {
     unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
diff --git a/llvm/test/CodeGen/SPIRV/pointers/generic_cast_to_ptr_explicit.ll b/llvm/test/CodeGen/SPIRV/pointers/generic_cast_to_ptr_explicit.ll
new file mode 100644
index 0000000000000..f2c5a82dca64d
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/pointers/generic_cast_to_ptr_explicit.ll
@@ -0,0 +1,44 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Make sure SPIRV operation function calls for generic_cast_to_ptr_explicit are lowered correctly.
+
+; CHECK: %[[#Char:]] = OpTypeInt 8 0
+; CHECK: %[[#GenericPtr:]] = OpTypePointer Generic %[[#Char]]
+; CHECK: %[[#GlobalPtr:]] = OpTypePointer CrossWorkgroup %[[#Char]]
+; CHECK: %[[#LocalPtr:]] = OpTypePointer Workgroup %[[#Char]]
+; CHECK: %[[#PrivatePtr:]] = OpTypePointer Function %[[#Char]]
+
+; CHECK: OpFunction %[[#GlobalPtr]]
+; CHECK-NEXT: %[[#Arg:]] = OpFunctionParameter %[[#GenericPtr]]
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpGenericCastToPtrExplicit %[[#GlobalPtr]] %[[#Arg]] CrossWorkgroup
+define ptr addrspace(1) @test_to_global(ptr addrspace(4) noundef %ptr) {
+entry:
+  %cast = call spir_func noundef ptr addrspace(1) @llvm.spv.generic.cast.to.ptr.explicit.p1(ptr addrspace(4) noundef %ptr)
+  ret ptr addrspace(1) %cast
+}
+
+; CHECK: OpFunction %[[#LocalPtr]]
+; CHECK-NEXT: %[[#Arg:]] = OpFunctionParameter %[[#GenericPtr]]
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpGenericCastToPtrExplicit %[[#LocalPtr]] %[[#Arg]] Workgroup
+define ptr addrspace(3) @test_to_local(ptr addrspace(4) noundef %ptr) {
+entry:
+  %cast = call spir_func noundef ptr addrspace(3) @llvm.spv.generic.cast.to.ptr.explicit.p3(ptr addrspace(4) noundef %ptr)
+  ret ptr addrspace(3) %cast
+}
+
+; CHECK: OpFunction %[[#PrivatePtr]]
+; CHECK-NEXT: %[[#Arg:]] = OpFunctionParameter %[[#GenericPtr]]
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: OpGenericCastToPtrExplicit %[[#PrivatePtr]] %[[#Arg]] Function
+define ptr @test_to_private(ptr addrspace(4) noundef %ptr) {
+entry:
+  %cast = call spir_func noundef ptr @llvm.spv.generic.cast.to.ptr.explicit.p0(ptr addrspace(4) noundef %ptr)
+  ret ptr %cast
+}
+
+declare noundef ptr @llvm.spv.generic.cast.to.ptr.explicit.p0(ptr addrspace(4))
+declare noundef ptr addrspace(1) @llvm.spv.generic.cast.to.ptr.explicit.p1(ptr addrspace(4))
+declare noundef ptr addrspace(3) @llvm.spv.generic.cast.to.ptr.explicit.p3(ptr addrspace(4))



More information about the llvm-commits mailing list