From a0e8f1ebee037c9ad1c70e371503218086472940 Mon Sep 17 00:00:00 2001 From: Nick Sarnie Date: Mon, 16 Oct 2023 11:01:08 +0000 Subject: [PATCH] [PATCH 69/79] [Backport to 15] Backport spirv-preserve-auxdata changes (#2180) Backport the below changes to 15: f729c49 89d658c 9823690 d498f48 d24b9c6 I made the following changes that are not in the original changes: Use llvm::Optional instead of std::optional Port tests to not use opaque pointers and related flags Fix patch fail due to missing unrelated function in this branch Signed-off-by: Sarnie, Nick Gbp-Pq: Name 0069-Backport-to-15-Backport-spirv-preserve-auxdata-chang.patch --- include/LLVMSPIRVOpts.h | 17 +++- lib/SPIRV/SPIRVReader.cpp | 67 +++++++++++++++ lib/SPIRV/SPIRVReader.h | 1 + lib/SPIRV/SPIRVWriter.cpp | 83 +++++++++++++++++++ lib/SPIRV/SPIRVWriter.h | 2 + lib/SPIRV/libSPIRV/NonSemantic.AuxData.h | 33 ++++++++ lib/SPIRV/libSPIRV/SPIRVEnum.h | 2 + lib/SPIRV/libSPIRV/SPIRVExtInst.h | 11 +++ lib/SPIRV/libSPIRV/SPIRVInstruction.h | 17 +++- lib/SPIRV/libSPIRV/SPIRVModule.cpp | 18 +++- lib/SPIRV/libSPIRV/SPIRVModule.h | 8 ++ lib/SPIRV/libSPIRV/SPIRVStream.cpp | 1 + lib/SPIRV/libSPIRV/SPIRVStream.h | 1 + ...eserve-all-function-attributes-attrkind.ll | 26 ++++++ .../preserve-all-function-attributes-crash.ll | 23 +++++ .../preserve-all-function-attributes.ll | 43 ++++++++++ .../preserve-all-function-metadata-debug.ll | 28 +++++++ .../preserve-all-function-metadata.ll | 47 +++++++++++ tools/llvm-spirv/llvm-spirv.cpp | 17 +++- 19 files changed, 439 insertions(+), 6 deletions(-) create mode 100644 lib/SPIRV/libSPIRV/NonSemantic.AuxData.h create mode 100644 test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-attrkind.ll create mode 100644 test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-crash.ll create mode 100644 test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes.ll create mode 100644 test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata-debug.ll create mode 100644 test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata.ll diff --git a/include/LLVMSPIRVOpts.h b/include/LLVMSPIRVOpts.h index 7d1f11f..fa1df5f 100644 --- a/include/LLVMSPIRVOpts.h +++ b/include/LLVMSPIRVOpts.h @@ -90,7 +90,9 @@ enum class DebugInfoEIS : uint32_t { /// \brief Helper class to manage SPIR-V translation class TranslatorOpts { public: - using ExtensionsStatusMap = std::map; + // Unset optional means not directly specified by user + using ExtensionsStatusMap = std::map>; + using ArgList = llvm::SmallVector; TranslatorOpts() = default; @@ -107,11 +109,14 @@ public: if (ExtStatusMap.end() == I) return false; - return I->second; + return I->second && *I->second; } void setAllowedToUseExtension(ExtensionID Extension, bool Allow = true) { - ExtStatusMap[Extension] = Allow; + // Only allow using the extension if it has not already been disabled + auto I = ExtStatusMap.find(Extension); + if (I == ExtStatusMap.end() || !I->second || (*I->second) == true) + ExtStatusMap[Extension] = Allow; } VersionNumber getMaxVersion() const { return MaxVersion; } @@ -122,6 +127,10 @@ public: void setMemToRegEnabled(bool Mem2Reg) { SPIRVMemToReg = Mem2Reg; } + bool preserveAuxData() const { return PreserveAuxData; } + + void setPreserveAuxData(bool ArgValue) { PreserveAuxData = ArgValue; } + void setGenKernelArgNameMDEnabled(bool ArgNameMD) { GenKernelArgNameMD = ArgNameMD; } @@ -230,6 +239,8 @@ private: // Add a workaround to preserve OpenCL kernel_arg_type and // kernel_arg_type_qual metadata through OpString bool PreserveOCLKernelArgTypeMetadataThroughString = false; + + bool PreserveAuxData = false; }; } // namespace SPIRV diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index 33a9a89..a4c271e 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -3380,10 +3380,16 @@ bool SPIRVToLLVM::translate() { if (!postProcessBuiltinsReturningStruct(M, IsCpp)) return false; } + + for (SPIRVExtInst *EI : BM->getAuxDataInstVec()) { + transAuxDataInst(EI); + } + eraseUselessFunctions(M); DbgTran->addDbgInfoVersion(); DbgTran->finalize(); + return true; } @@ -4438,6 +4444,67 @@ Instruction *SPIRVToLLVM::transOCLBuiltinFromExtInst(SPIRVExtInst *BC, return CI; } +void SPIRVToLLVM::transAuxDataInst(SPIRVExtInst *BC) { + assert(BC->getExtSetKind() == SPIRV::SPIRVEIS_NonSemantic_AuxData); + if (!BC->getModule()->preserveAuxData()) + return; + auto Args = BC->getArguments(); + // Args 0 and 1 are common between attributes and metadata. + // 0 is the function, 1 is the name of the attribute/metadata as a string + auto *SpvFcn = BC->getModule()->getValue(Args[0]); + auto *F = static_cast(getTranslatedValue(SpvFcn)); + assert(F && "Function should already have been translated!"); + auto AttrOrMDName = BC->getModule()->get(Args[1])->getStr(); + switch (BC->getExtOp()) { + case NonSemanticAuxData::FunctionAttribute: { + assert(Args.size() < 4 && "Unexpected FunctionAttribute Args"); + // If this attr was specially handled and added elsewhere, skip it. + const Attribute::AttrKind AsKind = + Attribute::getAttrKindFromName(AttrOrMDName); + if (AsKind != Attribute::None && F->hasFnAttribute(AsKind)) + return; + if (AsKind == Attribute::None && F->hasFnAttribute(AttrOrMDName)) + return; + // For attributes, arg 2 is the attribute value as a string, which may not + // exist. + if (Args.size() == 3) { + auto AttrValue = BC->getModule()->get(Args[2])->getStr(); + F->addFnAttr(AttrOrMDName, AttrValue); + } else { + if (AsKind != Attribute::None) + F->addFnAttr(AsKind); + else + F->addFnAttr(AttrOrMDName); + } + break; + } + case NonSemanticAuxData::FunctionMetadata: { + // If this metadata was specially handled and added elsewhere, skip it. + if (F->hasMetadata(AttrOrMDName)) + return; + SmallVector MetadataArgs; + // Process the metadata values. + for (size_t CurArg = 2; CurArg < Args.size(); CurArg++) { + auto *Arg = BC->getModule()->get(Args[CurArg]); + // For metadata, the metadata values can be either values or strings. + if (Arg->getOpCode() == OpString) { + auto *ArgAsStr = static_cast(Arg); + MetadataArgs.push_back( + MDString::get(F->getContext(), ArgAsStr->getStr())); + } else { + auto *ArgAsVal = static_cast(Arg); + auto *TranslatedMD = transValue(ArgAsVal, F, nullptr); + MetadataArgs.push_back(ValueAsMetadata::get(TranslatedMD)); + } + } + F->setMetadata(AttrOrMDName, MDNode::get(*Context, MetadataArgs)); + break; + } + default: + llvm_unreachable("Invalid op"); + } +} + // SPIR-V only contains language version. Use OpenCL language version as // SPIR version. void SPIRVToLLVM::transSourceLanguage() { diff --git a/lib/SPIRV/SPIRVReader.h b/lib/SPIRV/SPIRVReader.h index 5b03176..f1de7c6 100644 --- a/lib/SPIRV/SPIRVReader.h +++ b/lib/SPIRV/SPIRVReader.h @@ -95,6 +95,7 @@ public: bool transDecoration(SPIRVValue *, Value *); bool transAlign(SPIRVValue *, Value *); Instruction *transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB); + void transAuxDataInst(SPIRVExtInst *BC); std::vector transValue(const std::vector &, Function *F, BasicBlock *); Function *transFunction(SPIRVFunction *F); diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 34d0dd5..97af8e0 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -902,6 +902,8 @@ SPIRVFunction *LLVMToSPIRVBase::transFunctionDecl(Function *F) { transFPGAFunctionMetadata(BF, F); + transAuxDataInst(BF, F); + SPIRVDBG(dbgs() << "[transFunction] " << *F << " => "; spvdbgs() << *BF << '\n';) return BF; @@ -1026,6 +1028,82 @@ void LLVMToSPIRVBase::transFPGAFunctionMetadata(SPIRVFunction *BF, } } +void LLVMToSPIRVBase::transAuxDataInst(SPIRVFunction *BF, Function *F) { + auto *BM = BF->getModule(); + if (!BM->preserveAuxData()) + return; + BM->addExtension(SPIRV::ExtensionID::SPV_KHR_non_semantic_info); + const auto &FnAttrs = F->getAttributes().getFnAttrs(); + for (const auto &Attr : FnAttrs) { + std::vector Ops; + Ops.push_back(BF->getId()); + if (Attr.isStringAttribute()) { + // Format for String attributes is: + // NonSemanticAuxDataFunctionAttribute Fcn AttrName AttrValue + // or, if no value: + // NonSemanticAuxDataFunctionAttribute Fcn AttrName + // + // AttrName and AttrValue are always Strings + const StringRef AttrKind = Attr.getKindAsString(); + const StringRef AttrValue = Attr.getValueAsString(); + auto *KindSpvString = BM->getString(AttrKind.str()); + Ops.push_back(KindSpvString->getId()); + if (!AttrValue.empty()) { + auto *ValueSpvString = BM->getString(AttrValue.str()); + Ops.push_back(ValueSpvString->getId()); + } + } else { + // Format for other types is: + // NonSemanticAuxDataFunctionAttribute Fcn AttrStr + // AttrStr is always a String. + const std::string AttrStr = Attr.getAsString(); + auto *AttrSpvString = BM->getString(AttrStr); + Ops.push_back(AttrSpvString->getId()); + } + BM->addAuxData(NonSemanticAuxData::FunctionAttribute, + transType(Type::getVoidTy(F->getContext())), Ops); + } + SmallVector> AllMD; + SmallVector MDNames; + F->getContext().getMDKindNames(MDNames); + F->getAllMetadata(AllMD); + for (auto MD : AllMD) { + const std::string MDName = MDNames[MD.first].str(); + + // spirv.Decorations, spirv.ParameterDecorations and debug information are + // handled elsewhere for both forward and reverse translation and are + // complicated to support here, so just skip them. + if (MDName == SPIRV_MD_DECORATIONS || + MDName == SPIRV_MD_PARAMETER_DECORATIONS || + MD.first == LLVMContext::MD_dbg) + continue; + + // Format for metadata is: + // NonSemanticAuxDataFunctionMetadata Fcn MDName MDVals... + // MDName is always a String, MDVals have different types as explained + // below. Also note this instruction has a variable number of operands + std::vector Ops; + Ops.push_back(BF->getId()); + Ops.push_back(BM->getString(MDName)->getId()); + for (unsigned int OpIdx = 0; OpIdx < MD.second->getNumOperands(); OpIdx++) { + const auto &CurOp = MD.second->getOperand(OpIdx); + if (auto *MDStr = dyn_cast(CurOp)) { + // For MDString, MDVal is String + auto *SPIRVStr = BM->getString(MDStr->getString().str()); + Ops.push_back(SPIRVStr->getId()); + } else if (auto *ValueAsMeta = dyn_cast(CurOp)) { + // For Value metadata, MDVal is a SPIRVValue + auto *SPIRVVal = transValue(ValueAsMeta->getValue(), nullptr); + Ops.push_back(SPIRVVal->getId()); + } else { + assert(false && "Unsupported metadata type"); + } + } + BM->addAuxData(NonSemanticAuxData::FunctionMetadata, + transType(Type::getVoidTy(F->getContext())), Ops); + } +} + SPIRVValue *LLVMToSPIRVBase::transConstant(Value *V) { if (auto CPNull = dyn_cast(V)) return BM->addNullConstant( @@ -2613,6 +2691,11 @@ bool LLVMToSPIRVBase::transBuiltinSet() { SPIRVBuiltinSetNameMap::map(BM->getDebugInfoEIS()), &EISId)) return false; } + if (BM->preserveAuxData()) { + if (!BM->importBuiltinSet( + SPIRVBuiltinSetNameMap::map(SPIRVEIS_NonSemantic_AuxData), &EISId)) + return false; + } return true; } diff --git a/lib/SPIRV/SPIRVWriter.h b/lib/SPIRV/SPIRVWriter.h index e96e1ad..b0982c0 100644 --- a/lib/SPIRV/SPIRVWriter.h +++ b/lib/SPIRV/SPIRVWriter.h @@ -121,6 +121,8 @@ public: SPIRVFunction *transFunctionDecl(Function *F); void transVectorComputeMetadata(Function *F); void transFPGAFunctionMetadata(SPIRVFunction *BF, Function *F); + void transAuxDataInst(SPIRVFunction *BF, Function *F); + bool transGlobalVariables(); Op transBoolOpCode(SPIRVValue *Opn, Op OC); diff --git a/lib/SPIRV/libSPIRV/NonSemantic.AuxData.h b/lib/SPIRV/libSPIRV/NonSemantic.AuxData.h new file mode 100644 index 0000000..240734a --- /dev/null +++ b/lib/SPIRV/libSPIRV/NonSemantic.AuxData.h @@ -0,0 +1,33 @@ +/* +** Copyright (c) 2023 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +namespace NonSemanticAuxData { +enum Instruction { + FunctionMetadata = 0, + FunctionAttribute = 1, + PreserveCount = 2 +}; +} // namespace NonSemanticAuxData diff --git a/lib/SPIRV/libSPIRV/SPIRVEnum.h b/lib/SPIRV/libSPIRV/SPIRVEnum.h index 269804f..1bd5cc7 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -80,6 +80,7 @@ enum SPIRVExtInstSetKind { SPIRVEIS_OpenCL_DebugInfo_100, SPIRVEIS_NonSemantic_Shader_DebugInfo_100, SPIRVEIS_NonSemantic_Shader_DebugInfo_200, + SPIRVEIS_NonSemantic_AuxData, SPIRVEIS_Count, }; @@ -135,6 +136,7 @@ template <> inline void SPIRVMap::init() { "NonSemantic.Shader.DebugInfo.100"); add(SPIRVEIS_NonSemantic_Shader_DebugInfo_200, "NonSemantic.Shader.DebugInfo.200"); + add(SPIRVEIS_NonSemantic_AuxData, "NonSemantic.AuxData"); } typedef SPIRVMap SPIRVBuiltinSetNameMap; diff --git a/lib/SPIRV/libSPIRV/SPIRVExtInst.h b/lib/SPIRV/libSPIRV/SPIRVExtInst.h index e278726..693d8da 100644 --- a/lib/SPIRV/libSPIRV/SPIRVExtInst.h +++ b/lib/SPIRV/libSPIRV/SPIRVExtInst.h @@ -40,6 +40,7 @@ #ifndef SPIRV_LIBSPIRV_SPIRVEXTINST_H #define SPIRV_LIBSPIRV_SPIRVEXTINST_H +#include "NonSemantic.AuxData.h" #include "OpenCL.std.h" #include "SPIRV.debug.h" #include "SPIRVEnum.h" @@ -270,6 +271,16 @@ template <> inline void SPIRVMap::init() { } SPIRV_DEF_NAMEMAP(SPIRVDebugExtOpKind, SPIRVDebugExtOpMap) +typedef NonSemanticAuxData::Instruction NonSemanticAuxDataOpKind; +template <> +inline void SPIRVMap::init() { + add(NonSemanticAuxData::FunctionMetadata, + "NonSemanticAuxDataFunctionMetadata"); + add(NonSemanticAuxData::FunctionAttribute, + "NonSemanticAuxDataFunctionAttribute"); +} +SPIRV_DEF_NAMEMAP(NonSemanticAuxDataOpKind, NonSemanticAuxDataOpMap) + } // namespace SPIRV #endif // SPIRV_LIBSPIRV_SPIRVEXTINST_H diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/lib/SPIRV/libSPIRV/SPIRVInstruction.h index f7b57d0..bd5b338 100644 --- a/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -42,6 +42,7 @@ #include "SPIRVBasicBlock.h" #include "SPIRVEnum.h" +#include "SPIRVFunction.h" #include "SPIRVIsValidEnum.h" #include "SPIRVOpCode.h" #include "SPIRVStream.h" @@ -1771,7 +1772,8 @@ public: assert((ExtSetKind == SPIRVEIS_OpenCL || ExtSetKind == SPIRVEIS_Debug || ExtSetKind == SPIRVEIS_OpenCL_DebugInfo_100 || ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_100 || - ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_200) && + ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_200 || + ExtSetKind == SPIRVEIS_NonSemantic_AuxData) && "not supported"); } void encode(spv_ostream &O) const override { @@ -1786,6 +1788,9 @@ public: case SPIRVEIS_NonSemantic_Shader_DebugInfo_200: getEncoder(O) << ExtOpDebug; break; + case SPIRVEIS_NonSemantic_AuxData: + getEncoder(O) << ExtOpNonSemanticAuxData; + break; default: assert(0 && "not supported"); getEncoder(O) << ExtOp; @@ -1805,6 +1810,9 @@ public: case SPIRVEIS_NonSemantic_Shader_DebugInfo_200: getDecoder(I) >> ExtOpDebug; break; + case SPIRVEIS_NonSemantic_AuxData: + getDecoder(I) >> ExtOpNonSemanticAuxData; + break; default: assert(0 && "not supported"); getDecoder(I) >> ExtOp; @@ -1860,6 +1868,12 @@ public: return ArgTypes; } + llvm::Optional getRequiredExtension() const override { + if (SPIRVBuiltinSetNameMap::map(ExtSetKind).find("NonSemantic.") == 0) + return ExtensionID::SPV_KHR_non_semantic_info; + return {}; + } + protected: SPIRVExtInstSetKind ExtSetKind; SPIRVId ExtSetId; @@ -1867,6 +1881,7 @@ protected: SPIRVWord ExtOp; OCLExtOpKind ExtOpOCL; SPIRVDebugExtOpKind ExtOpDebug; + NonSemanticAuxDataOpKind ExtOpNonSemanticAuxData; }; std::vector ContinuedInstructions; }; diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/lib/SPIRV/libSPIRV/SPIRVModule.cpp index df64f16..ea05680 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -143,6 +143,9 @@ public: const std::vector &getDebugInstVec() const override { return DebugInstVec; } + const std::vector &getAuxDataInstVec() const override { + return AuxDataInstVec; + } const std::vector &getStringVec() const override { return StringVec; } @@ -304,6 +307,8 @@ public: const std::vector &) override; SPIRVEntry *addDebugInfo(SPIRVWord, SPIRVType *TheType, const std::vector &) override; + SPIRVEntry *addAuxData(SPIRVWord, SPIRVType *TheType, + const std::vector &) override; SPIRVEntry *addModuleProcessed(const std::string &) override; std::vector getModuleProcessedVec() override; SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *, SPIRVValue *, @@ -529,6 +534,7 @@ private: std::map IntTypeMap; std::map LiteralMap; std::vector DebugInstVec; + std::vector AuxDataInstVec; std::vector ModuleProcessedVec; SPIRVAliasInstMDVec AliasInstMDVec; SPIRVAliasInstMDMap AliasInstMDMap; @@ -715,6 +721,8 @@ void SPIRVModuleImpl::layoutEntry(SPIRVEntry *E) { EI->getExtOp() != SPIRVDebug::NoScope) { DebugInstVec.push_back(EI); } + if (EI->getExtSetKind() == SPIRVEIS_NonSemantic_AuxData) + AuxDataInstVec.push_back(EI); break; } case OpAsmTargetINTEL: { @@ -1374,6 +1382,13 @@ SPIRVEntry *SPIRVModuleImpl::addDebugInfo(SPIRVWord InstId, SPIRVType *TheType, return addEntry(createDebugInfo(InstId, TheType, Args)); } +SPIRVEntry *SPIRVModuleImpl::addAuxData(SPIRVWord InstId, SPIRVType *TheType, + const std::vector &Args) { + return addEntry(new SPIRVExtInst( + this, getId(), TheType, SPIRVEIS_NonSemantic_AuxData, + getExtInstSetId(SPIRVEIS_NonSemantic_AuxData), InstId, Args)); +} + SPIRVEntry *SPIRVModuleImpl::addModuleProcessed(const std::string &Process) { ModuleProcessedVec.push_back(new SPIRVModuleProcessed(this, Process)); return ModuleProcessedVec.back(); @@ -1968,7 +1983,8 @@ spv_ostream &operator<<(spv_ostream &O, SPIRVModule &M) { }), MI.DebugInstVec.end()); - O << SPIRVNL() << MI.DebugInstVec << SPIRVNL() << MI.FuncVec; + O << SPIRVNL() << MI.DebugInstVec << MI.AuxDataInstVec << SPIRVNL() + << MI.FuncVec; return O; } diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.h b/lib/SPIRV/libSPIRV/SPIRVModule.h index b7a09cf..0f09a41 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -157,6 +157,8 @@ public: virtual unsigned short getGeneratorVer() const = 0; virtual SPIRVWord getSPIRVVersion() const = 0; virtual const std::vector &getDebugInstVec() const = 0; + virtual const std::vector &getAuxDataInstVec() const = 0; + virtual const std::vector &getStringVec() const = 0; // Module changing functions @@ -319,6 +321,8 @@ public: const std::vector &) = 0; virtual SPIRVEntry *addDebugInfo(SPIRVWord, SPIRVType *, const std::vector &) = 0; + virtual SPIRVEntry *addAuxData(SPIRVWord, SPIRVType *, + const std::vector &) = 0; virtual SPIRVEntry *addModuleProcessed(const std::string &) = 0; virtual void addCapability(SPIRVCapabilityKind) = 0; template void addCapabilities(const T &Caps) { @@ -532,6 +536,10 @@ public: .shouldPreserveOCLKernelArgTypeMetadataThroughString(); } + bool preserveAuxData() const noexcept { + return TranslationOpts.preserveAuxData(); + } + SPIRVExtInstSetKind getDebugInfoEIS() const { switch (TranslationOpts.getDebugInfoEIS()) { case DebugInfoEIS::SPIRV_Debug: diff --git a/lib/SPIRV/libSPIRV/SPIRVStream.cpp b/lib/SPIRV/libSPIRV/SPIRVStream.cpp index b30dbe2..65ca5cb 100644 --- a/lib/SPIRV/libSPIRV/SPIRVStream.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVStream.cpp @@ -144,6 +144,7 @@ SPIRV_DEF_ENCDEC(Capability) SPIRV_DEF_ENCDEC(Decoration) SPIRV_DEF_ENCDEC(OCLExtOpKind) SPIRV_DEF_ENCDEC(SPIRVDebugExtOpKind) +SPIRV_DEF_ENCDEC(NonSemanticAuxDataOpKind) SPIRV_DEF_ENCDEC(LinkageType) // Read a string with padded 0's at the end so that they form a stream of diff --git a/lib/SPIRV/libSPIRV/SPIRVStream.h b/lib/SPIRV/libSPIRV/SPIRVStream.h index 9f74628..cd3e06e 100644 --- a/lib/SPIRV/libSPIRV/SPIRVStream.h +++ b/lib/SPIRV/libSPIRV/SPIRVStream.h @@ -228,6 +228,7 @@ SPIRV_DEC_ENCDEC(Capability) SPIRV_DEC_ENCDEC(Decoration) SPIRV_DEC_ENCDEC(OCLExtOpKind) SPIRV_DEC_ENCDEC(SPIRVDebugExtOpKind) +SPIRV_DEC_ENCDEC(NonSemanticAuxDataOpKind) SPIRV_DEC_ENCDEC(LinkageType) const SPIRVEncoder &operator<<(const SPIRVEncoder &O, const std::string &Str); diff --git a/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-attrkind.ll b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-attrkind.ll new file mode 100644 index 0000000..143c86f --- /dev/null +++ b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-attrkind.ll @@ -0,0 +1,26 @@ +; RUN: llvm-as < %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text --spirv-preserve-auxdata -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv --spirv-preserve-auxdata +; RUN: llvm-spirv -r --spirv-preserve-auxdata %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: Extension "SPV_KHR_non_semantic_info" +; CHECK-SPIRV: ExtInstImport [[#Import:]] "NonSemantic.AuxData" + +; CHECK-SPIRV: String [[#Attr0:]] "nounwind" + +; CHECK-SPIRV: Name [[#Fcn0:]] "foo" + +; CHECK-SPIRV: TypeVoid [[#VoidT:]] + +; CHECK-SPIRV: ExtInst [[#VoidT]] [[#Attr0Inst:]] [[#Import]] NonSemanticAuxDataFunctionAttribute [[#Fcn0]] [[#Attr0]] {{$}} + +target triple = "spir64-unknown-unknown" + +; CHECK-LLVM: define spir_func void @foo() #[[#Fcn0IRAttr:]] +define spir_func void @foo() #0 { +entry: +ret void +} +; CHECK-LLVM: attributes #[[#Fcn0IRAttr]] = { nounwind } +attributes #0 = { nounwind } diff --git a/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-crash.ll b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-crash.ll new file mode 100644 index 0000000..5ad5aa1 --- /dev/null +++ b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-crash.ll @@ -0,0 +1,23 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-preserve-auxdata --spirv-text -spirv-allow-unknown-intrinsics=llvm.genx. -o %t.txt +; RUN: llvm-spirv --spirv-preserve-auxdata --spirv-target-env=SPV-IR --spirv-text -r %t.txt -o %t.bc +; RUN: llvm-dis %t.bc -o %t.ll +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: FileCheck < %t.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-n8:16:32:64" +target triple = "spir-unknown-unknown" + +; CHECK-LLVM: define spir_kernel void @test_array +define spir_kernel void @test_array(i8 addrspace(1)* %in, i8 addrspace(1)* %out) { + call void @llvm.memmove.p1i8.p1i8.i32(i8 addrspace(1)* %out, i8 addrspace(1)* %in, i32 72, i1 false) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.memmove.p1i8.p1i8.i32(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i32, i1) #0 +; CHECK-SPIRV: Name [[#ID:]] "llvm.memmove.p1i8.p1i8.i32" +; CHECK-LLVM-NOT: llvm.memmove + +; CHECK-LLVM: attributes #0 = { nounwind } +attributes #0 = { nounwind } diff --git a/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes.ll b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes.ll new file mode 100644 index 0000000..193af4b --- /dev/null +++ b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes.ll @@ -0,0 +1,43 @@ +; RUN: llvm-as < %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text --spirv-preserve-auxdata -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: not llvm-spirv %t.bc -spirv-text --spirv-preserve-auxdata --spirv-ext=-SPV_KHR_non_semantic_info -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SPIRV-EXT-DISABLED +; RUN: llvm-spirv %t.bc -o %t.spv --spirv-preserve-auxdata +; RUN: llvm-spirv -r --spirv-preserve-auxdata %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM +; RUN: llvm-spirv -r %t.spv -o %t.rev.without.bc +; RUN: llvm-dis %t.rev.without.bc -o - | FileCheck %s --implicit-check-not="{{foo|bar|baz}}" + +; CHECK-SPIRV: Extension "SPV_KHR_non_semantic_info" +; CHECK-SPIRV: ExtInstImport [[#Import:]] "NonSemantic.AuxData" + +; CHECK-SPIRV: String [[#Attr0:]] "foo" +; CHECK-SPIRV: String [[#Attr1LHS:]] "bar" +; CHECK-SPIRV: String [[#Attr1RHS:]] "baz" + +; CHECK-SPIRV: Name [[#Fcn0:]] "mul_add" +; CHECK-SPIRV: Name [[#Fcn1:]] "test" + +; CHECK-SPIRV: TypeVoid [[#VoidT:]] + +; CHECK-SPIRV: ExtInst [[#VoidT]] [[#Attr0Inst:]] [[#Import]] NonSemanticAuxDataFunctionAttribute [[#Fcn0]] [[#Attr0]] {{$}} +; CHECK-SPIRV: ExtInst [[#VoidT]] [[#Attr1Inst:]] [[#Import]] NonSemanticAuxDataFunctionAttribute [[#Fcn1]] [[#Attr1LHS]] [[#Attr1RHS]] {{$}} + +target triple = "spir64-unknown-unknown" + +; CHECK-LLVM: declare spir_func void @mul_add() #[[#Fcn0IRAttr:]] +declare spir_func void @mul_add() #0 + +; CHECK-LLVM: define spir_func void @test() #[[#Fcn1IRAttr:]] +define spir_func void @test() #1 { +entry: + call spir_func void @mul_add() +ret void +} + +; CHECK-LLVM: attributes #[[#Fcn0IRAttr]] = { {{.*}}"foo" } +attributes #0 = { "foo" } +; CHECK-LLVM: attributes #[[#Fcn1IRAttr]] = { {{.*}}"bar"="baz" } +attributes #1 = { "bar"="baz" } + +; CHECK-SPIRV-EXT-DISABLED: RequiresExtension: Feature requires the following SPIR-V extension: +; CHECK-SPIRV-EXT-DISABLED-NEXT: SPV_KHR_non_semantic_info diff --git a/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata-debug.ll b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata-debug.ll new file mode 100644 index 0000000..7ce005e --- /dev/null +++ b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata-debug.ll @@ -0,0 +1,28 @@ +; RUN: llvm-as < %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text --spirv-preserve-auxdata -o - | FileCheck %s --check-prefix=CHECK-SPIRV + +; CHECK-SPIRV: Capability +; CHECK-SPIRV-NOT: NonSemanticAuxData +; CHECK-SPIRV: FunctionEnd +target triple = "spir64-unknown-unknown" + +define spir_func void @foo() #1 !dbg !4 { +ret void +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang 16.0.0", isOptimized: false, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "foo.c", directory: "./") +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !5) +!5 = !{!9} +!6 = !DISubroutineType(types: !7) +!7 = !{!8, !8, !8} +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DILabel(scope: !4, name: "top", file: !1, line: 4) +!10 = !DILocation(line: 4, column: 1, scope: !4) +!11 = !DILabel(scope: !4, name: "done", file: !1, line: 7) +!12 = !DILocation(line: 7, column: 1, scope: !4) diff --git a/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata.ll b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata.ll new file mode 100644 index 0000000..abc0a04 --- /dev/null +++ b/test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata.ll @@ -0,0 +1,47 @@ +; RUN: llvm-as < %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text --spirv-preserve-auxdata -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv --spirv-preserve-auxdata +; RUN: llvm-spirv -r --spirv-preserve-auxdata %t.spv -o %t.rev.bc +; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM +; RUN: llvm-spirv -r %t.spv -o %t.rev.without.bc +; RUN: llvm-dis %t.rev.without.bc -o - | FileCheck %s --implicit-check-not="{{foo|bar|baz}}" + +; CHECK-SPIRV: Extension "SPV_KHR_non_semantic_info" +; CHECK-SPIRV: ExtInstImport [[#Import:]] "NonSemantic.AuxData" + +; CHECK-SPIRV: String [[#MD0Name:]] "foo" +; CHECK-SPIRV: String [[#MD1Name:]] "bar" +; CHECK-SPIRV: String [[#MD1Value:]] "baz" + +; CHECK-SPIRV: Name [[#Fcn0:]] "test_val" +; CHECK-SPIRV: Name [[#Fcn1:]] "test_string" + +; CHECK-SPIRV: TypeInt [[#Int32T:]] 32 0 +; CHECK-SPIRV: Constant [[#Int32T]] [[#MD0Value:]] 5 + +; CHECK-SPIRV: TypeVoid [[#VoidT:]] + +; CHECK-SPIRV: ExtInst [[#VoidT]] [[#ValInst:]] [[#Import]] NonSemanticAuxDataFunctionMetadata [[#Fcn0]] [[#MD0Name]] [[#MD0Value]] {{$}} +; CHECK-SPIRV: ExtInst [[#VoidT]] [[#StrInst:]] [[#Import]] NonSemanticAuxDataFunctionMetadata [[#Fcn1]] [[#MD1Name]] [[#MD1Value]] {{$}} + +target triple = "spir64-unknown-unknown" + +; CHECK-LLVM: define spir_func void @test_val() {{.*}} !foo ![[#LLVMVal:]] +define spir_func void @test_val() #1 !foo !1 { +ret void +} + +; CHECK-LLVM: define spir_func void @test_string() {{.*}} !bar ![[#LLVMStr:]] +define spir_func void @test_string() #1 !bar !2 !spirv.Decorations !4 !spirv.ParameterDecorations !3 { +ret void +} + +; CHECK-LLVM: ![[#LLVMVal]] = !{i32 5} +!1 = !{i32 5} +; CHECK-LLVM ![[#LLVMSTR]] = !{!"baz"} +!2 = !{!"baz"} +!3 = !{!4, !7, !4} +!4 = !{!5, !6} +!5 = !{i32 0, i32 2} +!6 = !{i32 0, i32 8} +!7 = !{!6} diff --git a/tools/llvm-spirv/llvm-spirv.cpp b/tools/llvm-spirv/llvm-spirv.cpp index 85d4e61..cfbd9d0 100644 --- a/tools/llvm-spirv/llvm-spirv.cpp +++ b/tools/llvm-spirv/llvm-spirv.cpp @@ -190,6 +190,10 @@ static cl::opt SPIRVMemToReg("spirv-mem2reg", cl::init(false), cl::desc("LLVM/SPIR-V translation enable mem2reg")); +static cl::opt SPIRVPreserveAuxData( + "spirv-preserve-auxdata", cl::init(false), + cl::desc("Preserve all auxiliary data, such as function attributes and metadata")); + static cl::opt SpecConstInfo( "spec-const-info", cl::desc("Display id of constants available for specializaion and their " @@ -496,8 +500,11 @@ static int parseSPVExtOption( // - during SPIR-V generation, assume that any known extension is disallowed. // - during conversion to/from SPIR-V text representation, assume that any // known extension is allowed. + llvm::Optional DefaultVal; + if (IsReverse) + DefaultVal = true; for (const auto &It : ExtensionNamesMap) - ExtensionsStatus[It.second] = IsReverse; + ExtensionsStatus[It.second] = DefaultVal; if (SPVExt.empty()) return 0; // Nothing to do @@ -699,6 +706,14 @@ int main(int Ac, char **Av) { return -1; } + if (SPIRVPreserveAuxData) { + Opts.setPreserveAuxData( + SPIRVPreserveAuxData); + if (!IsReverse) + Opts.setAllowedToUseExtension( + SPIRV::ExtensionID::SPV_KHR_non_semantic_info); + } + if (SPIRVAllowUnknownIntrinsics.getNumOccurrences() != 0) { if (IsReverse) { errs() -- 2.30.2