diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc index b855e10a96..b46234ed49 100644 --- a/include/LLVMSPIRVExtensions.inc +++ b/include/LLVMSPIRVExtensions.inc @@ -35,3 +35,4 @@ EXT(SPV_INTEL_tensor_float32_conversion) EXT(SPV_INTEL_hw_thread_queries) EXT(SPV_EXT_relaxed_printf_string_address_space) EXT(SPV_INTEL_split_barrier) +EXT(SPV_INTEL_global_variable_decorations) diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index 4c7adf7f52..c45caafe55 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -2613,6 +2613,16 @@ transDecorationsToMetadataList(llvm::LLVMContext *Context, OPs.push_back(LinkTypeMD); break; } + case spv::internal::DecorationHostAccessINTEL: { + const auto *const HostAccDeco = + static_cast(Deco); + auto *const AccModeMD = ConstantAsMetadata::get(ConstantInt::get( + Type::getInt32Ty(*Context), HostAccDeco->getAccessMode())); + auto *const NameMD = MDString::get(*Context, HostAccDeco->getVarName()); + OPs.push_back(AccModeMD); + OPs.push_back(NameMD); + break; + } case DecorationMergeINTEL: { const auto MergeAttrLits = Deco->getVecLiteral(); std::string FirstString = getString(MergeAttrLits); diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 92d1e512a2..939cac9e31 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -1395,6 +1395,19 @@ SPIRVValue *LLVMToSPIRV::mapValue(Value *V, SPIRVValue *BV) { break; \ } +void checkIsGlobalVar(SPIRVEntry *E, Decoration Dec) { + std::string ErrStr = + SPIRVDecorationNameMap::map(Dec) + " can only be applied to a variable"; + + E->getErrorLog().checkError(E->isVariable(), SPIRVEC_InvalidModule, ErrStr); + + auto AddrSpace = SPIRSPIRVAddrSpaceMap::rmap( + static_cast(E)->getStorageClass()); + ErrStr += " in a global (module) scope"; + E->getErrorLog().checkError(AddrSpace == SPIRAS_Global, SPIRVEC_InvalidModule, + ErrStr); +} + static void transMetadataDecorations(Metadata *MD, SPIRVEntry *Target) { auto *ArgDecoMD = dyn_cast(MD); assert(ArgDecoMD && "Decoration list must be a metadata node"); @@ -1445,6 +1458,52 @@ static void transMetadataDecorations(Metadata *MD, SPIRVEntry *Target) { Target, Name->getString().str(), TypeKind)); break; } + case spv::internal::DecorationHostAccessINTEL: { + checkIsGlobalVar(Target, DecoKind); + + assert(NumOperands == 3 && "HostAccessINTEL requires 2 extra operands " + "after the decoration kind number"); + auto *AccessMode = + mdconst::dyn_extract(DecoMD->getOperand(1)); + assert(AccessMode && + "HostAccessINTEL requires first extra operand to be an int"); + auto *Name = dyn_cast(DecoMD->getOperand(2)); + assert(Name && + "HostAccessINTEL requires second extra operand to be a string"); + + Target->addDecorate(new SPIRVDecorateHostAccessINTEL( + Target, AccessMode->getZExtValue(), Name->getString().str())); + break; + } + case spv::internal::DecorationInitModeINTEL: { + checkIsGlobalVar(Target, DecoKind); + assert(static_cast(Target)->getInitializer() && + "InitModeINTEL only be applied to a global (module scope) " + "variable which has an Initializer operand"); + + assert(NumOperands == 2 && + "InitModeINTEL requires exactly 1 extra operand"); + auto *Trigger = mdconst::dyn_extract(DecoMD->getOperand(1)); + assert(Trigger && + "InitModeINTEL requires extra operand to be an integer"); + + Target->addDecorate( + new SPIRVDecorateInitModeINTEL(Target, Trigger->getZExtValue())); + break; + } + case spv::internal::DecorationImplementInCSRINTEL: { + checkIsGlobalVar(Target, DecoKind); + + assert(NumOperands == 2 && + "ImplementInCSRINTEL requires exactly 1 extra operand"); + auto *Value = mdconst::dyn_extract(DecoMD->getOperand(1)); + assert(Value && + "ImplementInCSRINTEL requires extra operand to be an integer"); + + Target->addDecorate( + new SPIRVDecorateImplementInCSRINTEL(Target, Value->getZExtValue())); + break; + } default: { if (NumOperands == 1) { Target->addDecorate(new SPIRVDecorate(DecoKind, Target)); diff --git a/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp b/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp index 73e64b3e96..de5ec7597f 100644 --- a/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp @@ -101,7 +101,7 @@ size_t SPIRVDecorateGeneric::getLiteralCount() const { return Literals.size(); } void SPIRVDecorate::encode(spv_ostream &O) const { SPIRVEncoder Encoder = getEncoder(O); Encoder << Target << Dec; - switch (Dec) { + switch (static_cast(Dec)) { case DecorationLinkageAttributes: SPIRVDecorateLinkageAttr::encodeLiterals(Encoder, Literals); break; @@ -114,6 +114,9 @@ void SPIRVDecorate::encode(spv_ostream &O) const { case DecorationUserSemantic: SPIRVDecorateUserSemanticAttr::encodeLiterals(Encoder, Literals); break; + case spv::internal::DecorationHostAccessINTEL: + SPIRVDecorateHostAccessINTEL::encodeLiterals(Encoder, Literals); + break; default: Encoder << Literals; } @@ -127,7 +130,7 @@ void SPIRVDecorate::setWordCount(SPIRVWord Count) { void SPIRVDecorate::decode(std::istream &I) { SPIRVDecoder Decoder = getDecoder(I); Decoder >> Target >> Dec; - switch (Dec) { + switch (static_cast(Dec)) { case DecorationLinkageAttributes: SPIRVDecorateLinkageAttr::decodeLiterals(Decoder, Literals); break; @@ -140,6 +143,9 @@ void SPIRVDecorate::decode(std::istream &I) { case DecorationUserSemantic: SPIRVDecorateUserSemanticAttr::decodeLiterals(Decoder, Literals); break; + case spv::internal::DecorationHostAccessINTEL: + SPIRVDecorateHostAccessINTEL::decodeLiterals(Decoder, Literals); + break; default: Decoder >> Literals; } diff --git a/lib/SPIRV/libSPIRV/SPIRVDecorate.h b/lib/SPIRV/libSPIRV/SPIRVDecorate.h index 52467c1eac..4850edbf33 100644 --- a/lib/SPIRV/libSPIRV/SPIRVDecorate.h +++ b/lib/SPIRV/libSPIRV/SPIRVDecorate.h @@ -168,6 +168,10 @@ class SPIRVDecorate : public SPIRVDecorateGeneric { return getSet(ExtensionID::SPV_INTEL_float_controls2); case DecorationCallableFunctionINTEL: return getSet(ExtensionID::SPV_INTEL_fast_composite); + case internal::DecorationHostAccessINTEL: + case internal::DecorationInitModeINTEL: + case internal::DecorationImplementInCSRINTEL: + return getSet(ExtensionID::SPV_INTEL_global_variable_decorations); default: return SPIRVExtSet(); } @@ -608,6 +612,69 @@ class SPIRVDecorateNoAliasINTEL : public SPIRVDecorateId { AliasList){}; }; +class SPIRVDecorateHostAccessINTEL : public SPIRVDecorate { +public: + // Complete constructor for SPIRVHostAccessINTEL + SPIRVDecorateHostAccessINTEL(SPIRVEntry *TheTarget, SPIRVWord AccessMode, + const std::string &VarName) + : SPIRVDecorate(spv::internal::DecorationHostAccessINTEL, TheTarget) { + Literals.push_back(AccessMode); + for (auto &I : getVec(VarName)) + Literals.push_back(I); + WordCount += Literals.size(); + }; + + SPIRVWord getAccessMode() const { return Literals.front(); } + std::string getVarName() const { + return getString(Literals.cbegin() + 1, Literals.cend()); + } + + static void encodeLiterals(SPIRVEncoder &Encoder, + const std::vector &Literals) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + Encoder << Literals.front(); + std::string Name = getString(Literals.cbegin() + 1, Literals.cend()); + Encoder << Name; + } else +#endif + Encoder << Literals; + } + + static void decodeLiterals(SPIRVDecoder &Decoder, + std::vector &Literals) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + SPIRVWord Mode; + Decoder >> Mode; + std::string Name; + Decoder >> Name; + Literals.front() = Mode; + std::copy_n(getVec(Name).begin(), Literals.size() - 1, + Literals.begin() + 1); + + } else +#endif + Decoder >> Literals; + } +}; + +class SPIRVDecorateInitModeINTEL : public SPIRVDecorate { +public: + // Complete constructor for SPIRVInitModeINTEL + SPIRVDecorateInitModeINTEL(SPIRVEntry *TheTarget, SPIRVWord Trigger) + : SPIRVDecorate(spv::internal::DecorationInitModeINTEL, TheTarget, + Trigger){}; +}; + +class SPIRVDecorateImplementInCSRINTEL : public SPIRVDecorate { +public: + // Complete constructor for SPIRVImplementInCSRINTEL + SPIRVDecorateImplementInCSRINTEL(SPIRVEntry *TheTarget, SPIRVWord Value) + : SPIRVDecorate(spv::internal::DecorationImplementInCSRINTEL, TheTarget, + Value){}; +}; + } // namespace SPIRV #endif // SPIRV_LIBSPIRV_SPIRVDECORATE_H diff --git a/lib/SPIRV/libSPIRV/SPIRVEnum.h b/lib/SPIRV/libSPIRV/SPIRVEnum.h index 397451e54f..4693a0bebb 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -416,6 +416,12 @@ template <> inline void SPIRVMap::init() { {internal::CapabilityMemoryAccessAliasingINTEL}); ADD_VEC_INIT(internal::DecorationNoAliasINTEL, {internal::CapabilityMemoryAccessAliasingINTEL}); + ADD_VEC_INIT(internal::DecorationHostAccessINTEL, + {internal::CapabilityGlobalVariableDecorationsINTEL}); + ADD_VEC_INIT(internal::DecorationInitModeINTEL, + {internal::CapabilityGlobalVariableDecorationsINTEL}); + ADD_VEC_INIT(internal::DecorationImplementInCSRINTEL, + {internal::CapabilityGlobalVariableDecorationsINTEL}); } template <> inline void SPIRVMap::init() { diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h index b412d26bdd..0022bc8ddf 100644 --- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h @@ -374,6 +374,9 @@ template <> inline void SPIRVMap::init() { add(internal::DecorationAliasScopeINTEL, "AliasScopeINTEL"); add(internal::DecorationNoAliasINTEL, "NoAliasINTEL"); + add(internal::DecorationHostAccessINTEL, "HostAccessINTEL"); + add(internal::DecorationInitModeINTEL, "InitModeINTEL"); + add(internal::DecorationImplementInCSRINTEL, "ImplementInCSRINTEL"); } SPIRV_DEF_NAMEMAP(Decoration, SPIRVDecorationNameMap) @@ -578,6 +581,8 @@ template <> inline void SPIRVMap::init() { "TensorFloat32ConversionINTEL"); add(internal::CapabilityHWThreadQueryINTEL, "HWThreadQueryINTEL"); add(CapabilitySplitBarrierINTEL, "SplitBarrierINTEL"); + add(internal::CapabilityGlobalVariableDecorationsINTEL, + "GlobalVariableDecorationsINTEL"); add(CapabilityMax, "Max"); } diff --git a/lib/SPIRV/libSPIRV/spirv_internal.hpp b/lib/SPIRV/libSPIRV/spirv_internal.hpp index 5a5945597f..b568e91834 100644 --- a/lib/SPIRV/libSPIRV/spirv_internal.hpp +++ b/lib/SPIRV/libSPIRV/spirv_internal.hpp @@ -49,7 +49,10 @@ enum InternalOp { enum InternalDecoration { IDecAliasScopeINTEL = 5914, - IDecNoAliasINTEL = 5915 + IDecNoAliasINTEL = 5915, + IDecHostAccessINTEL = 6147, + IDecInitModeINTEL = 6148, + IDecImplementInCSRINTEL = 6149, }; enum InternalCapability { @@ -59,6 +62,8 @@ enum InternalCapability { ICapabilityTensorFloat32ConversionINTEL = 6425, ICapabilityMaskedGatherScatterINTEL = 6427, ICapabilityHWThreadQueryINTEL = 6134, + ICapFPArithmeticFenceINTEL = 6144, + ICapGlobalVariableDecorationsINTEL = 6146 }; enum InternalMemoryAccessMask { @@ -100,6 +105,15 @@ constexpr Decoration DecorationAliasScopeINTEL = static_cast(IDecAliasScopeINTEL ); constexpr Decoration DecorationNoAliasINTEL = static_cast(IDecNoAliasINTEL); +constexpr Decoration DecorationHostAccessINTEL = + static_cast(IDecHostAccessINTEL); +constexpr Decoration DecorationInitModeINTEL = + static_cast(IDecInitModeINTEL); +constexpr Decoration DecorationImplementInCSRINTEL = + static_cast(IDecImplementInCSRINTEL); + +constexpr Capability CapabilityGlobalVariableDecorationsINTEL = + static_cast(ICapGlobalVariableDecorationsINTEL); constexpr Capability CapabilityMemoryAccessAliasingINTEL = static_cast(ICapMemoryAccessAliasingINTEL); diff --git a/test/transcoding/SPV_INTEL_global_variable_decorations/global_var_decorations.ll b/test/transcoding/SPV_INTEL_global_variable_decorations/global_var_decorations.ll new file mode 100644 index 0000000000..b01c4c0a4a --- /dev/null +++ b/test/transcoding/SPV_INTEL_global_variable_decorations/global_var_decorations.ll @@ -0,0 +1,75 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_global_variable_decorations -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV + +; RUN: llvm-spirv -r %t.spv --spirv-target-env=SPV-IR -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-SPV-IR + +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc +; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM + +; Expected to fail - the decorations require enabled extension to be translated. +; RUN: not llvm-spirv %t.bc -o %t.spv + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir64-unknown-unknown" + +@int_var = addrspace(1) global i32 42, !spirv.Decorations !1 +@float_var = addrspace(1) global float 1.0, !spirv.Decorations !6 +@bool_var = addrspace(1) global i1 0, !spirv.Decorations !9 + +; CHECK-SPIRV: Capability GlobalVariableDecorationsINTEL +; CHECK-SPIRV: Extension "SPV_INTEL_global_variable_decorations" + +; CHECK-SPIRV: Decorate [[#GROUP0:]] InitModeINTEL 0 +; CHECK-SPIRV: DecorationGroup [[#GROUP0]] +; CHECK-SPIRV: Decorate [[#GROUP1:]] ImplementInCSRINTEL 1 +; CHECK-SPIRV: DecorationGroup [[#GROUP1]] + +; CHECK-SPIRV: Decorate [[#INT_VAR_ID:]] HostAccessINTEL 1 "IntVarName" +; CHECK-SPIRV: Decorate [[#BOOL_VAR_ID:]] HostAccessINTEL 3 "BoolVarName" +; CHECK-SPIRV: Decorate [[#FLOAT_VAR_ID:]] InitModeINTEL 1 +; CHECK-SPIRV: Decorate [[#BOOL_VAR_ID]] ImplementInCSRINTEL 0 +; CHECK-SPIRV: GroupDecorate [[#GROUP0]] [[#INT_VAR_ID]] [[#BOOL_VAR_ID]] +; CHECK-SPIRV: GroupDecorate [[#GROUP1]] [[#INT_VAR_ID]] [[#FLOAT_VAR_ID]] + +; 5 is a global storage +; CHECK-SPIRV: Variable [[#IGNORE0:]] [[#INT_VAR_ID]] 5 +; CHECK-SPIRV: Variable [[#IGNORE1:]] [[#FLOAT_VAR_ID]] 5 +; CHECK-SPIRV: Variable [[#IGNORE2:]] [[#BOOL_VAR_ID]] 5 + +!1 = !{!2, !3, !4} +!2 = !{i32 6147, i32 1, !"IntVarName"} ; HostAccessINTEL 1 "IntVarName" +!3 = !{i32 6149, i1 true} ; ImplementInCSRINTEL = true +!4 = !{i32 6148, i32 0} ; InitModeINTEL = 0 +!5 = !{i32 6148, i32 1} ; InitModeINTEL = 1 +!6 = !{!3, !5} +!7 = !{i32 6147, i32 3, !"BoolVarName"} ; HostAccessINTEL 3 "BoolVarName" +!8 = !{i32 6149, i1 false} ; ImplementInCSRINTEL = false +!9 = !{!7, !8, !4} + +; CHECK-SPV-IR: @int_var = addrspace(1) global i32 42, !spirv.Decorations ![[#INT_VAR_DEC:]] +; CHECK-SPV-IR: @float_var = addrspace(1) global float 1.000000e+00, !spirv.Decorations ![[#FLOAT_VAR_DEC:]] +; CHECK-SPV-IR: @bool_var = addrspace(1) global i1 false, !spirv.Decorations ![[#BOOL_VAR_DEC:]] + +; CHECK-SPV-IR: ![[#INT_VAR_DEC]] = !{![[#IGNORE3:]], ![[#MD_HOST_ACCESS_INTVAR:]], ![[#MD_INIT_0:]], ![[#MD_CSR_1:]]} +; CHECK-SPV-IR: ![[#MD_HOST_ACCESS_INTVAR]] = !{i32 6147, i32 1, !"IntVarName"} +; CHECK-SPV-IR: ![[#MD_INIT_0]] = !{i32 6148, i32 0} +; CHECK-SPV-IR: ![[#MD_CSR_1]] = !{i32 6149, i32 1} +; CHECK-SPV-IR: ![[#FLOAT_VAR_DEC]] = !{![[#IGNORE4:]], ![[#MD_INIT_1:]], ![[#MD_CSR_1]]} +; CHECK-SPV-IR: ![[#MD_INIT_1]] = !{i32 6148, i32 1} +; CHECK-SPV-IR: ![[#BOOL_VAR_DEC]] = !{![[#IGNORE5:]], ![[#MD_HOST_ACCESS_BOOLVAR:]], ![[#MD_INIT_0]], ![[#MD_CSR_0:]]} +; CHECK-SPV-IR: ![[#MD_HOST_ACCESS_BOOLVAR]] = !{i32 6147, i32 3, !"BoolVarName"} +; CHECK-SPV-IR: ![[#MD_CSR_0]] = !{i32 6149, i32 0} + + +; CHECK-LLVM-NOT: @int_var = {{.*}}, !spirv.Decorations ![[#IGNORE6:]] +; CHECK-LLVM-NOT: @float_var = {{.*}}, !spirv.Decorations ![[#IGNORE7:]] +; CHECK-LLVM-NOT: @bool_var = {{.*}}, !spirv.Decorations ![[#IGNORE8:]] + +; CHECK-LLVM: @int_var = addrspace(1) global i32 42 +; CHECK-LLVM: @float_var = addrspace(1) global float 1.000000e+00 +; CHECK-LLVM: @bool_var = addrspace(1) global i1 false