Skip to content

[SPIRV] Add intrinsic for OpGenericCastToPtrExplicit #137626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

Naghasan
Copy link
Contributor

The patch adds an intrinsic to encode OpGenericCastToPtrExplicit and the associated lowering logic.

@llvmbot
Copy link
Member

llvmbot commented Apr 28, 2025

@llvm/pr-subscribers-backend-spir-v

@llvm/pr-subscribers-llvm-ir

Author: Victor Lomuller (Naghasan)

Changes

The patch adds an intrinsic to encode OpGenericCastToPtrExplicit and the associated lowering logic.


Full diff: https://github.com/llvm/llvm-project/pull/137626.diff

4 Files Affected:

  • (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+7)
  • (modified) llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp (+4)
  • (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+14)
  • (added) llvm/test/CodeGen/SPIRV/pointers/generic_cast_to_ptr_explicit.ll (+44)
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..3d69d3e640ae6 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3120,6 +3120,20 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
                .addUse(MemSemReg)
                .constrainAllUses(TII, TRI, RBI);
   }
+  case Intrinsic::spv_generic_cast_to_ptr_explicit: {
+    bool Result = true;
+    Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 1).getReg();
+    SPIRV::StorageClass::StorageClass ResSC =
+        GR.getPointerStorageClass(ResType);
+    Result &= isGenericCastablePtr(ResSC);
+    return Result && 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))

@Naghasan Naghasan force-pushed the generic_cast_to_ptr_explicit_intrinsic branch from 7524450 to 57e1c90 Compare April 28, 2025 16:35
The patch adds an intrinsic to encode
OpGenericCastToPtrExplicit and the associated lowering logic.
@Naghasan Naghasan force-pushed the generic_cast_to_ptr_explicit_intrinsic branch from 57e1c90 to 690f8af Compare April 28, 2025 16:35
@VyacheslavLevytskyy VyacheslavLevytskyy merged commit 082598a into llvm:main Apr 29, 2025
10 of 12 checks passed
gizmondo pushed a commit to gizmondo/llvm-project that referenced this pull request Apr 29, 2025
The patch adds an intrinsic to encode OpGenericCastToPtrExplicit and the
associated lowering logic.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants