From 2eff9206675ec86e94193d40b7ae3a74861aea8d Mon Sep 17 00:00:00 2001 From: Viktoria Maximova Date: Thu, 5 Sep 2024 18:01:13 +0200 Subject: [PATCH 1/3] 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 3716032288bc8..7a6254918840e 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 775296146c528..b38517e804364 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; } @@ -2196,8 +2213,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)) { @@ -2407,14 +2429,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)) { @@ -6671,9 +6696,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..0f8c4e170851d 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h @@ -329,13 +329,11 @@ _SPIRV_OP(GroupNonUniformBitwiseXor, 361) _SPIRV_OP(GroupNonUniformLogicalAnd, 362) _SPIRV_OP(GroupNonUniformLogicalOr, 363) _SPIRV_OP(GroupNonUniformLogicalXor, 364) -_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 From 5c902598ddff8eef6d74d867d1b42fde3af6d879 Mon Sep 17 00:00:00 2001 From: Viktoria Maximova Date: Mon, 16 Sep 2024 17:27:50 +0200 Subject: [PATCH 2/3] SPV_KHR_untyped_pointers - implement OpUntypedVariableKHR (#2709) This continues #2687 by introducing untyped variables. 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/484e4070adb0a95 --- llvm-spirv/lib/SPIRV/SPIRVReader.cpp | 24 ++-- llvm-spirv/lib/SPIRV/SPIRVReader.h | 2 +- llvm-spirv/lib/SPIRV/SPIRVWriter.cpp | 65 +++++++---- .../lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp | 2 +- .../lib/SPIRV/libSPIRV/SPIRVBasicBlock.h | 4 +- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp | 3 +- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h | 4 +- .../lib/SPIRV/libSPIRV/SPIRVInstruction.h | 108 +++++++++++++++--- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp | 37 +++--- llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h | 9 +- .../lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h | 1 + .../KHR/SPV_KHR_untyped_pointers/globals.ll | 41 +++++++ .../SPV_KHR_untyped_pointers/infinite-phi.ll | 58 ++++++++++ .../KHR/SPV_KHR_untyped_pointers/store.ll | 22 ++-- .../untyped_var.spvasm | 37 ++++++ 15 files changed, 336 insertions(+), 81 deletions(-) create mode 100644 llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/globals.ll create mode 100644 llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/infinite-phi.ll create mode 100644 llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_var.spvasm diff --git a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp index 7a6254918840e..5a3e4c5891797 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp @@ -1529,9 +1529,15 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, case OpUndef: return mapValue(BV, UndefValue::get(transType(BV->getType()))); - case OpVariable: { - auto *BVar = static_cast(BV); - auto *PreTransTy = BVar->getType()->getPointerElementType(); + case OpVariable: + case OpUntypedVariableKHR: { + auto *BVar = static_cast(BV); + SPIRVType *PreTransTy = BVar->getType()->getPointerElementType(); + if (BVar->getType()->isTypeUntypedPointerKHR()) { + auto *UntypedVar = static_cast(BVar); + if (SPIRVType *DT = UntypedVar->getDataType()) + PreTransTy = DT; + } auto *Ty = transType(PreTransTy); bool IsConst = BVar->isConstant(); llvm::GlobalValue::LinkageTypes LinkageTy = transLinkageType(BVar); @@ -4062,7 +4068,7 @@ bool SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) { return true; } -void SPIRVToLLVM::transGlobalCtorDtors(SPIRVVariable *BV) { +void SPIRVToLLVM::transGlobalCtorDtors(SPIRVVariableBase *BV) { if (BV->getName() != "llvm.global_ctors" && BV->getName() != "llvm.global_dtors") return; @@ -4907,15 +4913,17 @@ SPIRVToLLVM::transLinkageType(const SPIRVValue *V) { return GlobalValue::ExternalLinkage; } // Variable declaration - if (V->getOpCode() == OpVariable) { - if (static_cast(V)->getInitializer() == 0) + if (V->getOpCode() == OpVariable || + V->getOpCode() == OpUntypedVariableKHR) { + if (static_cast(V)->getInitializer() == 0) return GlobalValue::ExternalLinkage; } // Definition return GlobalValue::AvailableExternallyLinkage; case LinkageTypeExport: - if (V->getOpCode() == OpVariable) { - if (static_cast(V)->getInitializer() == 0) + if (V->getOpCode() == OpVariable || + V->getOpCode() == OpUntypedVariableKHR) { + if (static_cast(V)->getInitializer() == 0) // Tentative definition return GlobalValue::CommonLinkage; } diff --git a/llvm-spirv/lib/SPIRV/SPIRVReader.h b/llvm-spirv/lib/SPIRV/SPIRVReader.h index 58c8f53bdc9c9..c3c7c24d644ea 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVReader.h +++ b/llvm-spirv/lib/SPIRV/SPIRVReader.h @@ -251,7 +251,7 @@ class SPIRVToLLVM : private BuiltinCallHelper { void transUserSemantic(SPIRV::SPIRVFunction *Fun); void transGlobalAnnotations(); - void transGlobalCtorDtors(SPIRVVariable *BV); + void transGlobalCtorDtors(SPIRVVariableBase *BV); void createCXXStructor(const char *ListName, SmallVectorImpl &Funcs); void transIntelFPGADecorations(SPIRVValue *BV, Value *V); diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index b38517e804364..b5ba78aec867a 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -755,8 +755,8 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(SPIRVType *ET, unsigned AddrSpc) { SPIRVType *TranslatedTy = nullptr; if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers) && - !(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeImage() || - ET->isTypeSampler() || ET->isTypePipe())) { + !(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeStruct() || + ET->isTypeImage() || ET->isTypeSampler() || ET->isTypePipe())) { TranslatedTy = BM->addUntypedPointerKHRType( SPIRSPIRVAddrSpaceMap::map(static_cast(AddrSpc))); } else { @@ -1329,7 +1329,8 @@ SPIRVValue *LLVMToSPIRVBase::transConstantUse(Constant *C, if (Trans->getType() == ExpectedType || Trans->getType()->isTypePipeStorage()) return Trans; - assert(C->getType()->isPointerTy() && + assert((C->getType()->isPointerTy() || + ExpectedType->isTypeUntypedPointerKHR()) && "Only pointer type mismatches should be possible"); // In the common case of strings ([N x i8] GVs), see if we can emit a GEP // instruction. @@ -2067,8 +2068,12 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, } } } - SPIRVType *TransTy = transType(Ty); - BVarInit = transConstantUse(Init, TransTy->getPointerElementType()); + if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers)) { + BVarInit = transConstantUse(Init, transType(Init->getType())); + } else { + SPIRVType *TransTy = transType(Ty); + BVarInit = transConstantUse(Init, TransTy->getPointerElementType()); + } } SPIRVStorageClassKind StorageClass; @@ -2101,9 +2106,12 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, } SPIRVType *TranslatedTy = transType(Ty); - auto *BVar = static_cast( - BM->addVariable(TranslatedTy, GV->isConstant(), transLinkageType(GV), - BVarInit, GV->getName().str(), StorageClass, nullptr)); + auto *BVar = static_cast(BM->addVariable( + TranslatedTy, + TranslatedTy->isTypeUntypedPointerKHR() ? transType(GV->getValueType()) + : nullptr, + GV->isConstant(), transLinkageType(GV), BVarInit, GV->getName().str(), + StorageClass, nullptr)); if (IsVectorCompute) { BVar->addDecorate(DecorationVectorComputeVariableINTEL); @@ -2292,8 +2300,9 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, StorageClassFunction, BM->addArrayType(transType(Alc->getAllocatedType()), Length)); SPIRVValue *Arr = BM->addVariable( - AllocationType, false, spv::internal::LinkageTypeInternal, nullptr, - Alc->getName().str() + "_alloca", StorageClassFunction, BB); + AllocationType, nullptr, false, spv::internal::LinkageTypeInternal, + nullptr, Alc->getName().str() + "_alloca", StorageClassFunction, + BB); // Manually set alignment. OpBitcast created below will be decorated as // that's the SPIR-V value mapped to the original LLVM one. transAlign(Alc, Arr); @@ -2317,7 +2326,10 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, TranslatedTy->getPointerElementType()) : TranslatedTy; SPIRVValue *Var = BM->addVariable( - VarTy, false, spv::internal::LinkageTypeInternal, nullptr, + VarTy, + VarTy->isTypeUntypedPointerKHR() ? transType(Alc->getAllocatedType()) + : nullptr, + false, spv::internal::LinkageTypeInternal, nullptr, Alc->getName().str(), StorageClassFunction, BB); if (V->getType()->getPointerAddressSpace() == SPIRAS_Generic) { SPIRVValue *Cast = @@ -2762,7 +2774,7 @@ void checkIsGlobalVar(SPIRVEntry *E, Decoration Dec) { E->getErrorLog().checkError(E->isVariable(), SPIRVEC_InvalidModule, ErrStr); auto AddrSpace = SPIRSPIRVAddrSpaceMap::rmap( - static_cast(E)->getStorageClass()); + static_cast(E)->getStorageClass()); ErrStr += " in a global (module) scope"; E->getErrorLog().checkError(AddrSpace == SPIRAS_Global, SPIRVEC_InvalidModule, ErrStr); @@ -2910,10 +2922,11 @@ static void transMetadataDecorations(Metadata *MD, SPIRVValue *Target) { case spv::internal::DecorationInitModeINTEL: case DecorationInitModeINTEL: { checkIsGlobalVar(Target, DecoKind); - ErrLog.checkError(static_cast(Target)->getInitializer(), - SPIRVEC_InvalidLlvmModule, - "InitModeINTEL only be applied to a global (module " - "scope) variable which has an Initializer operand"); + ErrLog.checkError( + static_cast(Target)->getInitializer(), + SPIRVEC_InvalidLlvmModule, + "InitModeINTEL only be applied to a global (module " + "scope) variable which has an Initializer operand"); ErrLog.checkError(NumOperands == 2, SPIRVEC_InvalidLlvmModule, "InitModeINTEL requires exactly 1 extra operand"); @@ -4155,14 +4168,18 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, SPIRVType *FTy = transType(II->getType()->getStructElementType(0)); SPIRVTypePointer *ITy = static_cast(transPointerType( II->getType()->getStructElementType(1), SPIRAS_Private)); - - unsigned BitWidth = ITy->getElementType()->getBitWidth(); - BM->getErrorLog().checkError(BitWidth == 32, SPIRVEC_InvalidBitWidth, - std::to_string(BitWidth)); - + if (!ITy->isTypeUntypedPointerKHR()) { + unsigned BitWidth = ITy->getElementType()->getBitWidth(); + BM->getErrorLog().checkError(BitWidth == 32, SPIRVEC_InvalidBitWidth, + std::to_string(BitWidth)); + } SPIRVValue *IntVal = - BM->addVariable(ITy, false, spv::internal::LinkageTypeInternal, nullptr, - "", ITy->getStorageClass(), BB); + BM->addVariable(ITy, + ITy->isTypeUntypedPointerKHR() + ? transType(II->getType()->getStructElementType(1)) + : nullptr, + false, spv::internal::LinkageTypeInternal, nullptr, "", + ITy->getStorageClass(), BB); std::vector Ops{transValue(II->getArgOperand(0), BB), IntVal}; @@ -4584,7 +4601,7 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, Init = BM->addCompositeConstant(CompositeTy, Elts); } SPIRVType *VarTy = transPointerType(AT, SPIRV::SPIRAS_Constant); - SPIRVValue *Var = BM->addVariable(VarTy, /*isConstant*/ true, + SPIRVValue *Var = BM->addVariable(VarTy, nullptr, /*isConstant*/ true, spv::internal::LinkageTypeInternal, Init, "", StorageClassUniformConstant, nullptr); SPIRVType *SourceTy = diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp index d976025a356a7..873d1fd4bd9ae 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp @@ -94,7 +94,7 @@ SPIRVInstruction *SPIRVBasicBlock::getVariableInsertionPoint() const { isa(Inst) || // Note: OpVariable and OpPhi instructions do not belong to the // same block in a valid SPIR-V module. - isa(Inst)); + isa(Inst) || isa(Inst)); }); if (IP == InstVec.end()) return nullptr; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h index 3cf00c7373974..35460e69e3a87 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h @@ -77,9 +77,9 @@ class SPIRVBasicBlock : public SPIRVValue { const SPIRVInstruction *getTerminateInstr() const { return InstVec.empty() ? nullptr : InstVec.back(); } - // OpVariable instructions must be the first instructions in the block, + // Variables must be the first instructions in the block, // intermixed with OpLine and OpNoLine instructions. Return first instruction - // not being an OpVariable, OpLine or OpNoLine. + // not being an OpVariable, OpUntypedVariableKHR, OpLine or OpNoLine. SPIRVInstruction *getVariableInsertionPoint() const; void setScope(SPIRVEntry *Scope) override; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp index c001ef12db98f..d1a56bb97426c 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp @@ -559,7 +559,8 @@ SPIRVEntry::getDecorationIds(Decoration Kind) const { } bool SPIRVEntry::hasLinkageType() const { - return OpCode == OpFunction || OpCode == OpVariable; + return OpCode == OpFunction || OpCode == OpVariable || + OpCode == OpUntypedVariableKHR; } bool SPIRVEntry::isExtInst(const SPIRVExtInstSetKind InstSet) const { diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h index 59a1bb8bb7b8a..5a6cf8a229cd8 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -339,7 +339,9 @@ class SPIRVEntry { bool isUndef() const { return OpCode == OpUndef; } bool isControlBarrier() const { return OpCode == OpControlBarrier; } bool isMemoryBarrier() const { return OpCode == OpMemoryBarrier; } - bool isVariable() const { return OpCode == OpVariable; } + bool isVariable() const { + return OpCode == OpVariable || OpCode == OpUntypedVariableKHR; + } bool isEndOfBlock() const; virtual bool isInst() const { return false; } virtual bool isOperandLiteral(unsigned Index) const { diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h index 7cfdade58b6b0..8b39ab9f368fd 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -452,24 +452,25 @@ class SPIRVMemoryAccess { SPIRVId NoAliasInstID; }; -class SPIRVVariable : public SPIRVInstruction { +class SPIRVVariableBase : public SPIRVInstruction { public: // Complete constructor for integer constant - SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheInitializer, - const std::string &TheName, - SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB, - SPIRVModule *TheM) - : SPIRVInstruction(TheInitializer && !TheInitializer->isUndef() ? 5 : 4, - OpVariable, TheType, TheId, TheBB, TheM), + SPIRVVariableBase(Op OC, SPIRVType *TheType, SPIRVId TheId, + SPIRVValue *TheInitializer, const std::string &TheName, + SPIRVStorageClassKind TheStorageClass, + SPIRVBasicBlock *TheBB, SPIRVModule *TheM, SPIRVWord WC) + : SPIRVInstruction(WC, OC, TheType, TheId, TheBB, TheM), StorageClass(TheStorageClass) { if (TheInitializer && !TheInitializer->isUndef()) Initializer.push_back(TheInitializer->getId()); Name = TheName; validate(); } - // Incomplete constructor - SPIRVVariable() - : SPIRVInstruction(OpVariable), StorageClass(StorageClassFunction) {} + // Incomplete constructors + SPIRVVariableBase(Op OC) + : SPIRVInstruction(OC), StorageClass(StorageClassFunction) {} + SPIRVVariableBase() + : SPIRVInstruction(OpNop), StorageClass(StorageClassFunction) {} SPIRVStorageClassKind getStorageClass() const { return StorageClass; } SPIRVValue *getInitializer() const { @@ -521,6 +522,77 @@ class SPIRVVariable : public SPIRVInstruction { std::vector Initializer; }; +class SPIRVVariable : public SPIRVVariableBase { +public: + // Complete constructor for integer constant + SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheInitializer, + const std::string &TheName, + SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB, + SPIRVModule *TheM) + : SPIRVVariableBase(OpVariable, TheType, TheId, TheInitializer, TheName, + TheStorageClass, TheBB, TheM, + TheInitializer && !TheInitializer->isUndef() ? 5 + : 4) {} + // Incomplete constructor + SPIRVVariable() : SPIRVVariableBase(OpVariable) {} +}; + +class SPIRVUntypedVariableKHR : public SPIRVVariableBase { +public: + SPIRVUntypedVariableKHR(SPIRVType *TheType, SPIRVId TheId, + SPIRVType *TheDataType, SPIRVValue *TheInitializer, + const std::string &TheName, + SPIRVStorageClassKind TheStorageClass, + SPIRVBasicBlock *TheBB, SPIRVModule *TheM) + : SPIRVVariableBase( + OpUntypedVariableKHR, TheType, TheId, TheInitializer, TheName, + TheStorageClass, TheBB, TheM, + TheDataType && !TheDataType->isUndef() + ? (TheInitializer && !TheInitializer->isUndef() ? 6 : 5) + : 4) { + if (TheDataType && !TheDataType->isUndef()) + DataType.push_back(TheDataType->getId()); + validate(); + } + SPIRVUntypedVariableKHR() : SPIRVVariableBase(OpUntypedVariableKHR) {} + SPIRVType *getDataType() const { + if (DataType.empty()) + return nullptr; + assert(DataType.size() == 1); + return get(DataType[0]); + } + std::vector getNonLiteralOperands() const override { + std::vector Vec; + if (SPIRVType *T = getDataType()) + Vec.push_back(T); + if (SPIRVValue *V = getInitializer()) + Vec.push_back(V); + return Vec; + } + std::optional getRequiredExtension() const override { + return ExtensionID::SPV_KHR_untyped_pointers; + } + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityUntypedPointersKHR); + } + +protected: + void validate() const override { + SPIRVVariableBase::validate(); + assert(DataType.size() == 1 || DataType.empty()); + } + void setWordCount(SPIRVWord TheWordCount) override { + SPIRVEntry::setWordCount(TheWordCount); + if (TheWordCount > 4) + DataType.resize(1); + if (TheWordCount > 5) + Initializer.resize(1); + } + _SPIRV_DEF_ENCDEC5(Type, Id, StorageClass, DataType, Initializer) + + std::vector DataType; +}; + class SPIRVStore : public SPIRVInstruction, public SPIRVMemoryAccess { public: const static SPIRVWord FixedWords = 3; @@ -572,9 +644,6 @@ class SPIRVStore : public SPIRVInstruction, public SPIRVMemoryAccess { (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"); } @@ -629,8 +698,6 @@ class SPIRVLoad : public SPIRVInstruction, public SPIRVMemoryAccess { getValueType(PtrId) ->getPointerElementType() ->isTypeUntypedPointerKHR() || - // TODO: This check should be removed once we support untyped - // variables. Type->isTypeUntypedPointerKHR() || Type == getValueType(PtrId)->getPointerElementType()) && "Inconsistent types"); @@ -688,9 +755,14 @@ class SPIRVBinary : public SPIRVInstTemplateBase { } else if (isBinaryPtrOpCode(OpCode)) { assert((Op1Ty->isTypePointer() && Op2Ty->isTypePointer()) && "Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction"); - assert(static_cast(Op1Ty)->getElementType() == - static_cast(Op2Ty)->getElementType() && - "Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction"); + if (!Op1Ty->isTypeUntypedPointerKHR() || + !Op2Ty->isTypeUntypedPointerKHR()) + assert( + static_cast(Op1Ty)->getElementType() == + static_cast(Op2Ty)->getElementType() && + "Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction"); + else if (OpCode == OpPtrDiff) + assert(Op1Ty == Op2Ty && "Invalid types for PtrDiff instruction"); } else { assert(0 && "Invalid op code!"); } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp index 0e5fd8553c69c..7261f9b3a71bd 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -127,7 +127,7 @@ class SPIRVModuleImpl : public SPIRVModule { } std::set &getExtension() override { return SPIRVExt; } SPIRVFunction *getFunction(unsigned I) const override { return FuncVec[I]; } - SPIRVVariable *getVariable(unsigned I) const override { + SPIRVVariableBase *getVariable(unsigned I) const override { return VariableVec[I]; } SPIRVValue *getValue(SPIRVId TheId) const override; @@ -456,9 +456,9 @@ class SPIRVModuleImpl : public SPIRVModule { SPIRVBasicBlock *BB) override; SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *, SPIRVBasicBlock *) override; - SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind, - SPIRVValue *, const std::string &, - SPIRVStorageClassKind, + SPIRVInstruction *addVariable(SPIRVType *, SPIRVType *, bool, + SPIRVLinkageTypeKind, SPIRVValue *, + const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *) override; SPIRVValue *addVectorShuffleInst(SPIRVType *Type, SPIRVValue *Vec1, SPIRVValue *Vec2, @@ -516,7 +516,7 @@ class SPIRVModuleImpl : public SPIRVModule { typedef std::vector SPIRVForwardPointerVec; typedef std::vector SPIRVTypeVec; typedef std::vector SPIRVConstantVector; - typedef std::vector SPIRVVariableVec; + typedef std::vector SPIRVVariableVec; typedef std::vector SPIRVStringVec; typedef std::vector SPIRVMemberNameVec; typedef std::vector SPIRVDecGroupVec; @@ -757,8 +757,9 @@ void SPIRVModuleImpl::layoutEntry(SPIRVEntry *E) { case OpMemberName: addTo(MemberNameVec, E); break; - case OpVariable: { - auto *BV = static_cast(E); + case OpVariable: + case OpUntypedVariableKHR: { + auto *BV = static_cast(E); if (!BV->getParent()) addTo(VariableVec, E); } break; @@ -1855,12 +1856,20 @@ SPIRVModuleImpl::getOrAddAliasScopeListDeclINTELInst(std::vector Args, return getOrAddMemAliasingINTELInst(Args, MD); } -SPIRVInstruction *SPIRVModuleImpl::addVariable( - SPIRVType *Type, bool IsConstant, SPIRVLinkageTypeKind LinkageTy, - SPIRVValue *Initializer, const std::string &Name, - SPIRVStorageClassKind StorageClass, SPIRVBasicBlock *BB) { - SPIRVVariable *Variable = new SPIRVVariable(Type, getId(), Initializer, Name, - StorageClass, BB, this); +SPIRVInstruction * +SPIRVModuleImpl::addVariable(SPIRVType *Type, SPIRVType *AllocType, + bool IsConstant, SPIRVLinkageTypeKind LinkageTy, + SPIRVValue *Initializer, const std::string &Name, + SPIRVStorageClassKind StorageClass, + SPIRVBasicBlock *BB) { + SPIRVVariableBase *Variable = nullptr; + if (Type->isTypeUntypedPointerKHR()) { + Variable = new SPIRVUntypedVariableKHR( + Type, getId(), AllocType, Initializer, Name, StorageClass, BB, this); + } else { + Variable = new SPIRVVariable(Type, getId(), Initializer, Name, StorageClass, + BB, this); + } if (BB) return addInstruction(Variable, BB, BB->getVariableInsertionPoint()); @@ -1893,7 +1902,7 @@ class TopologicalSort { enum DFSState : char { Unvisited, Discovered, Visited }; typedef std::vector SPIRVTypeVec; typedef std::vector SPIRVConstantVector; - typedef std::vector SPIRVVariableVec; + typedef std::vector SPIRVVariableVec; typedef std::vector SPIRVConstAndVarVec; typedef std::vector SPIRVForwardPointerVec; typedef std::function Comp; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h index 7e77ef80e49d0..8915eb7ecc2a1 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -84,7 +84,7 @@ class SPIRVTypeQueue; class SPIRVTypePipe; class SPIRVTypeVmeImageINTEL; class SPIRVValue; -class SPIRVVariable; +class SPIRVVariableBase; class SPIRVDecorateGeneric; class SPIRVDecorationGroup; class SPIRVGroupDecorate; @@ -138,7 +138,7 @@ class SPIRVModule { virtual SPIRVExtInstSetKind getBuiltinSet(SPIRVId) const = 0; virtual std::set &getExtension() = 0; virtual SPIRVFunction *getFunction(unsigned) const = 0; - virtual SPIRVVariable *getVariable(unsigned) const = 0; + virtual SPIRVVariableBase *getVariable(unsigned) const = 0; virtual SPIRVMemoryModelKind getMemoryModel() const = 0; virtual unsigned getNumFunctions() const = 0; virtual unsigned getNumVariables() const = 0; @@ -464,8 +464,9 @@ class SPIRVModule { SPIRVBasicBlock *BB) = 0; virtual SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *, SPIRVBasicBlock *) = 0; - virtual SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind, - SPIRVValue *, const std::string &, + virtual SPIRVInstruction *addVariable(SPIRVType *, SPIRVType *, bool, + SPIRVLinkageTypeKind, SPIRVValue *, + const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *) = 0; virtual SPIRVValue * diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h index 0f8c4e170851d..008dd21901e78 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h @@ -334,6 +334,7 @@ _SPIRV_OP(PtrEqual, 401) _SPIRV_OP(PtrNotEqual, 402) _SPIRV_OP(PtrDiff, 403) _SPIRV_OP(TypeUntypedPointerKHR, 4417) +_SPIRV_OP(UntypedVariableKHR, 4418) _SPIRV_OP(GroupNonUniformRotateKHR, 4431) _SPIRV_OP(SDotKHR, 4450) _SPIRV_OP(UDotKHR, 4451) diff --git a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/globals.ll b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/globals.ll new file mode 100644 index 0000000000000..55ca60176f190 --- /dev/null +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/globals.ll @@ -0,0 +1,41 @@ +; 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. +; 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 +; RUN: llvm-dis %t.rev.bc -o %t.rev.ll +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM + +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-SPIRV-DAG: TypeInt [[#I16:]] 16 0 +; CHECK-SPIRV-DAG: Constant [[#I16]] [[#CONST0:]] 0 +; CHECK-SPIRV-DAG: TypeInt [[#I32:]] 32 0 +; CHECK-SPIRV-DAG: TypeUntypedPointerKHR [[#PTRTY:]] 5 +; CHECK-SPIRV-DAG: TypeUntypedPointerKHR [[#LOCALPTRTY:]] 4 + +; CHECK-SPIRV: UntypedVariableKHR [[#PTRTY]] [[#VARA:]] 5 [[#I16]] [[#CONST0]] +; CHECK-SPIRV: UntypedVariableKHR [[#PTRTY]] [[#VARB:]] 5 [[#I32]] +; CHECK-SPIRV: UntypedVariableKHR [[#PTRTY]] [[#VARC:]] 5 [[#PTRTY]] [[#VARA]] +; CHECK-SPIRV: UntypedVariableKHR [[#LOCALPTRTY]] [[#VARD:]] 4 [[#PTRTY]] + +; CHECK-LLVM: @a = addrspace(1) global i16 0 +; CHECK-LLVM: @b = external addrspace(1) global i32 +; CHECK-LLVM: @c = addrspace(1) global ptr addrspace(1) @a +; CHECK-LLVM: @d = external addrspace(3) global ptr addrspace(1) + +@a = addrspace(1) global i16 0 +@b = external addrspace(1) global i32 +@c = addrspace(1) global ptr addrspace(1) @a +@d = external addrspace(3) global ptr addrspace(1) + +; Function Attrs: nounwind +define spir_func void @foo() { +entry: + ret void +} diff --git a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/infinite-phi.ll b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/infinite-phi.ll new file mode 100644 index 0000000000000..83b1248a8a019 --- /dev/null +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/infinite-phi.ll @@ -0,0 +1,58 @@ +; 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. +; 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 +; RUN: llvm-dis %t.rev.bc -o %t.rev.ll +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM + +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-SPIRV: TypeInt [[#INT:]] 32 0 +; CHECK-SPIRV: TypeUntypedPointerKHR [[#PTRTY:]] 7 +; CHECK-SPIRV: TypeFloat [[#FLOAT:]] 32 + +; CHECK-SPIRV: UntypedVariableKHR [[#PTRTY]] [[#IPTR:]] 7 [[#INT]] +; CHECK-SPIRV: UntypedVariableKHR [[#PTRTY]] [[#FPTR:]] 7 [[#FLOAT]] + +; This bitcast seems redundant, it appears because of the Type Scavenger. +; TODO: Investigate and fix if possible. +; CHECK-SPIRV: Bitcast [[#PTRTY]] [[#IPTRI:]] [[#IPTR]] +; CHECK-SPIRV: Phi [[#PTRTY]] [[#PTR1:]] [[#PTR2:]] [[#]] [[#IPTRI]] +; CHECK-SPIRV: Phi [[#PTRTY]] [[#PTR2]] [[#PTR1]] [[#]] [[#FPTR]] + +; CHECK-LLVM: %iptr = alloca i32, align 4 +; CHECK-LLVM: %fptr = alloca float, align 4 +; CHECK-LLVM: %0 = bitcast ptr %iptr to ptr +; CHECK-LLVM: br label %loop + +; CHECK-LLVM: %ptr1 = phi ptr [ %ptr2, %loop ], [ %0, %entry ] +; CHECK-LLVM: %ptr2 = phi ptr [ %ptr1, %loop ], [ %fptr, %entry ] +; CHECK-LLVM: %cond = phi i32 [ 0, %entry ], [ %cond.next, %loop ] +; CHECK-LLVM: %cond.next = add i32 %cond, 1 +; CHECK-LLVM: %cmp = icmp slt i32 %cond.next, 150 +; CHECK-LLVM: br i1 %cmp, label %exit, label %loop + +; Function Attrs: nounwind +define spir_kernel void @foo() { +entry: + %iptr = alloca i32, align 4 + %fptr = alloca float, align 4 + br label %loop + +loop: + %ptr1 = phi ptr [%ptr2, %loop], [%iptr, %entry] + %ptr2 = phi ptr [%ptr1, %loop], [%fptr, %entry] + %cond = phi i32 [0, %entry], [%cond.next, %loop] + %cond.next = add i32 %cond, 1 + %cmp = icmp slt i32 %cond.next, 150 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} 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 index aa25898bf47ee..c42396d2f0afd 100644 --- a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/store.ll +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/store.ll @@ -4,7 +4,7 @@ ; 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. +; TODO: enable back once spirv-tools are updated. ; R/UN: spirv-val %t.spv ; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_untyped_pointers -spirv-text -o %t.spt @@ -18,17 +18,20 @@ ; CHECK-SPIRV: Extension "SPV_KHR_untyped_pointers" ; CHECK-SPIRV-DAG: TypeInt [[#IntTy:]] 32 0 ; CHECK-SPIRV-DAG: Constant [[#IntTy]] [[#Constant0:]] 0 +; CHECK-SPIRV-DAG: Constant [[#IntTy]] [[#Constant42:]] 42 ; 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: UntypedVariableKHR [[#UntypedPtrTyFunc]] [[#VarBId:]] 7 [[#UntypedPtrTy]] ; 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: UntypedVariableKHR [[#UntypedPtrTyFunc]] [[#VarCId:]] 7 [[#IntTy]] +; CHECK-SPIRV: Store [[#VarCId]] [[#Constant42]] 2 4 ; CHECK-SPIRV: Load [[#IntTy]] [[#LoadId:]] [[#FuncParam1]] 2 4 ; CHECK-SPIRV: Store [[#FuncParam0]] [[#LoadId]] 2 4 @@ -36,7 +39,7 @@ target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:2 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: %b = alloca ptr addrspace(1), 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 @@ -50,10 +53,15 @@ entry: } ; 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 +; CHECK-LLVM: %c = alloca i32 +; CHECK-LLVM: store i32 42, ptr %c, align 4 +; CHECK-LLVM: %2 = load i32, ptr addrspace(1) %1, align 4 +; CHECK-LLVM: store i32 %2, 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 +entry: + %c = alloca i32, align 4 + store i32 42, ptr %c, align 4 + %2 = load i32, ptr addrspace(1) %1, align 4 + store i32 %2, ptr addrspace(1) %0, align 4 ret void } diff --git a/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_var.spvasm b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_var.spvasm new file mode 100644 index 0000000000000..224f64db20b63 --- /dev/null +++ b/llvm-spirv/test/extensions/KHR/SPV_KHR_untyped_pointers/untyped_var.spvasm @@ -0,0 +1,37 @@ +; TODO: enable back once spirv-tools are updated. +; XFAIL: * + +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.6 -o %t.spv %s +; RUN: spirv-val %t.spv + +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc +; RUN: FileCheck < %t.rev.ll %s + +; CHECK: @var = internal addrspace(3) global i32 undef +; CHECK: call spir_func void @0(ptr addrspace(3) @var) + +OpCapability Addresses +OpCapability Kernel +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %main "main" %var +OpName %var "var" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %int +%void_fn = OpTypeFunction %void +%ptr_fn = OpTypeFunction %void %ptr +%foo = OpFunction %void None %ptr_fn +%param = OpFunctionParameter %ptr +%first = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %foo %var +OpReturn +OpFunctionEnd From 2db7cdd075ba0ec6507da6dc511a0b1fbc063c68 Mon Sep 17 00:00:00 2001 From: "Maksimova, Viktoria" Date: Wed, 25 Sep 2024 04:36:06 -0700 Subject: [PATCH 3/3] Do not use SPV_KHR_untyped_pointers extension in the tests yet --- sycl/test/basic_tests/sycl-kernel-save-user-names.cpp | 2 +- sycl/test/extensions/private_alloca.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sycl/test/basic_tests/sycl-kernel-save-user-names.cpp b/sycl/test/basic_tests/sycl-kernel-save-user-names.cpp index 5c3c0a771ecd8..2b9257e94b2d0 100644 --- a/sycl/test/basic_tests/sycl-kernel-save-user-names.cpp +++ b/sycl/test/basic_tests/sycl-kernel-save-user-names.cpp @@ -1,6 +1,6 @@ // RUN: %clangxx -fsycl -fsycl-device-only -fno-discard-value-names -fno-sycl-early-optimizations -o %t.bc %s // RUN: sycl-post-link -properties %t.bc -spec-const=emulation -o %t.table -// RUN: llvm-spirv -o %t.spv -spirv-max-version=1.3 -spirv-ext=+all %t.bc +// RUN: llvm-spirv -o %t.spv -spirv-max-version=1.3 -spirv-ext=+all,-SPV_KHR_untyped_pointers %t.bc // RUN: llvm-spirv -o %t.rev.bc -r %t.spv // RUN: llvm-dis %t.rev.bc -o=- | FileCheck %s diff --git a/sycl/test/extensions/private_alloca.cpp b/sycl/test/extensions/private_alloca.cpp index 22f834dc5217c..ad50a6eeb3ea5 100644 --- a/sycl/test/extensions/private_alloca.cpp +++ b/sycl/test/extensions/private_alloca.cpp @@ -1,7 +1,7 @@ // RUN: %clangxx -fsycl -fsycl-device-only -c -o %t.bc %s // RUN: %if asserts %{sycl-post-link -properties -debug-only=SpecConst %t.bc -spec-const=native -o %t.txt 2>&1 | FileCheck %s -check-prefixes=CHECK-LOG %} %else %{sycl-post-link %t.bc -properties -spec-const=native -o %t.txt 2>&1 %} // RUN: cat %t_0.prop | FileCheck %s -check-prefixes=CHECK,CHECK-RT -// RUN: llvm-spirv -o %t_0.spv -spirv-max-version=1.1 -spirv-ext=+all %t_0.bc +// RUN: llvm-spirv -o %t_0.spv -spirv-max-version=1.1 -spirv-ext=+all,-SPV_KHR_untyped_pointers %t_0.bc // RUN: llvm-spirv -o - --to-text %t_0.spv | FileCheck %s -check-prefixes=CHECK-SPV // Check SPIR-V code generation for 'sycl_ext_oneapi_private_alloca'. Each call