Skip to content

Commit

Permalink
Add SPV_INTEL_bindless_images preview extension (KhronosGroup#2535)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrSidims committed Apr 25, 2024
1 parent 5f60e6d commit ba5891f
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 2 deletions.
1 change: 1 addition & 0 deletions include/LLVMSPIRVExtensions.inc
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ EXT(SPV_EXT_relaxed_printf_string_address_space)
EXT(SPV_INTEL_fp_max_error)
EXT(SPV_INTEL_cache_controls)
EXT(SPV_INTEL_maximum_registers)
EXT(SPV_INTEL_bindless_images)
2 changes: 2 additions & 0 deletions lib/SPIRV/SPIRVInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ const static char Float[] = "float";
const static char Half[] = "half";
const static char Int[] = "int";
const static char UInt[] = "uint";
const static char Long[] = "long";
const static char ULong[] = "ulong";
const static char Void[] = "void";
} // namespace kSPIRVImageSampledTypeName

Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3327,6 +3327,7 @@ Instruction *SPIRVToLLVM::transSPIRVBuiltinFromInst(SPIRVInstruction *BI,
case internal::OpJointMatrixLoadINTEL:
case OpCooperativeMatrixLoadKHR:
case internal::OpCooperativeMatrixLoadCheckedINTEL:
case internal::OpConvertHandleToImageINTEL:
AddRetTypePostfix = true;
break;
default: {
Expand Down
14 changes: 13 additions & 1 deletion lib/SPIRV/SPIRVUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,11 @@ std::string getSPIRVImageSampledTypeName(SPIRVType *Ty) {
else
return kSPIRVImageSampledTypeName::UInt;
}
if (Ty->getIntegerBitWidth() == 64) {
if (static_cast<SPIRVTypeInt *>(Ty)->isSigned())
return kSPIRVImageSampledTypeName::Long;
return kSPIRVImageSampledTypeName::ULong;
}
break;
case OpTypeFloat:
switch (Ty->getFloatBitWidth()) {
Expand Down Expand Up @@ -1482,6 +1487,9 @@ Type *getLLVMTypeForSPIRVImageSampledTypePostfix(StringRef Postfix,
if (Postfix == kSPIRVImageSampledTypeName::Int ||
Postfix == kSPIRVImageSampledTypeName::UInt)
return Type::getInt32Ty(Ctx);
if (Postfix == kSPIRVImageSampledTypeName::Long ||
Postfix == kSPIRVImageSampledTypeName::ULong)
return Type::getInt64Ty(Ctx);
llvm_unreachable("Invalid sampled type postfix");
return nullptr;
}
Expand Down Expand Up @@ -2172,7 +2180,7 @@ class SPIRVFriendlyIRMangleInfo : public BuiltinFuncMangleInfo {

void init(StringRef UniqUnmangledName) override {
UnmangledName = UniqUnmangledName.str();
switch (OC) {
switch (static_cast<unsigned>(OC)) {
case OpConvertUToF:
case OpUConvert:
case OpSatConvertUToS:
Expand Down Expand Up @@ -2337,6 +2345,10 @@ class SPIRVFriendlyIRMangleInfo : public BuiltinFuncMangleInfo {
}
break;
}
case internal::OpConvertHandleToImageINTEL:
case internal::OpConvertHandleToSamplerINTEL:
addUnsignedArg(0);
break;
default:;
// No special handling is needed
}
Expand Down
61 changes: 61 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3804,5 +3804,66 @@ template <Op OC> class SPIRVReadClockKHRInstBase : public SPIRVUnaryInst<OC> {
_SPIRV_OP(ReadClockKHR)
#undef _SPIRV_OP

template <Op OC> class SPIRVBindlessImagesInstBase : public SPIRVUnaryInst<OC> {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityBindlessImagesINTEL);
}

llvm::Optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_bindless_images;
}

void validate() const override {
SPIRVUnary::validate();

// validate is a const method, whilst getOperand is non-const method
// because it may call a method of class Module that may modify LiteralMap
// of Module field. That modification is not impacting validate method for
// these instructions, so const_cast is safe here.
using SPVBindlessImagesInst = SPIRVBindlessImagesInstBase<OC>;
SPIRVValue *Input =
const_cast<SPVBindlessImagesInst *>(this)->getOperand(0);
SPIRVType *InCompTy = Input->getType();

auto StringAddrMod = [](SPIRVAddressingModelKind Kind) -> std::string {
if (Kind == AddressingModelPhysical32)
return std::string("Physical32");
if (Kind == AddressingModelPhysical64)
return std::string("Physical64");
return std::string("AddressingModel: ") + std::to_string(Kind);
};

auto InstName = OpCodeNameMap::map(OC);
auto AddrMod = this->getModule()->getAddressingModel();
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
SPVErrLog.checkError(
(InCompTy->isTypeInt(32) && AddrMod == AddressingModelPhysical32) ||
(InCompTy->isTypeInt(64) && AddrMod == AddressingModelPhysical64),
SPIRVEC_InvalidInstruction,
InstName +
"\nParameter value must be a 32-bit scalar in case of "
"Physical32 addressing model or a 64-bit scalar in case of "
"Physical64 addressing model\n"
"Type size: " +
std::to_string(InCompTy->getBitWidth()) +
"\nAddressing model: " + StringAddrMod(AddrMod) + "\n");

SPIRVType *ResTy = this->getType();
SPVErrLog.checkError(
(ResTy->isTypeImage() && OC == internal::OpConvertHandleToImageINTEL) ||
(ResTy->isTypeSampler() &&
OC == internal::OpConvertHandleToSamplerINTEL),
SPIRVEC_InvalidInstruction,
InstName + "\nIncorrect return type of the instruction must be "
"image/sampler\n");
}
};
#define _SPIRV_OP(x) \
typedef SPIRVBindlessImagesInstBase<internal::Op##x> SPIRV##x;
_SPIRV_OP(ConvertHandleToImageINTEL)
_SPIRV_OP(ConvertHandleToSamplerINTEL)
#undef _SPIRV_OP

} // namespace SPIRV
#endif // SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H
1 change: 1 addition & 0 deletions lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
add(internal::CapabilityRegisterLimitsINTEL, "RegisterLimitsINTEL");
add(internal::CapabilityCooperativeMatrixCheckedInstructionsINTEL,
"CooperativeMatrixCheckedInstructionsINTEL");
add(internal::CapabilityBindlessImagesINTEL, "BindlessImagesINTEL");
}
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)

