[PATCH 69/79] [Backport to 15] Backport spirv-preserve-auxdata changes (#2180)
authorNick Sarnie <sarnex@users.noreply.github.com>
Mon, 16 Oct 2023 11:01:08 +0000 (11:01 +0000)
committerAndreas Beckmann <anbe@debian.org>
Thu, 8 Feb 2024 21:48:18 +0000 (22:48 +0100)
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 <nick.sarnie@intel.com>
Gbp-Pq: Name 0069-Backport-to-15-Backport-spirv-preserve-auxdata-chang.patch

19 files changed:
include/LLVMSPIRVOpts.h
lib/SPIRV/SPIRVReader.cpp
lib/SPIRV/SPIRVReader.h
lib/SPIRV/SPIRVWriter.cpp
lib/SPIRV/SPIRVWriter.h
lib/SPIRV/libSPIRV/NonSemantic.AuxData.h [new file with mode: 0644]
lib/SPIRV/libSPIRV/SPIRVEnum.h
lib/SPIRV/libSPIRV/SPIRVExtInst.h
lib/SPIRV/libSPIRV/SPIRVInstruction.h
lib/SPIRV/libSPIRV/SPIRVModule.cpp
lib/SPIRV/libSPIRV/SPIRVModule.h
lib/SPIRV/libSPIRV/SPIRVStream.cpp
lib/SPIRV/libSPIRV/SPIRVStream.h
test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-attrkind.ll [new file with mode: 0644]
test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes-crash.ll [new file with mode: 0644]
test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-attributes.ll [new file with mode: 0644]
test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata-debug.ll [new file with mode: 0644]
test/extensions/KHR/SPV_KHR_non_semantic_info/preserve-all-function-metadata.ll [new file with mode: 0644]
tools/llvm-spirv/llvm-spirv.cpp

index 7d1f11ff409321431dc51a92be8827a431f2ae28..fa1df5fd3645d0a935300fd0870da92466eff0a3 100644 (file)
@@ -90,7 +90,9 @@ enum class DebugInfoEIS : uint32_t {
 /// \brief Helper class to manage SPIR-V translation
 class TranslatorOpts {
 public:
-  using ExtensionsStatusMap = std::map<ExtensionID, bool>;
+  // Unset optional means not directly specified by user
+  using ExtensionsStatusMap = std::map<ExtensionID, llvm::Optional<bool>>;
+
   using ArgList = llvm::SmallVector<llvm::StringRef, 4>;
 
   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
index 33a9a893527e4973310b746537a5d43ed203a8e9..a4c271ed6b0dbcf7f3b1a4da70a36d852754d2e7 100644 (file)
@@ -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<Function *>(getTranslatedValue(SpvFcn));
+  assert(F && "Function should already have been translated!");
+  auto AttrOrMDName = BC->getModule()->get<SPIRVString>(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<SPIRVString>(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<Metadata *> MetadataArgs;
+    // Process the metadata values.
+    for (size_t CurArg = 2; CurArg < Args.size(); CurArg++) {
+      auto *Arg = BC->getModule()->get<SPIRVEntry>(Args[CurArg]);
+      // For metadata, the metadata values can be either values or strings.
+      if (Arg->getOpCode() == OpString) {
+        auto *ArgAsStr = static_cast<SPIRVString *>(Arg);
+        MetadataArgs.push_back(
+            MDString::get(F->getContext(), ArgAsStr->getStr()));
+      } else {
+        auto *ArgAsVal = static_cast<SPIRVValue *>(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() {
index 5b031765bacf8cd6b8ffa6ba960bfef90661f775..f1de7c6f52655fc2b0907ebd9b094d3e6a5c8a23 100644 (file)
@@ -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<Value *> transValue(const std::vector<SPIRVValue *> &,
                                   Function *F, BasicBlock *);
   Function *transFunction(SPIRVFunction *F);
index 34d0dd57fe3ebf7eba244c084d9a11ccae4cb030..97af8e04255751915434544d2dd5e5f4adfa1ab7 100644 (file)
@@ -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<SPIRVWord> 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<std::pair<unsigned, MDNode *>> AllMD;
+  SmallVector<StringRef> 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<SPIRVWord> 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<MDString>(CurOp)) {
+        // For MDString, MDVal is String
+        auto *SPIRVStr = BM->getString(MDStr->getString().str());
+        Ops.push_back(SPIRVStr->getId());
+      } else if (auto *ValueAsMeta = dyn_cast<ValueAsMetadata>(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<ConstantPointerNull>(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;
 }
 
index e96e1ad08c3d269eb72fe896523ea1cefd4a8ca0..b0982c0478922628d958be4892501aae41a1087d 100644 (file)
@@ -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 (file)
index 0000000..240734a
--- /dev/null
@@ -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
index 269804f551c996107e5c220bd59d3cc7b5a6bd90..1bd5cc7e40a96695773018294df0b022f0583c4f 100644 (file)
@@ -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<SPIRVExtInstSetKind, std::string>::init() {
       "NonSemantic.Shader.DebugInfo.100");
   add(SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
       "NonSemantic.Shader.DebugInfo.200");
+  add(SPIRVEIS_NonSemantic_AuxData, "NonSemantic.AuxData");
 }
 typedef SPIRVMap<SPIRVExtInstSetKind, std::string> SPIRVBuiltinSetNameMap;
 
index e278726f58c2b1baa83fdf85f24f4882805a3e2d..693d8dab6bcd14885151f0138d752cabf2a4edc9 100644 (file)
@@ -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<SPIRVDebugExtOpKind, std::string>::init() {
 }
 SPIRV_DEF_NAMEMAP(SPIRVDebugExtOpKind, SPIRVDebugExtOpMap)
 
+typedef NonSemanticAuxData::Instruction NonSemanticAuxDataOpKind;
+template <>
+inline void SPIRVMap<NonSemanticAuxDataOpKind, std::string>::init() {
+  add(NonSemanticAuxData::FunctionMetadata,
+      "NonSemanticAuxDataFunctionMetadata");
+  add(NonSemanticAuxData::FunctionAttribute,
+      "NonSemanticAuxDataFunctionAttribute");
+}
+SPIRV_DEF_NAMEMAP(NonSemanticAuxDataOpKind, NonSemanticAuxDataOpMap)
+
 } // namespace SPIRV
 
 #endif // SPIRV_LIBSPIRV_SPIRVEXTINST_H
index f7b57d0848edd3174a8caf2c59e0d7dd4c1cded3..bd5b338c5b3d85e4a5669b9723408904ec7df1b9 100644 (file)
@@ -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<ExtensionID> 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<SPIRVExtInst *> ContinuedInstructions;
 };
index df64f16749c5d8e018625cf94c19e4edfacd60f0..ea05680a7431befb8ba36ce327947b45df0f729c 100644 (file)
@@ -143,6 +143,9 @@ public:
   const std::vector<SPIRVExtInst *> &getDebugInstVec() const override {
     return DebugInstVec;
   }
+  const std::vector<SPIRVExtInst *> &getAuxDataInstVec() const override {
+    return AuxDataInstVec;
+  }
   const std::vector<SPIRVString *> &getStringVec() const override {
     return StringVec;
   }
@@ -304,6 +307,8 @@ public:
                               const std::vector<SPIRVWord> &) override;
   SPIRVEntry *addDebugInfo(SPIRVWord, SPIRVType *TheType,
                            const std::vector<SPIRVWord> &) override;
+  SPIRVEntry *addAuxData(SPIRVWord, SPIRVType *TheType,
+                         const std::vector<SPIRVWord> &) override;
   SPIRVEntry *addModuleProcessed(const std::string &) override;
   std::vector<SPIRVModuleProcessed *> getModuleProcessedVec() override;
   SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *, SPIRVValue *,
@@ -529,6 +534,7 @@ private:
   std::map<unsigned, SPIRVTypeInt *> IntTypeMap;
   std::map<unsigned, SPIRVConstant *> LiteralMap;
   std::vector<SPIRVExtInst *> DebugInstVec;
+  std::vector<SPIRVExtInst *> AuxDataInstVec;
   std::vector<SPIRVModuleProcessed *> 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<SPIRVWord> &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;
 }
 
index b7a09cfd5ecccb159640873cccd5438172912581..0f09a41a2c8dbdf83697037133bcdc544e5973d0 100644 (file)
@@ -157,6 +157,8 @@ public:
   virtual unsigned short getGeneratorVer() const = 0;
   virtual SPIRVWord getSPIRVVersion() const = 0;
   virtual const std::vector<SPIRVExtInst *> &getDebugInstVec() const = 0;
+  virtual const std::vector<SPIRVExtInst *> &getAuxDataInstVec() const = 0;
+
   virtual const std::vector<SPIRVString *> &getStringVec() const = 0;
 
   // Module changing functions
@@ -319,6 +321,8 @@ public:
                                       const std::vector<SPIRVWord> &) = 0;
   virtual SPIRVEntry *addDebugInfo(SPIRVWord, SPIRVType *,
                                    const std::vector<SPIRVWord> &) = 0;
+  virtual SPIRVEntry *addAuxData(SPIRVWord, SPIRVType *,
+                                 const std::vector<SPIRVWord> &) = 0;
   virtual SPIRVEntry *addModuleProcessed(const std::string &) = 0;
   virtual void addCapability(SPIRVCapabilityKind) = 0;
   template <typename T> 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:
index b30dbe2f3439f7c83888c5960a7deb1a43c2950e..65ca5cbb6123229a1bf87af85cd4d56938ebcb71 100644 (file)
@@ -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
index 9f746284e4efd6487994457002f347293ddbb86a..cd3e06e7d4bf0e816c4b1403042e586c4f2fa0d5 100644 (file)
@@ -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 (file)
index 0000000..143c86f
--- /dev/null
@@ -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 (file)
index 0000000..5ad5aa1
--- /dev/null
@@ -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 (file)
index 0000000..193af4b
--- /dev/null
@@ -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 (file)
index 0000000..7ce005e
--- /dev/null
@@ -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 (file)
index 0000000..abc0a04
--- /dev/null
@@ -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}
index 85d4e61d220ed9096a63ab284c974a29b590cdf3..cfbd9d090b43e4234f642d486257315802643448 100644 (file)
@@ -190,6 +190,10 @@ static cl::opt<bool>
     SPIRVMemToReg("spirv-mem2reg", cl::init(false),
                   cl::desc("LLVM/SPIR-V translation enable mem2reg"));
 
+static cl::opt<bool> SPIRVPreserveAuxData(
+    "spirv-preserve-auxdata", cl::init(false),
+    cl::desc("Preserve all auxiliary data, such as function attributes and metadata"));
+
 static cl::opt<bool> 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<bool> 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()