[SPIRV] Add intrinsic for OpGenericCastToPtrExplicit (#137626)

The patch adds an intrinsic to encode OpGenericCastToPtrExplicit and the
associated lowering logic.
This commit is contained in:
Victor Lomuller
2025-04-29 10:58:25 +01:00
committed by GitHub
parent 4609b6a3e7
commit 082598a64d
4 changed files with 70 additions and 0 deletions

View File

@@ -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>]>;
}

View File

@@ -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());

View File

@@ -3109,6 +3109,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

View File

@@ -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))