Expand Down
4 changes: 4 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVOpCodeEnumInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ _SPIRV_OP_INTERNAL(ComplexFDivINTEL, internal::ComplexFDivINTEL)
_SPIRV_OP_INTERNAL(MaskedGatherINTEL, internal::OpMaskedGatherINTEL)
_SPIRV_OP_INTERNAL(MaskedScatterINTEL, internal::OpMaskedScatterINTEL)
_SPIRV_OP_INTERNAL(RoundFToTF32INTEL, internal::RoundFToTF32INTEL)
_SPIRV_OP_INTERNAL(ConvertHandleToImageINTEL,
internal::ConvertHandleToImageINTEL)
_SPIRV_OP_INTERNAL(ConvertHandleToSamplerINTEL,
internal::ConvertHandleToSamplerINTEL)
9 changes: 8 additions & 1 deletion lib/SPIRV/libSPIRV/spirv_internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ enum InternalOp {
IOpMaskedScatterINTEL = 6429,
IOpJointMatrixGetElementCoordINTEL = 6440,
IOpCooperativeMatrixPrefetchINTEL = 6449,
IOpConvertHandleToImageINTEL = 6529,
IOpConvertHandleToSamplerINTEL = 6530,
IOpPrev = OpMax - 2,
IOpForward
};
Expand Down Expand Up @@ -115,7 +117,8 @@ enum InternalCapability {
ICapabilityMaskedGatherScatterINTEL = 6427,
ICapabilityJointMatrixWIInstructionsINTEL = 6435,
ICapabilityCacheControlsINTEL = 6441,
ICapRegisterLimitsINTEL = 6460
ICapRegisterLimitsINTEL = 6460,
ICapabilityBindlessImagesINTEL = 6528
};

enum InternalFunctionControlMask { IFunctionControlOptNoneINTELMask = 0x10000 };
Expand Down Expand Up @@ -206,6 +209,10 @@ _SPIRV_OP(Capability, TensorFloat32RoundingINTEL)
_SPIRV_OP(Op, RoundFToTF32INTEL)

_SPIRV_OP(Capability, CacheControlsINTEL)

_SPIRV_OP(Capability, BindlessImagesINTEL)
_SPIRV_OP(Op, ConvertHandleToImageINTEL)
_SPIRV_OP(Op, ConvertHandleToSamplerINTEL)
#undef _SPIRV_OP

constexpr SourceLanguage SourceLanguagePython =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv %t.bc -o %t.spv --spirv-ext=+SPV_INTEL_bindless_images
; RUN: llvm-spirv %t.spv -o %t.spt --to-text
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
; RUN: llvm-spirv %t.spv -o %t.rev.bc -r --spirv-target-env=SPV-IR
; RUN: llvm-dis %t.rev.bc -o %t.rev.ll
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM

