/// \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;
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; }
void setMemToRegEnabled(bool Mem2Reg) { SPIRVMemToReg = Mem2Reg; }
+ bool preserveAuxData() const { return PreserveAuxData; }
+
+ void setPreserveAuxData(bool ArgValue) { PreserveAuxData = ArgValue; }
+
void setGenKernelArgNameMDEnabled(bool ArgNameMD) {
GenKernelArgNameMD = ArgNameMD;
}
// 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
if (!postProcessBuiltinsReturningStruct(M, IsCpp))
return false;
}
+
+ for (SPIRVExtInst *EI : BM->getAuxDataInstVec()) {
+ transAuxDataInst(EI);
+ }
+
eraseUselessFunctions(M);
DbgTran->addDbgInfoVersion();
DbgTran->finalize();
+
return true;
}
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() {
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);
transFPGAFunctionMetadata(BF, F);
+ transAuxDataInst(BF, F);
+
SPIRVDBG(dbgs() << "[transFunction] " << *F << " => ";
spvdbgs() << *BF << '\n';)
return 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(
SPIRVBuiltinSetNameMap::map(BM->getDebugInfoEIS()), &EISId))
return false;
}
+ if (BM->preserveAuxData()) {
+ if (!BM->importBuiltinSet(
+ SPIRVBuiltinSetNameMap::map(SPIRVEIS_NonSemantic_AuxData), &EISId))
+ return false;
+ }
return true;
}
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);
--- /dev/null
+/*
+** 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
SPIRVEIS_OpenCL_DebugInfo_100,
SPIRVEIS_NonSemantic_Shader_DebugInfo_100,
SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
+ SPIRVEIS_NonSemantic_AuxData,
SPIRVEIS_Count,
};
"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;
#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"
}
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
#include "SPIRVBasicBlock.h"
#include "SPIRVEnum.h"
+#include "SPIRVFunction.h"
#include "SPIRVIsValidEnum.h"
#include "SPIRVOpCode.h"
#include "SPIRVStream.h"
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 {
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;
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;
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;
SPIRVWord ExtOp;
OCLExtOpKind ExtOpOCL;
SPIRVDebugExtOpKind ExtOpDebug;
+ NonSemanticAuxDataOpKind ExtOpNonSemanticAuxData;
};
std::vector<SPIRVExtInst *> ContinuedInstructions;
};
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;
}
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 *,
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;
EI->getExtOp() != SPIRVDebug::NoScope) {
DebugInstVec.push_back(EI);
}
+ if (EI->getExtSetKind() == SPIRVEIS_NonSemantic_AuxData)
+ AuxDataInstVec.push_back(EI);
break;
}
case OpAsmTargetINTEL: {
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();
}),
MI.DebugInstVec.end());
- O << SPIRVNL() << MI.DebugInstVec << SPIRVNL() << MI.FuncVec;
+ O << SPIRVNL() << MI.DebugInstVec << MI.AuxDataInstVec << SPIRVNL()
+ << MI.FuncVec;
return O;
}
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
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) {
.shouldPreserveOCLKernelArgTypeMetadataThroughString();
}
+ bool preserveAuxData() const noexcept {
+ return TranslationOpts.preserveAuxData();
+ }
+
SPIRVExtInstSetKind getDebugInfoEIS() const {
switch (TranslationOpts.getDebugInfoEIS()) {
case DebugInfoEIS::SPIRV_Debug:
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
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);
--- /dev/null
+; 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 }
--- /dev/null
+; 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 }
--- /dev/null
+; 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
--- /dev/null
+; 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)
--- /dev/null
+; 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}
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 "
// - 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
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()