From 0d663f294e74411a536342e900c3003d77d59363 Mon Sep 17 00:00:00 2001 From: Viktoria Maximova Date: Thu, 5 Sep 2024 18:01:13 +0200 Subject: [PATCH] SPV_KHR_untyped_pointers - implement OpTypeUntypedPointerKHR (#2687) This is the first part of the extension implementation. Introducing untyped pointer type. Spec: https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_untyped_pointers.html Original commit: https://github.com/KhronosGroup/SPIRV-LLVM-Translator/commit/7dacb7cdedc9c01 --- llvm-spirv/include/LLVMSPIRVExtensions.inc | 1 + llvm-spirv/lib/SPIRV/SPIRVReader.cpp | 7 ++ llvm-spirv/lib/SPIRV/SPIRVWriter.cpp | 56 +++++++++---- .../lib/SPIRV/libSPIRV/SPIRVInstruction.h | 34 ++++++-- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp | 28 +++++-- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h | 6 +- .../lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h | 1 + llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCode.h | 3 +- .../lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h | 4 +- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.cpp | 16 +++- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h | 68 ++++++++++++--- llvm-spirv/spirv-headers-tag.conf | 2 +- .../test/GroupAndSubgroupInstructions.spvasm | 4 +- .../FPGALoopMergeInst.ll | 2 +- .../SPV_KHR_untyped_pointers/read_image.ll | 84 +++++++++++++++++++ .../KHR/SPV_KHR_untyped_pointers/store.ll | 59 +++++++++++++ .../untyped_ptr_type.ll | 43 ++++++++++ llvm-spirv/test/spirv-extensions-control.ll | 4 +- .../test/transcoding/spirv-target-types.ll | 5 ++ 19 files changed, 372 insertions(+), 55 deletions(-) create mode 100644 llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/read_image.ll create mode 100644 llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/store.ll create mode 100644 llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_ptr_type.ll diff --git a/llvm-spirv/include/LLVMSPIRVExtensions.inc b/llvm-spirv/include/LLVMSPIRVExtensions.inc index 2c06e1178eb0a..9b31bdbefe0bf 100644 --- a/llvm-spirv/include/LLVMSPIRVExtensions.inc +++ b/llvm-spirv/include/LLVMSPIRVExtensions.inc @@ -17,6 +17,7 @@ EXT(SPV_KHR_subgroup_rotate) EXT(SPV_KHR_non_semantic_info) EXT(SPV_KHR_shader_clock) EXT(SPV_KHR_cooperative_matrix) +EXT(SPV_KHR_untyped_pointers) EXT(SPV_INTEL_subgroups) EXT(SPV_INTEL_media_block_io) EXT(SPV_INTEL_device_side_avc_motion_estimation) diff --git a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp index 2bf15ff711a13..9d2ae1cef17bf 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp @@ -357,6 +357,11 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool UseTPT) { return TypedPointerType::get(ElementTy, AS); return mapType(T, PointerType::get(ElementTy, AS)); } + case OpTypeUntypedPointerKHR: { + const unsigned AS = + SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass()); + return mapType(T, PointerType::get(*Context, AS)); + } case OpTypeVector: return mapType(T, FixedVectorType::get(transType(T->getVectorComponentType()), @@ -560,6 +565,8 @@ std::string SPIRVToLLVM::transTypeToOCLTypeName(SPIRVType *T, bool IsSigned) { } return transTypeToOCLTypeName(ET) + "*"; } + case OpTypeUntypedPointerKHR: + return "int*"; case OpTypeVector: return transTypeToOCLTypeName(T->getVectorComponentType()) + T->getVectorComponentCount(); diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index 8dba81c03b56d..26eb61f71aa94 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -417,8 +417,8 @@ SPIRVType *LLVMToSPIRVBase::transType(Type *T) { // A pointer to image or pipe type in LLVM is translated to a SPIRV // (non-pointer) image or pipe type. if (T->isPointerTy()) { - auto *ET = Type::getInt8Ty(T->getContext()); auto AddrSpc = T->getPointerAddressSpace(); + auto *ET = Type::getInt8Ty(T->getContext()); return transPointerType(ET, AddrSpc); } @@ -720,7 +720,6 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(Type *ET, unsigned AddrSpc) { transType(ET))); } } else { - SPIRVType *ElementType = transType(ET); // ET, as a recursive type, may contain exactly the same pointer T, so it // may happen that after translation of ET we already have translated T, // added the translated pointer to the SPIR-V module and mapped T to this @@ -729,7 +728,17 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(Type *ET, unsigned AddrSpc) { if (Loc != PointeeTypeMap.end()) { return Loc->second; } - SPIRVType *TranslatedTy = transPointerType(ElementType, AddrSpc); + + SPIRVType *ElementType = nullptr; + SPIRVType *TranslatedTy = nullptr; + if (ET->isPointerTy() && + BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers)) { + TranslatedTy = BM->addUntypedPointerKHRType( + SPIRSPIRVAddrSpaceMap::map(static_cast(AddrSpc))); + } else { + ElementType = transType(ET); + TranslatedTy = transPointerType(ElementType, AddrSpc); + } PointeeTypeMap[TypeKey] = TranslatedTy; return TranslatedTy; } @@ -744,8 +753,16 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(SPIRVType *ET, unsigned AddrSpc) { if (Loc != PointeeTypeMap.end()) return Loc->second; - SPIRVType *TranslatedTy = BM->addPointerType( - SPIRSPIRVAddrSpaceMap::map(static_cast(AddrSpc)), ET); + SPIRVType *TranslatedTy = nullptr; + if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers) && + !(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeImage() || + ET->isTypeSampler() || ET->isTypePipe())) { + TranslatedTy = BM->addUntypedPointerKHRType( + SPIRSPIRVAddrSpaceMap::map(static_cast(AddrSpc))); + } else { + TranslatedTy = BM->addPointerType( + SPIRSPIRVAddrSpaceMap::map(static_cast(AddrSpc)), ET); + } PointeeTypeMap[TypeKey] = TranslatedTy; return TranslatedTy; } @@ -2187,8 +2204,13 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, MemoryAccessNoAliasINTELMaskMask); if (MemoryAccess.front() == 0) MemoryAccess.clear(); - return mapValue(V, BM->addLoadInst(transValue(LD->getPointerOperand(), BB), - MemoryAccess, BB)); + return mapValue( + V, + BM->addLoadInst( + transValue(LD->getPointerOperand(), BB), MemoryAccess, BB, + BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers) + ? transType(LD->getType()) + : nullptr)); } if (BinaryOperator *B = dyn_cast(V)) { @@ -2398,14 +2420,17 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, if (auto *Phi = dyn_cast(V)) { std::vector IncomingPairs; + SPIRVType *Ty = transScavengedType(Phi); for (size_t I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) { - IncomingPairs.push_back(transValue(Phi->getIncomingValue(I), BB, true, - FuncTransMode::Pointer)); + SPIRVValue *Val = transValue(Phi->getIncomingValue(I), BB, true, + FuncTransMode::Pointer); + if (Val->getType() != Ty) + Val = BM->addUnaryInst(OpBitcast, Ty, Val, BB); + IncomingPairs.push_back(Val); IncomingPairs.push_back(transValue(Phi->getIncomingBlock(I), nullptr)); } - return mapValue(V, - BM->addPhiInst(transScavengedType(Phi), IncomingPairs, BB)); + return mapValue(V, BM->addPhiInst(Ty, IncomingPairs, BB)); } if (auto *Ext = dyn_cast(V)) { @@ -6659,9 +6684,12 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI, assert((Pointee == Args[I] || !isa(Pointee)) && "Illegal use of a function pointer type"); } - SPArgs.push_back(SPI->isOperandLiteral(I) - ? cast(Args[I])->getZExtValue() - : transValue(Args[I], BB)->getId()); + if (!SPI->isOperandLiteral(I)) { + SPIRVValue *Val = transValue(Args[I], BB); + SPArgs.push_back(Val->getId()); + } else { + SPArgs.push_back(cast(Args[I])->getZExtValue()); + } } BM->addInstTemplate(SPI, SPArgs, BB, SPRetTy); if (!SPRetTy || !SPRetTy->isTypeStruct()) diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h index c243403eb020b..7cfdade58b6b0 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -568,9 +568,15 @@ class SPIRVStore : public SPIRVInstruction, public SPIRVMemoryAccess { SPIRVInstruction::validate(); if (getSrc()->isForward() || getDst()->isForward()) return; - assert(getValueType(PtrId)->getPointerElementType() == - getValueType(ValId) && - "Inconsistent operand types"); + assert( + (getValueType(PtrId) + ->getPointerElementType() + ->isTypeUntypedPointerKHR() || + // TODO: This check should be removed once we support untyped + // variables. + getValueType(ValId)->isTypeUntypedPointerKHR() || + getValueType(PtrId)->getPointerElementType() == getValueType(ValId)) && + "Inconsistent operand types"); } private: @@ -585,11 +591,12 @@ class SPIRVLoad : public SPIRVInstruction, public SPIRVMemoryAccess { // Complete constructor SPIRVLoad(SPIRVId TheId, SPIRVId PointerId, const std::vector &TheMemoryAccess, - SPIRVBasicBlock *TheBB) + SPIRVBasicBlock *TheBB, SPIRVType *TheType = nullptr) : SPIRVInstruction( FixedWords + TheMemoryAccess.size(), OpLoad, - TheBB->getValueType(PointerId)->getPointerElementType(), TheId, - TheBB), + TheType ? TheType + : TheBB->getValueType(PointerId)->getPointerElementType(), + TheId, TheBB), SPIRVMemoryAccess(TheMemoryAccess), PtrId(PointerId), MemoryAccess(TheMemoryAccess) { validate(); @@ -619,6 +626,12 @@ class SPIRVLoad : public SPIRVInstruction, public SPIRVMemoryAccess { void validate() const override { SPIRVInstruction::validate(); assert((getValue(PtrId)->isForward() || + getValueType(PtrId) + ->getPointerElementType() + ->isTypeUntypedPointerKHR() || + // TODO: This check should be removed once we support untyped + // variables. + Type->isTypeUntypedPointerKHR() || Type == getValueType(PtrId)->getPointerElementType()) && "Inconsistent types"); } @@ -2001,7 +2014,8 @@ class SPIRVCompositeExtractBase : public SPIRVInstTemplateBase { (void)Composite; assert(getValueType(Composite)->isTypeArray() || getValueType(Composite)->isTypeStruct() || - getValueType(Composite)->isTypeVector()); + getValueType(Composite)->isTypeVector() || + getValueType(Composite)->isTypeUntypedPointerKHR()); } }; @@ -2027,7 +2041,8 @@ class SPIRVCompositeInsertBase : public SPIRVInstTemplateBase { (void)Composite; assert(getValueType(Composite)->isTypeArray() || getValueType(Composite)->isTypeStruct() || - getValueType(Composite)->isTypeVector()); + getValueType(Composite)->isTypeVector() || + getValueType(Composite)->isTypeUntypedPointerKHR()); assert(Type == getValueType(Composite)); } }; @@ -2374,7 +2389,8 @@ template class SPIRVLifetime : public SPIRVInstruction { // Signedness of 1, its sign bit cannot be set. if (!(ObjType->getPointerElementType()->isTypeVoid() || // (void *) is i8* in LLVM IR - ObjType->getPointerElementType()->isTypeInt(8)) || + ObjType->getPointerElementType()->isTypeInt(8) || + ObjType->getPointerElementType()->isTypeUntypedPointerKHR()) || !Module->hasCapability(CapabilityAddresses)) assert(Size == 0 && "Size must be 0"); } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp index c904eb834493c..0e5fd8553c69c 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -252,6 +252,8 @@ class SPIRVModuleImpl : public SPIRVModule { SPIRVTypeInt *addIntegerType(unsigned BitWidth) override; SPIRVTypeOpaque *addOpaqueType(const std::string &) override; SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *) override; + SPIRVTypeUntypedPointerKHR * + addUntypedPointerKHRType(SPIRVStorageClassKind) override; SPIRVTypeImage *addImageType(SPIRVType *, const SPIRVTypeImageDescriptor &) override; SPIRVTypeImage *addImageType(SPIRVType *, const SPIRVTypeImageDescriptor &, @@ -353,7 +355,7 @@ class SPIRVModuleImpl : public SPIRVModule { SPIRVInstruction *addCmpInst(Op, SPIRVType *, SPIRVValue *, SPIRVValue *, SPIRVBasicBlock *) override; SPIRVInstruction *addLoadInst(SPIRVValue *, const std::vector &, - SPIRVBasicBlock *) override; + SPIRVBasicBlock *, SPIRVType *) override; SPIRVInstruction *addPhiInst(SPIRVType *, std::vector, SPIRVBasicBlock *) override; SPIRVInstruction *addCompositeConstructInst(SPIRVType *, @@ -563,6 +565,8 @@ class SPIRVModuleImpl : public SPIRVModule { SPIRVUnknownStructFieldMap UnknownStructFieldMap; SPIRVTypeBool *BoolTy; SPIRVTypeVoid *VoidTy; + SmallDenseMap + UntypedPtrTyMap; SmallDenseMap IntTypeMap; SmallDenseMap FloatTypeMap; SmallDenseMap, SPIRVTypePointer *, 4> @@ -1014,6 +1018,17 @@ SPIRVModuleImpl::addPointerType(SPIRVStorageClassKind StorageClass, return addType(Ty); } +SPIRVTypeUntypedPointerKHR * +SPIRVModuleImpl::addUntypedPointerKHRType(SPIRVStorageClassKind StorageClass) { + auto Loc = UntypedPtrTyMap.find(StorageClass); + if (Loc != UntypedPtrTyMap.end()) + return Loc->second; + + auto *Ty = new SPIRVTypeUntypedPointerKHR(this, getId(), StorageClass); + UntypedPtrTyMap[StorageClass] = Ty; + return addType(Ty); +} + SPIRVTypeFunction *SPIRVModuleImpl::addFunctionType( SPIRVType *ReturnType, const std::vector &ParameterTypes) { return addType( @@ -1430,9 +1445,10 @@ SPIRVModuleImpl::addInstruction(SPIRVInstruction *Inst, SPIRVBasicBlock *BB, SPIRVInstruction * SPIRVModuleImpl::addLoadInst(SPIRVValue *Source, const std::vector &TheMemoryAccess, - SPIRVBasicBlock *BB) { + SPIRVBasicBlock *BB, SPIRVType *TheType) { return addInstruction( - new SPIRVLoad(getId(), Source->getId(), TheMemoryAccess, BB), BB); + new SPIRVLoad(getId(), Source->getId(), TheMemoryAccess, BB, TheType), + BB); } SPIRVInstruction * @@ -1925,11 +1941,13 @@ class TopologicalSort { // We've found a recursive data type, e.g. a structure having a member // which is a pointer to the same structure. State = Unvisited; // Forget about it - if (E->getOpCode() == OpTypePointer) { + if (E->getOpCode() == OpTypePointer || + E->getOpCode() == OpTypeUntypedPointerKHR) { // If we have a pointer in the recursive chain, we can break the // cyclic dependency by inserting a forward declaration of that // pointer. - SPIRVTypePointer *Ptr = static_cast(E); + SPIRVTypePointerBase<> *Ptr = + static_cast *>(E); SPIRVModule *BM = E->getModule(); ForwardPointerSet.insert(BM->add(new SPIRVTypeForwardPointer( BM, Ptr->getId(), Ptr->getPointerStorageClass()))); diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h index d2879fbcc4c50..7e77ef80e49d0 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -71,6 +71,7 @@ class SPIRVTypeFunction; class SPIRVTypeInt; class SPIRVTypeOpaque; class SPIRVTypePointer; +class SPIRVTypeUntypedPointerKHR; class SPIRVTypeImage; class SPIRVTypeSampler; class SPIRVTypeSampledImage; @@ -257,6 +258,8 @@ class SPIRVModule { virtual SPIRVTypeOpaque *addOpaqueType(const std::string &) = 0; virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *) = 0; + virtual SPIRVTypeUntypedPointerKHR * + addUntypedPointerKHRType(SPIRVStorageClassKind) = 0; virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &) = 0; virtual SPIRVEntry *addTypeStructContinuedINTEL(unsigned NumMembers) = 0; virtual void closeStructType(SPIRVTypeStruct *, bool) = 0; @@ -396,7 +399,8 @@ class SPIRVModule { SPIRVBasicBlock *BB, SPIRVType *Ty) = 0; virtual SPIRVInstruction *addLoadInst(SPIRVValue *, const std::vector &, - SPIRVBasicBlock *) = 0; + SPIRVBasicBlock *, + SPIRVType *TheType = nullptr) = 0; virtual SPIRVInstruction *addLifetimeInst(Op OC, SPIRVValue *Object, SPIRVWord Size, SPIRVBasicBlock *BB) = 0; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index aca7f3280692a..763527bc0c956 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -478,6 +478,7 @@ template <> inline void SPIRVMap::init() { add(CapabilityRoundingModeRTZ, "RoundingModeRTZ"); add(CapabilityRayQueryProvisionalKHR, "RayQueryProvisionalKHR"); add(CapabilityRayQueryKHR, "RayQueryKHR"); + add(CapabilityUntypedPointersKHR, "UntypedPointersKHR"); add(CapabilityRayTraversalPrimitiveCullingKHR, "RayTraversalPrimitiveCullingKHR"); add(CapabilityRayTracingKHR, "RayTracingKHR"); diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCode.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCode.h index 3a7cbad1b1cf5..cfb0c8833019e 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCode.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCode.h @@ -227,7 +227,8 @@ inline bool isTypeOpCode(Op OpCode) { OC == internal::OpTypeJointMatrixINTEL || OC == internal::OpTypeJointMatrixINTELv2 || OC == OpTypeCooperativeMatrixKHR || - OC == internal::OpTypeTaskSequenceINTEL; + OC == internal::OpTypeTaskSequenceINTEL || + OC == OpTypeUntypedPointerKHR; } inline bool isSpecConstantOpCode(Op OpCode) { diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h index 0eb00e1c1df56..b5e04b5e452d3 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h @@ -333,9 +333,7 @@ _SPIRV_OP(PtrEqual, 401) _SPIRV_OP(PtrNotEqual, 402) _SPIRV_OP(PtrDiff, 403) _SPIRV_OP(CopyLogical, 400) -_SPIRV_OP(PtrEqual, 401) -_SPIRV_OP(PtrNotEqual, 402) -_SPIRV_OP(PtrDiff, 403) +_SPIRV_OP(TypeUntypedPointerKHR, 4417) _SPIRV_OP(GroupNonUniformRotateKHR, 4431) _SPIRV_OP(SDotKHR, 4450) _SPIRV_OP(UDotKHR, 4451) diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.cpp index 24e9ac3a317a8..84b6cd6a9e55f 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.cpp @@ -86,12 +86,16 @@ SPIRVType *SPIRVType::getFunctionReturnType() const { } SPIRVType *SPIRVType::getPointerElementType() const { - assert(OpCode == OpTypePointer && "Not a pointer type"); + assert((OpCode == OpTypePointer || OpCode == OpTypeUntypedPointerKHR) && + "Not a pointer type"); + if (OpCode == OpTypeUntypedPointerKHR) + return const_cast(this); return static_cast(this)->getElementType(); } SPIRVStorageClassKind SPIRVType::getPointerStorageClass() const { - assert(OpCode == OpTypePointer && "Not a pointer type"); + assert((OpCode == OpTypePointer || OpCode == OpTypeUntypedPointerKHR) && + "Not a pointer type"); return static_cast(this)->getStorageClass(); } @@ -183,7 +187,13 @@ bool SPIRVType::isTypeInt(unsigned Bits) const { return isType(this, Bits); } -bool SPIRVType::isTypePointer() const { return OpCode == OpTypePointer; } +bool SPIRVType::isTypePointer() const { + return OpCode == OpTypePointer || OpCode == OpTypeUntypedPointerKHR; +} + +bool SPIRVType::isTypeUntypedPointerKHR() const { + return OpCode == OpTypeUntypedPointerKHR; +} bool SPIRVType::isTypeOpaque() const { return OpCode == OpTypeOpaque; } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h index e53a287dd5bc5..a586a997a7941 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h @@ -92,6 +92,7 @@ class SPIRVType : public SPIRVEntry { bool isTypeInt(unsigned Bits = 0) const; bool isTypeOpaque() const; bool isTypePointer() const; + bool isTypeUntypedPointerKHR() const; bool isTypeSampler() const; bool isTypeSampledImage() const; bool isTypeStruct() const; @@ -233,25 +234,47 @@ class SPIRVTypeFloat : public SPIRVType { unsigned BitWidth; // Bit width }; -class SPIRVTypePointer : public SPIRVType { +template +class SPIRVTypePointerBase : public SPIRVType { +public: + // Complete constructor + SPIRVTypePointerBase(SPIRVModule *M, SPIRVId TheId, + SPIRVStorageClassKind TheStorageClass) + : SPIRVType(M, WC, TheOpCode, TheId), ElemStorageClass(TheStorageClass) { + validate(); + } + // Incomplete constructor + SPIRVTypePointerBase() + : SPIRVType(TheOpCode), ElemStorageClass(StorageClassFunction) {} + + SPIRVStorageClassKind getStorageClass() const { return ElemStorageClass; } + +protected: + _SPIRV_DEF_ENCDEC2(Id, ElemStorageClass) + void validate() const override { + SPIRVEntry::validate(); + assert(isValid(ElemStorageClass)); + } + + SPIRVStorageClassKind ElemStorageClass; // Storage Class +}; + +class SPIRVTypePointer : public SPIRVTypePointerBase { public: // Complete constructor SPIRVTypePointer(SPIRVModule *M, SPIRVId TheId, SPIRVStorageClassKind TheStorageClass, SPIRVType *ElementType) - : SPIRVType(M, 4, OpTypePointer, TheId), - ElemStorageClass(TheStorageClass), ElemTypeId(ElementType->getId()) { + : SPIRVTypePointerBase(M, TheId, TheStorageClass), + ElemTypeId(ElementType->getId()) { validate(); } // Incomplete constructor - SPIRVTypePointer() - : SPIRVType(OpTypePointer), ElemStorageClass(StorageClassFunction), - ElemTypeId(0) {} + SPIRVTypePointer() : SPIRVTypePointerBase(), ElemTypeId(0) {} SPIRVType *getElementType() const { return static_cast(getEntry(ElemTypeId)); } - SPIRVStorageClassKind getStorageClass() const { return ElemStorageClass; } SPIRVCapVec getRequiredCapability() const override { auto Cap = getVec(CapabilityAddresses); if (getElementType()->isTypeFloat(16)) @@ -266,16 +289,35 @@ class SPIRVTypePointer : public SPIRVType { protected: _SPIRV_DEF_ENCDEC3(Id, ElemStorageClass, ElemTypeId) - void validate() const override { - SPIRVEntry::validate(); - assert(isValid(ElemStorageClass)); - } - private: - SPIRVStorageClassKind ElemStorageClass; // Storage Class SPIRVId ElemTypeId; }; +class SPIRVTypeUntypedPointerKHR + : public SPIRVTypePointerBase { +public: + // Complete constructor + SPIRVTypeUntypedPointerKHR(SPIRVModule *M, SPIRVId TheId, + SPIRVStorageClassKind TheStorageClass) + : SPIRVTypePointerBase(M, TheId, TheStorageClass) { + validate(); + } + // Incomplete constructor + SPIRVTypeUntypedPointerKHR() : SPIRVTypePointerBase() {} + + SPIRVStorageClassKind getStorageClass() const { return ElemStorageClass; } + SPIRVCapVec getRequiredCapability() const override { + auto Cap = getVec(CapabilityUntypedPointersKHR, CapabilityAddresses); + auto C = getCapability(ElemStorageClass); + Cap.insert(Cap.end(), C.begin(), C.end()); + return Cap; + } + + std::optional getRequiredExtension() const override { + return ExtensionID::SPV_KHR_untyped_pointers; + } +}; + class SPIRVTypeForwardPointer : public SPIRVEntryNoId { public: SPIRVTypeForwardPointer(SPIRVModule *M, SPIRVId PointerId, diff --git a/llvm-spirv/spirv-headers-tag.conf b/llvm-spirv/spirv-headers-tag.conf index 3c34bf8933ad9..3140a223530b2 100644 --- a/llvm-spirv/spirv-headers-tag.conf +++ b/llvm-spirv/spirv-headers-tag.conf @@ -1 +1 @@ -b73e168ca5e123dcf3dea8a34b19a5130f421ae1 +db5a00f8cebe81146cafabf89019674a3c4bf03d diff --git a/llvm-spirv/test/GroupAndSubgroupInstructions.spvasm b/llvm-spirv/test/GroupAndSubgroupInstructions.spvasm index c6069afb97620..2ff5609a8004e 100644 --- a/llvm-spirv/test/GroupAndSubgroupInstructions.spvasm +++ b/llvm-spirv/test/GroupAndSubgroupInstructions.spvasm @@ -58,7 +58,7 @@ ; sub_group_rotate(c, x); ; } ; clang -cc1 -O2 -triple spir -cl-std=cl2.0 -finclude-default-header -cl-ext=+all source.cl -emit-llvm-bc -o tmp.bc -; llvm-spirv tmp.bc --spirv-ext=+all -o tmp.spv +; llvm-spirv tmp.bc --spirv-ext=+all,-SPV_KHR_untyped_pointers -o tmp.spv ; spirv-dis tmp.spv -o llvm-spirv/test/GroupAndSubgroupInstructions.spvasm ; REQUIRES: spirv-as @@ -76,7 +76,7 @@ ; RUN: llvm-dis %t.bc -o %t.ll ; RUN: FileCheck < %t.ll %s --check-prefixes=CHECK-COMMON,CHECK-SPV-IR -; RUN: llvm-spirv %t.bc --spirv-ext=+all -o %t.rev.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+all,-SPV_KHR_untyped_pointers -o %t.rev.spv ; RUN: spirv-val %t.rev.spv diff --git a/llvm-spirv/test/extensions/INTEL/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll b/llvm-spirv/test/extensions/INTEL/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll index 0520fe3d88182..60935b8ef5dab 100644 --- a/llvm-spirv/test/extensions/INTEL/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll +++ b/llvm-spirv/test/extensions/INTEL/SPV_INTEL_fpga_loop_controls/FPGALoopMergeInst.ll @@ -107,7 +107,7 @@ ; into a separate test file ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-ext=+all -o %t.spv +; RUN: llvm-spirv %t.bc -spirv-ext=+SPV_INTEL_fpga_loop_controls,+SPV_INTEL_unstructured_loop_controls -o %t.spv ; RUN: llvm-spirv %t.spv --to-text -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV diff --git a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/read_image.ll b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/read_image.ll new file mode 100644 index 0000000000000..45e4b9cb5664b --- /dev/null +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/read_image.ll @@ -0,0 +1,84 @@ +; Check that untyped pointers extension does not affect the translation of images. + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_untyped_pointers -spirv-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv --spirv-ext=+SPV_KHR_untyped_pointers %t.bc -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc --spirv-target-env=SPV-IR +; RUN: llvm-dis < %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o %t.rev.ll +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: TypeInt [[#IntTy:]] 32 +; CHECK-SPIRV: TypeImage [[#ImageTy:]] [[#]] 2 0 0 0 0 0 0 +; CHECK-SPIRV: TypeVector [[#IVecTy:]] [[#IntTy]] +; CHECK-SPIRV: TypeFloat [[#FloatTy:]] +; CHECK-SPIRV: TypeVector [[#FVecTy:]] [[#FloatTy]] + +; CHECK-SPIRV: Load [[#ImageTy]] [[#Image0:]] +; CHECK-SPIRV: Load [[#IVecTy]] [[#Coord0:]] +; CHECK-SPIRV: ImageRead [[#IVecTy]] [[#]] [[#Image0]] [[#Coord0]] 8192 + +; CHECK-SPIRV: Load [[#ImageTy]] [[#Image1:]] +; CHECK-SPIRV: Load [[#IVecTy]] [[#Coord1:]] +; CHECK-SPIRV: ImageRead [[#FVecTy]] [[#]] [[#Image1]] [[#Coord1]] + +; CHECK-LLVM: call spir_func <4 x i32> @_Z24__spirv_ImageRead_Ruint4PU3AS133__spirv_Image__void_2_0_0_0_0_0_0Dv4_ii(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) +; CHECK-LLVM: call spir_func <4 x float> @_Z25__spirv_ImageRead_Rfloat4PU3AS133__spirv_Image__void_2_0_0_0_0_0_0Dv4_i(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1" +target triple = "spir64" + +; Function Attrs: convergent noinline norecurse nounwind optnone +define dso_local spir_kernel void @kernelA(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) %input) #0 !kernel_arg_addr_space !3 !kernel_arg_access_qual !4 !kernel_arg_type !5 !kernel_arg_base_type !5 !kernel_arg_type_qual !6 { +entry: + %input.addr = alloca target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0), align 8 + %c = alloca <4 x i32>, align 16 + %.compoundliteral = alloca <4 x i32>, align 16 + store target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) %input, ptr %input.addr, align 8 + %0 = load target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0), ptr %input.addr, align 8 + store <4 x i32> zeroinitializer, ptr %.compoundliteral, align 16 + %1 = load <4 x i32>, ptr %.compoundliteral, align 16 + %call = call spir_func <4 x i32> @_Z12read_imageui14ocl_image3d_roDv4_i(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) %0, <4 x i32> noundef %1) #2 + store <4 x i32> %call, ptr %c, align 16 + ret void +} + +; Function Attrs: convergent nounwind willreturn memory(read) +declare spir_func <4 x i32> @_Z12read_imageui14ocl_image3d_roDv4_i(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0), <4 x i32> noundef) #1 + +; Function Attrs: convergent noinline norecurse nounwind optnone +define dso_local spir_kernel void @kernelB(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) %input) #0 !kernel_arg_addr_space !3 !kernel_arg_access_qual !4 !kernel_arg_type !5 !kernel_arg_base_type !5 !kernel_arg_type_qual !6 { +entry: + %input.addr = alloca target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0), align 8 + %f = alloca <4 x float>, align 16 + %.compoundliteral = alloca <4 x i32>, align 16 + store target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) %input, ptr %input.addr, align 8 + %0 = load target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0), ptr %input.addr, align 8 + store <4 x i32> zeroinitializer, ptr %.compoundliteral, align 16 + %1 = load <4 x i32>, ptr %.compoundliteral, align 16 + %call = call spir_func <4 x float> @_Z11read_imagef14ocl_image3d_roDv4_i(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0) %0, <4 x i32> noundef %1) #2 + store <4 x float> %call, ptr %f, align 16 + ret void +} + +; Function Attrs: convergent nounwind willreturn memory(read) +declare spir_func <4 x float> @_Z11read_imagef14ocl_image3d_roDv4_i(target("spirv.Image", void, 2, 0, 0, 0, 0, 0, 0), <4 x i32> noundef) #1 + +attributes #0 = { convergent noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "uniform-work-group-size"="false" } +attributes #1 = { convergent nounwind willreturn memory(read) "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { convergent nounwind willreturn memory(read) } + +!llvm.module.flags = !{!0} +!opencl.ocl.version = !{!1} +!opencl.spir.version = !{!1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 2, i32 0} +!2 = !{!"clang version 20.0.0git (https:;github.com/llvm/llvm-project.git 5313d2e6d02d2a8b192e2c007241ff261287e1ca)"} +!3 = !{i32 1} +!4 = !{!"read_only"} +!5 = !{!"image3d_t"} +!6 = !{!""} diff --git a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/store.ll b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/store.ll new file mode 100644 index 0000000000000..aa25898bf47ee --- /dev/null +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/store.ll @@ -0,0 +1,59 @@ +; This test checks translation of function parameter which is untyped pointer. +; Lately, when we do support untyped variables, this one could be used to check +; "full" forward and reverse translation of opaque pointers. + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_untyped_pointers -o %t.spv +; TODO: enable back once spirv-tools are updated and untyped variable is implemented. +; R/UN: spirv-val %t.spv + +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_untyped_pointers -spirv-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV + +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o %t.rev.ll +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: Capability UntypedPointersKHR +; CHECK-SPIRV: Extension "SPV_KHR_untyped_pointers" +; CHECK-SPIRV-DAG: TypeInt [[#IntTy:]] 32 0 +; CHECK-SPIRV-DAG: Constant [[#IntTy]] [[#Constant0:]] 0 +; CHECK-SPIRV-DAG: TypeUntypedPointerKHR [[#UntypedPtrTy:]] 5 +; CHECK-SPIRV-DAG: TypeUntypedPointerKHR [[#UntypedPtrTyFunc:]] 7 + +; CHECK-SPIRV: FunctionParameter [[#UntypedPtrTy]] [[#FuncParam:]] +; CHECK-SPIRV: Variable [[#UntypedPtrTyFunc]] [[#VarBId:]] 7 +; CHECK-SPIRV: Store [[#VarBId]] [[#FuncParam]] 2 4 +; CHECK-SPIRV: Load [[#UntypedPtrTy]] [[#LoadId:]] [[#VarBId]] 2 4 +; CHECK-SPIRV: Store [[#LoadId]] [[#Constant0]] 2 4 + +; CHECK-SPIRV: FunctionParameter [[#UntypedPtrTy]] [[#FuncParam0:]] +; CHECK-SPIRV: FunctionParameter [[#UntypedPtrTy]] [[#FuncParam1:]] +; CHECK-SPIRV: Load [[#IntTy]] [[#LoadId:]] [[#FuncParam1]] 2 4 +; CHECK-SPIRV: Store [[#FuncParam0]] [[#LoadId]] 2 4 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; CHECK-LLVM: define spir_func void @foo(ptr addrspace(1) %a) +; CHECK-LLVM: %b = alloca ptr, align 4 +; CHECK-LLVM: store ptr addrspace(1) %a, ptr %b, align 4 +; CHECK-LLVM: %0 = load ptr addrspace(1), ptr %b, align 4 +; CHECK-LLVM: store i32 0, ptr addrspace(1) %0, align 4 +define spir_func void @foo(ptr addrspace(1) %a) { +entry: + %b = alloca ptr addrspace(1), align 4 + store ptr addrspace(1) %a, ptr %b, align 4 + %0 = load ptr addrspace(1), ptr %b, align 4 + store i32 0, ptr addrspace(1) %0, align 4 + ret void +} + +; CHECK-LLVM: define spir_func void @boo(ptr addrspace(1) %0, ptr addrspace(1) %1) +; CHECK-LLVM: %3 = load i32, ptr addrspace(1) %1, align 4 +; CHECK-LLVM: store i32 %3, ptr addrspace(1) %0, align 4 +define dso_local void @boo(ptr addrspace(1) %0, ptr addrspace(1) %1) { + %3 = load i32, ptr addrspace(1) %1, align 4 + store i32 %3, ptr addrspace(1) %0, align 4 + ret void +} diff --git a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_ptr_type.ll b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_ptr_type.ll new file mode 100644 index 0000000000000..a568ed9ce9c22 --- /dev/null +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_ptr_type.ll @@ -0,0 +1,43 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv --spirv-ext=+SPV_KHR_untyped_pointers + +; TODO: enable back once spirv-tools are updated +; R/UN: spirv-val %t.spv + +; RUN: llvm-spirv %t.spv -o %t.spt --to-text +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV + +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o %t.rev.ll +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: Capability UntypedPointersKHR +; CHECK-SPIRV: Extension "SPV_KHR_untyped_pointers" +; CHECK-SPIRV: TypeUntypedPointerKHR [[#UntypedPtrTy:]] 7 +; CHECK-SPIRV: TypeFunction [[#FuncTy:]] [[#UntypedPtrTy]] [[#UntypedPtrTy]] + +; CHECK-SPIRV: Function [[#UntypedPtrTy]] [[#ProcessFuncId:]] 0 [[#FuncTy]] +; CHECK-SPIRV: FunctionParameter [[#UntypedPtrTy]] + +; CHECK-SPIRV: Function [[#UntypedPtrTy]] [[#FuncId:]] 0 [[#FuncTy]] +; CHECK-SPIRV: FunctionParameter [[#UntypedPtrTy]] [[#ParamId:]] +; CHECK-SPIRV: FunctionCall [[#UntypedPtrTy]] [[#Res:]] [[#ProcessFuncId]] [[#ParamId]] +; CHECK-SPIRV: ReturnValue [[#Res]] + + +; CHECK-LLVM: declare spir_func ptr @processPointer(ptr) +; CHECK-LLVM: define spir_func ptr @example(ptr %arg) +; CHECK-LLVM: entry: +; CHECK-LLVM: %result = call spir_func ptr @processPointer(ptr %arg) +; CHECK-LLVM: ret ptr %result + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-G1" +target triple = "spir64-unknown-unknown" + +declare ptr @processPointer(ptr) + +define ptr @example(ptr %arg) { +entry: + %result = call ptr @processPointer(ptr %arg) + ret ptr %result +} diff --git a/llvm-spirv/test/spirv-extensions-control.ll b/llvm-spirv/test/spirv-extensions-control.ll index d0e84184ede22..f02badcb79f3f 100644 --- a/llvm-spirv/test/spirv-extensions-control.ll +++ b/llvm-spirv/test/spirv-extensions-control.ll @@ -10,11 +10,11 @@ ; ; Bunch of positive tests: ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc --spirv-ext=+all -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=+all,-SPV_KHR_untyped_pointers -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID ; RUN: llvm-spirv %t.bc --spirv-ext=-all -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID ; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID ; RUN: llvm-spirv %t.bc --spirv-ext=-SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID -; RUN: llvm-spirv %t.bc --spirv-ext=+all,-SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=+all,-SPV_INTEL_subgroups,-SPV_KHR_untyped_pointers -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID ; RUN: llvm-spirv %t.bc --spirv-ext=-all,+SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID ; RUN: llvm-spirv %t.bc --spirv-ext=-SPV_INTEL_subgroups,+SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID ; diff --git a/llvm-spirv/test/transcoding/spirv-target-types.ll b/llvm-spirv/test/transcoding/spirv-target-types.ll index 08136fbd015cd..09b7850682fbc 100644 --- a/llvm-spirv/test/transcoding/spirv-target-types.ll +++ b/llvm-spirv/test/transcoding/spirv-target-types.ll @@ -3,6 +3,11 @@ ; RUN: llvm-as %s -o %t.bc ; RUN: llvm-spirv %t.bc -spirv-text -o %t.spv.txt ; RUN: FileCheck < %t.spv.txt %s --check-prefix=CHECK-SPIRV + +; Check that untyped pointers extension does not affect the translation of images. +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_untyped_pointers -spirv-text -o %t.spv.txt +; RUN: FileCheck < %t.spv.txt %s --check-prefix=CHECK-SPIRV + ; RUN: llvm-spirv %t.bc -o %t.from-llvm.spv ; RUN: llvm-spirv -to-binary %t.spv.txt -o %t.from-text.spv ; RUN: llvm-spirv %t.bc -o %t.spv