; RUN: not llvm-spirv %t.bc 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
; CHECK-ERROR: RequiresExtension: Feature requires the following SPIR-V extension:
; CHECK-ERROR-NEXT: SPV_INTEL_bindless_images

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
target triple = "spir64-unknown-unknown"

; CHECK-SPIRV: Capability BindlessImagesINTEL
; CHECK-SPIRV: Extension "SPV_INTEL_bindless_images"
; CHECK-SPIRV-DAG: TypeVoid [[#VoidTy:]]
; CHECK-SPIRV-DAG: TypeInt [[#Int64Ty:]] 64
; CHECK-SPIRV-DAG: Constant [[#Int64Ty]] [[#Const42:]] 42 0
; CHECK-SPIRV-DAG: TypeImage [[#IntImgTy:]] [[#Int64Ty]]
; CHECK-SPIRV-DAG: TypeSampler [[#SamplerTy:]]
; CHECK-SPIRV: FunctionParameter [[#Int64Ty]] [[#Input:]]
; CHECK-SPIRV: ConvertHandleToImageINTEL [[#IntImgTy]] [[#]] [[#Input]]
; CHECK-SPIRV: ConvertHandleToSamplerINTEL [[#SamplerTy]] [[#]] [[#Const42]]

; CHECK-LLVM: call spir_func %spirv.Image._ulong_2_0_0_0_0_0_0 addrspace(1)* @_Z77__spirv_ConvertHandleToImageINTEL_RPU3AS134__spirv_Image__ulong_2_0_0_0_0_0_0m(i64 %{{.*}})
; CHECK-LLVM: call spir_func %spirv.Sampler addrspace(2)* @_Z35__spirv_ConvertHandleToSamplerINTELm(i64 42)

%spirv.Image._long_2_0_0_0_0_0_0 = type opaque
%spirv.Sampler = type opaque

define spir_func void @foo(i64 %in) {
%img = call spir_func %spirv.Image._long_2_0_0_0_0_0_0 addrspace(1)* @_Z33__spirv_ConvertHandleToImageINTELl(i64 %in)
%samp = call spir_func %spirv.Sampler addrspace(2)* @_Z35__spirv_ConvertHandleToSamplerINTELl(i64 42)
ret void
}

declare spir_func %spirv.Image._long_2_0_0_0_0_0_0 addrspace(1)* @_Z33__spirv_ConvertHandleToImageINTELl(i64)

declare spir_func %spirv.Sampler addrspace(2)* @_Z35__spirv_ConvertHandleToSamplerINTELl(i64)

!opencl.spir.version = !{!0}
!spirv.Source = !{!1}
!llvm.ident = !{!2}

!0 = !{i32 1, i32 2}
!1 = !{i32 4, i32 100000}
!2 = !{!"clang version 17.0.0"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
; RUN: llvm-as %s -o %t.bc
; RUN: not llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_bindless_images 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR-1
; CHECK-ERROR-1: InvalidInstruction: Can't translate llvm instruction:
; CHECK-ERROR-1-NEXT: ConvertHandleToImageINTEL
; CHECK-ERROR-1-NEXT: Parameter value must be a 32-bit scalar in case of Physical32 addressing model or a 64-bit scalar in case of Physical64 addressing model
; CHECK-ERROR-1-NEXT: Type size: 32
; CHECK-ERROR-1-NEXT: Addressing model: Physical64

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
target triple = "spir64-unknown-unknown"

%spirv.Image._long_2_0_0_0_0_0_0 = type opaque
%spirv.Sampler = type opaque

define spir_func void @foo(i32 %in) {
%img = call spir_func %spirv.Image._long_2_0_0_0_0_0_0 addrspace(1)* @_Z33__spirv_ConvertHandleToImageINTELi(i32 %in)
%samp = call spir_func %spirv.Sampler addrspace(1)* @_Z35__spirv_ConvertHandleToSamplerINTELl(i64 42)
ret void
}

declare spir_func %spirv.Image._long_2_0_0_0_0_0_0 addrspace(1)* @_Z33__spirv_ConvertHandleToImageINTELi(i32)

declare spir_func %spirv.Sampler addrspace(1)* @_Z35__spirv_ConvertHandleToSamplerINTELl(i64)

!opencl.spir.version = !{!0}
!spirv.Source = !{!1}
!llvm.ident = !{!2}

!0 = !{i32 1, i32 2}
!1 = !{i32 4, i32 100000}
!2 = !{!"clang version 17.0.0"}

0 comments on commit ba5891f

Please sign in to comment.