| //===- SPIRVModule.cpp - Class to represent SPIR-V module --------*- C++ -*-===// |
| // |
| // The LLVM/SPIRV Translator |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the "Software"), |
| // to deal with the Software without restriction, including without limitation |
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| // and/or sell copies of the Software, and to permit persons to whom the |
| // Software is furnished to do so, subject to the following conditions: |
| // |
| // Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimers. |
| // Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimers in the documentation |
| // and/or other materials provided with the distribution. |
| // Neither the names of Advanced Micro Devices, Inc., nor the names of its |
| // contributors may be used to endorse or promote products derived from this |
| // Software without specific prior written permission. |
| // THE SOFTWARE IS 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 |
| // CONTRIBUTORS 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 SOFTWARE OR THE USE OR OTHER DEALINGS WITH |
| // THE SOFTWARE. |
| // |
| //===----------------------------------------------------------------------===// |
| /// \file |
| /// |
| /// This file implements Module class for SPIR-V. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "SPIRVModule.h" |
| #include "SPIRVDebug.h" |
| #include "SPIRVEntry.h" |
| #include "SPIRVType.h" |
| #include "SPIRVValue.h" |
| #include "SPIRVExtInst.h" |
| #include "SPIRVFunction.h" |
| #include "SPIRVInstruction.h" |
| #include "SPIRVStream.h" |
| |
| #include <set> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| namespace SPIRV{ |
| |
| SPIRVModule::SPIRVModule():AutoAddCapability(true), ValidateCapability(false) |
| {} |
| |
| SPIRVModule::~SPIRVModule() |
| {} |
| |
| class SPIRVModuleImpl : public SPIRVModule { |
| public: |
| SPIRVModuleImpl():SPIRVModule(), NextId(1), |
| SPIRVVersion(SPIRV_1_0), |
| GeneratorId(SPIRVGEN_KhronosLLVMSPIRVTranslator), |
| GeneratorVer(0), |
| InstSchema(SPIRVISCH_Default), |
| SrcLang(SourceLanguageOpenCL_C), |
| SrcLangVer(102000), |
| MemoryModel(MemoryModelOpenCL){ |
| AddrModel = sizeof(size_t) == 32 ? AddressingModelPhysical32 |
| : AddressingModelPhysical64; |
| }; |
| virtual ~SPIRVModuleImpl(); |
| |
| // Object query functions |
| bool exist(SPIRVId) const; |
| bool exist(SPIRVId, SPIRVEntry **) const; |
| SPIRVId getId(SPIRVId Id = SPIRVID_INVALID, unsigned Increment = 1); |
| virtual SPIRVEntry *getEntry(SPIRVId Id) const; |
| bool hasDebugInfo() const { return !LineVec.empty();} |
| |
| // Error handling functions |
| SPIRVErrorLog &getErrorLog() { return ErrLog;} |
| SPIRVErrorCode getError(std::string &ErrMsg) { return ErrLog.getError(ErrMsg);} |
| |
| // Module query functions |
| SPIRVAddressingModelKind getAddressingModel() { return AddrModel;} |
| SPIRVExtInstSetKind getBuiltinSet(SPIRVId SetId) const; |
| const SPIRVCapMap &getCapability() const { return CapMap; } |
| bool hasCapability(SPIRVCapabilityKind Cap) const { |
| return CapMap.find(Cap) != CapMap.end(); |
| } |
| std::set<std::string> &getExtension() { return SPIRVExt;} |
| SPIRVFunction *getFunction(unsigned I) const { return FuncVec[I];} |
| SPIRVVariable *getVariable(unsigned I) const { return VariableVec[I];} |
| virtual SPIRVValue *getValue(SPIRVId TheId) const; |
| virtual std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const; |
| virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVEntry *>&)const; |
| virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>&)const; |
| virtual SPIRVType *getValueType(SPIRVId TheId)const; |
| virtual std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&) |
| const; |
| SPIRVMemoryModelKind getMemoryModel() const { return MemoryModel;} |
| virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal); |
| unsigned getNumEntryPoints(SPIRVExecutionModelKind EM) const { |
| auto Loc = EntryPointVec.find(EM); |
| if (Loc == EntryPointVec.end()) |
| return 0; |
| return Loc->second.size(); |
| } |
| SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind EM, unsigned I) const { |
| auto Loc = EntryPointVec.find(EM); |
| if (Loc == EntryPointVec.end()) |
| return nullptr; |
| assert(I < Loc->second.size()); |
| return get<SPIRVFunction>(Loc->second[I]); |
| } |
| unsigned getNumFunctions() const { return FuncVec.size();} |
| unsigned getNumVariables() const { return VariableVec.size();} |
| SourceLanguage getSourceLanguage(SPIRVWord * Ver = nullptr) const { |
| if (Ver) |
| *Ver = SrcLangVer; |
| return SrcLang; |
| } |
| std::set<std::string> &getSourceExtension() { return SrcExtension;} |
| bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId EP) const; |
| unsigned short getGeneratorId() const { return GeneratorId; } |
| unsigned short getGeneratorVer() const { return GeneratorVer; } |
| SPIRVWord getSPIRVVersion() const { return SPIRVVersion; } |
| |
| // Module changing functions |
| bool importBuiltinSet(const std::string &, SPIRVId *); |
| bool importBuiltinSetWithId(const std::string &, SPIRVId); |
| void optimizeDecorates(); |
| void setAddressingModel(SPIRVAddressingModelKind AM) { AddrModel = AM;} |
| void setAlignment(SPIRVValue *, SPIRVWord); |
| void setMemoryModel(SPIRVMemoryModelKind MM) { |
| MemoryModel = MM; |
| if (MemoryModel == spv::MemoryModelOpenCL) |
| addCapability(CapabilityKernel); |
| } |
| void setName(SPIRVEntry *E, const std::string &Name); |
| void setSourceLanguage(SourceLanguage Lang, SPIRVWord Ver) { |
| SrcLang = Lang; |
| SrcLangVer = Ver; |
| } |
| void setGeneratorId(unsigned short Id) { GeneratorId = Id; } |
| void setGeneratorVer(unsigned short Ver) { GeneratorVer = Ver; } |
| void resolveUnknownStructFields(); |
| |
| void setSPIRVVersion(SPIRVWord Ver) override { SPIRVVersion = Ver; } |
| |
| // Object creation functions |
| template<class T> void addTo(std::vector<T *> &V, SPIRVEntry *E); |
| virtual SPIRVEntry *addEntry(SPIRVEntry *E); |
| virtual SPIRVBasicBlock *addBasicBlock(SPIRVFunction *, SPIRVId); |
| virtual SPIRVString *getString(const std::string &Str); |
| virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST, |
| SPIRVWord MemberNumber, const std::string &Name); |
| virtual void addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I, |
| SPIRVId ID); |
| virtual SPIRVLine *addLine(SPIRVEntry *E, SPIRVString *FileName, SPIRVWord Line, |
| SPIRVWord Column); |
| virtual void addCapability(SPIRVCapabilityKind); |
| virtual void addCapabilityInternal(SPIRVCapabilityKind); |
| virtual const SPIRVDecorateGeneric *addDecorate(const SPIRVDecorateGeneric *); |
| virtual SPIRVDecorationGroup *addDecorationGroup(); |
| virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group); |
| virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group, |
| const std::vector<SPIRVEntry *> &Targets); |
| virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric( |
| SPIRVGroupDecorateGeneric *GDec); |
| virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate( |
| SPIRVDecorationGroup *Group, const std::vector<SPIRVEntry *> &Targets); |
| virtual void addEntryPoint(SPIRVExecutionModelKind ExecModel, |
| SPIRVId EntryPoint); |
| virtual SPIRVForward *addForward(SPIRVType *Ty); |
| virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty); |
| virtual SPIRVFunction *addFunction(SPIRVFunction *); |
| virtual SPIRVFunction *addFunction(SPIRVTypeFunction *, SPIRVId); |
| virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *); |
| |
| // Type creation functions |
| template<class T> T * addType(T *Ty); |
| virtual SPIRVTypeArray *addArrayType(SPIRVType *, SPIRVConstant *); |
| virtual SPIRVTypeBool *addBoolType(); |
| virtual SPIRVTypeFloat *addFloatType(unsigned BitWidth); |
| virtual SPIRVTypeFunction *addFunctionType(SPIRVType *, |
| const std::vector<SPIRVType *> &); |
| virtual SPIRVTypeInt *addIntegerType(unsigned BitWidth); |
| virtual SPIRVTypeOpaque *addOpaqueType(const std::string &); |
| virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *); |
| virtual SPIRVTypeImage *addImageType(SPIRVType *, |
| const SPIRVTypeImageDescriptor &); |
| virtual SPIRVTypeImage *addImageType(SPIRVType *, |
| const SPIRVTypeImageDescriptor &, SPIRVAccessQualifierKind); |
| virtual SPIRVTypeSampler *addSamplerType(); |
| virtual SPIRVTypePipeStorage *addPipeStorageType(); |
| virtual SPIRVTypeSampledImage *addSampledImageType(SPIRVTypeImage *T); |
| virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &); |
| virtual void closeStructType(SPIRVTypeStruct *T, bool); |
| virtual SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord); |
| virtual SPIRVType *addOpaqueGenericType(Op); |
| virtual SPIRVTypeDeviceEvent *addDeviceEventType(); |
| virtual SPIRVTypeQueue *addQueueType(); |
| virtual SPIRVTypePipe *addPipeType(); |
| virtual SPIRVTypeVoid *addVoidType(); |
| virtual void createForwardPointers(); |
| |
| // Constant creation functions |
| virtual SPIRVInstruction *addBranchInst(SPIRVLabel *, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addBranchConditionalInst(SPIRVValue *, SPIRVLabel *, |
| SPIRVLabel *, SPIRVBasicBlock *); |
| virtual SPIRVValue *addCompositeConstant(SPIRVType *, |
| const std::vector<SPIRVValue*>&); |
| virtual SPIRVValue *addConstant(SPIRVValue *); |
| virtual SPIRVValue *addConstant(SPIRVType *, uint64_t); |
| virtual SPIRVValue *addDoubleConstant(SPIRVTypeFloat *, double); |
| virtual SPIRVValue *addFloatConstant(SPIRVTypeFloat *, float); |
| virtual SPIRVValue *addIntegerConstant(SPIRVTypeInt *, uint64_t); |
| virtual SPIRVValue *addNullConstant(SPIRVType *); |
| virtual SPIRVValue *addUndef(SPIRVType *TheType); |
| virtual SPIRVValue *addSamplerConstant(SPIRVType *TheType, SPIRVWord AddrMode, |
| SPIRVWord ParametricMode, SPIRVWord FilterMode); |
| virtual SPIRVValue* addPipeStorageConstant(SPIRVType* TheType, |
| SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity); |
| |
| // Instruction creation functions |
| virtual SPIRVInstruction *addPtrAccessChainInst(SPIRVType *, SPIRVValue *, |
| std::vector<SPIRVValue *>, SPIRVBasicBlock *, bool); |
| virtual SPIRVInstruction *addAsyncGroupCopy(SPIRVValue *Scope, |
| SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride, |
| SPIRVValue *Event, SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addExtInst(SPIRVType *, |
| SPIRVWord, SPIRVWord, const std::vector<SPIRVWord> &, |
| SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addExtInst(SPIRVType *, |
| SPIRVWord, SPIRVWord, const std::vector<SPIRVValue *> &, |
| SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *, |
| SPIRVValue *, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addCallInst(SPIRVFunction*, |
| const std::vector<SPIRVWord> &, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addCmpInst(Op, SPIRVType *, SPIRVValue *, |
| SPIRVValue *, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addLoadInst(SPIRVValue *, |
| const std::vector<SPIRVWord>&, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addPhiInst(SPIRVType *, std::vector<SPIRVValue *>, |
| SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addCompositeExtractInst(SPIRVType *, SPIRVValue *, |
| const std::vector<SPIRVWord>&, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addCompositeInsertInst(SPIRVValue *Object, |
| SPIRVValue *Composite, const std::vector<SPIRVWord>& Indices, |
| SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addCopyObjectInst(SPIRVType *TheType, |
| SPIRVValue *Operand, SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addCopyMemoryInst(SPIRVValue *, SPIRVValue *, |
| const std::vector<SPIRVWord>&, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addCopyMemorySizedInst(SPIRVValue *, SPIRVValue *, |
| SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addControlBarrierInst( |
| SPIRVValue *ExecKind, SPIRVValue *MemKind, |
| SPIRVValue *MemSema, SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addGroupInst(Op OpCode, SPIRVType *Type, |
| Scope Scope, const std::vector<SPIRVValue *> &Ops, |
| SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addInstruction(SPIRVInstruction *Inst, |
| SPIRVBasicBlock *BB); |
| virtual SPIRVInstTemplateBase *addInstTemplate(Op OC, |
| SPIRVBasicBlock* BB, SPIRVType *Ty); |
| virtual SPIRVInstTemplateBase *addInstTemplate(Op OC, |
| const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty); |
| virtual SPIRVInstruction *addMemoryBarrierInst( |
| Scope ScopeKind, SPIRVWord MemFlag, SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addReturnInst(SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addReturnValueInst(SPIRVValue *, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addSelectInst(SPIRVValue *, SPIRVValue *, SPIRVValue *, |
| SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addStoreInst(SPIRVValue *, SPIRVValue *, |
| const std::vector<SPIRVWord>&, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addSwitchInst(SPIRVValue *, SPIRVBasicBlock *, |
| const std::vector<std::pair<SPIRVWord, SPIRVBasicBlock *>>&, |
| SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *, |
| SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind, |
| SPIRVValue *, const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *); |
| virtual SPIRVValue *addVectorShuffleInst(SPIRVType *Type, SPIRVValue *Vec1, |
| SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components, |
| SPIRVBasicBlock *BB); |
| virtual SPIRVInstruction *addVectorExtractDynamicInst(SPIRVValue *, |
| SPIRVValue *, SPIRVBasicBlock *); |
| virtual SPIRVInstruction *addVectorInsertDynamicInst(SPIRVValue *, |
| SPIRVValue *, SPIRVValue*, SPIRVBasicBlock *); |
| |
| // I/O functions |
| friend spv_ostream & operator<<(spv_ostream &O, SPIRVModule& M); |
| friend std::istream & operator>>(std::istream &I, SPIRVModule& M); |
| |
| private: |
| SPIRVErrorLog ErrLog; |
| SPIRVId NextId; |
| SPIRVWord SPIRVVersion; |
| unsigned short GeneratorId; |
| unsigned short GeneratorVer; |
| SPIRVInstructionSchemaKind InstSchema; |
| SourceLanguage SrcLang; |
| SPIRVWord SrcLangVer; |
| std::set<std::string> SrcExtension; |
| std::set<std::string> SPIRVExt; |
| SPIRVAddressingModelKind AddrModel; |
| SPIRVMemoryModelKind MemoryModel; |
| |
| typedef std::map<SPIRVId, SPIRVEntry *> SPIRVIdToEntryMap; |
| typedef std::vector<SPIRVEntry *> SPIRVEntryVector; |
| typedef std::set<SPIRVId> SPIRVIdSet; |
| typedef std::vector<SPIRVId> SPIRVIdVec; |
| typedef std::vector<SPIRVFunction *> SPIRVFunctionVector; |
| typedef std::vector<SPIRVTypeForwardPointer *> SPIRVForwardPointerVec; |
| typedef std::vector<SPIRVType *> SPIRVTypeVec; |
| typedef std::vector<SPIRVValue *> SPIRVConstantVector; |
| typedef std::vector<SPIRVVariable *> SPIRVVariableVec; |
| typedef std::vector<SPIRVString *> SPIRVStringVec; |
| typedef std::vector<SPIRVMemberName *> SPIRVMemberNameVec; |
| typedef std::vector<SPIRVLine *> SPIRVLineVec; |
| typedef std::vector<SPIRVDecorationGroup *> SPIRVDecGroupVec; |
| typedef std::vector<SPIRVGroupDecorateGeneric *> SPIRVGroupDecVec; |
| typedef std::map<SPIRVId, SPIRVExtInstSetKind> SPIRVIdToBuiltinSetMap; |
| typedef std::map<SPIRVExecutionModelKind, SPIRVIdSet> SPIRVExecModelIdSetMap; |
| typedef std::map<SPIRVExecutionModelKind, SPIRVIdVec> SPIRVExecModelIdVecMap; |
| typedef std::unordered_map<std::string, SPIRVString*> SPIRVStringMap; |
| typedef std::map<SPIRVTypeStruct *, std::vector<std::pair<unsigned, SPIRVId>>> |
| SPIRVUnknownStructFieldMap; |
| |
| SPIRVForwardPointerVec ForwardPointerVec; |
| SPIRVTypeVec TypeVec; |
| SPIRVIdToEntryMap IdEntryMap; |
| SPIRVFunctionVector FuncVec; |
| SPIRVConstantVector ConstVec; |
| SPIRVVariableVec VariableVec; |
| SPIRVEntryVector EntryNoId; // Entries without id |
| SPIRVIdToBuiltinSetMap IdBuiltinMap; |
| SPIRVIdSet NamedId; |
| SPIRVStringVec StringVec; |
| SPIRVMemberNameVec MemberNameVec; |
| SPIRVLineVec LineVec; |
| SPIRVDecorateSet DecorateSet; |
| SPIRVDecGroupVec DecGroupVec; |
| SPIRVGroupDecVec GroupDecVec; |
| SPIRVExecModelIdSetMap EntryPointSet; |
| SPIRVExecModelIdVecMap EntryPointVec; |
| SPIRVStringMap StrMap; |
| SPIRVCapMap CapMap; |
| SPIRVUnknownStructFieldMap UnknownStructFieldMap; |
| std::map<unsigned, SPIRVTypeInt*> IntTypeMap; |
| std::map<unsigned, SPIRVConstant*> LiteralMap; |
| |
| void layoutEntry(SPIRVEntry* Entry); |
| }; |
| |
| SPIRVModuleImpl::~SPIRVModuleImpl() { |
| //ToDo: Fix bug causing crash |
| //for (auto I:IdEntryMap) |
| // delete I.second; |
| |
| // ToDo: Fix bug causing crash |
| //for (auto I:EntryNoId) { |
| // bildbgs() << "[delete] " << *I; |
| // delete I; |
| //} |
| |
| for (auto C : CapMap) |
| delete C.second; |
| } |
| |
| SPIRVLine* |
| SPIRVModuleImpl::addLine(SPIRVEntry* E, SPIRVString* FileName, |
| SPIRVWord Line, SPIRVWord Column) { |
| auto L = add(new SPIRVLine(E, FileName->getId(), Line, Column)); |
| E->setLine(L); |
| return L; |
| } |
| |
| // Creates decoration group and group decorates from decorates shared by |
| // multiple targets. |
| void |
| SPIRVModuleImpl::optimizeDecorates() { |
| SPIRVDBG(spvdbgs() << "[optimizeDecorates] begin\n"); |
| for (auto I = DecorateSet.begin(), E = DecorateSet.end(); I != E;) { |
| auto D = *I; |
| SPIRVDBG(spvdbgs() << " check " << *D << '\n'); |
| if (D->getOpCode() == OpMemberDecorate) { |
| ++I; |
| continue; |
| } |
| auto ER = DecorateSet.equal_range(D); |
| SPIRVDBG(spvdbgs() << " equal range " << **ER.first |
| << " to "; |
| if (ER.second != DecorateSet.end()) |
| spvdbgs() << **ER.second; |
| else |
| spvdbgs() << "end"; |
| spvdbgs() << '\n'); |
| if (std::distance(ER.first, ER.second) < 2) { |
| I = ER.second; |
| SPIRVDBG(spvdbgs() << " skip equal range \n"); |
| continue; |
| } |
| SPIRVDBG(spvdbgs() << " add deco group. erase equal range\n"); |
| auto G = new SPIRVDecorationGroup(this, getId()); |
| std::vector<SPIRVId> Targets; |
| Targets.push_back(D->getTargetId()); |
| const_cast<SPIRVDecorateGeneric*>(D)->setTargetId(G->getId()); |
| G->getDecorations().insert(D); |
| for (I = ER.first; I != ER.second; ++I) { |
| auto E = *I; |
| if (*E == *D) |
| continue; |
| Targets.push_back(E->getTargetId()); |
| } |
| |
| // WordCount is only 16 bits. We can only have 65535 - FixedWC targtets per |
| // group. |
| // For now, just skip using a group if the number of targets to too big |
| if (Targets.size() < 65530) { |
| DecorateSet.erase(ER.first, ER.second); |
| auto GD = new SPIRVGroupDecorate(G, Targets); |
| DecGroupVec.push_back(G); |
| GroupDecVec.push_back(GD); |
| } |
| } |
| } |
| |
| SPIRVValue* |
| SPIRVModuleImpl::addSamplerConstant(SPIRVType* TheType, |
| SPIRVWord AddrMode, SPIRVWord ParametricMode, SPIRVWord FilterMode) { |
| return addConstant(new SPIRVConstantSampler(this, TheType, getId(), AddrMode, |
| ParametricMode, FilterMode)); |
| } |
| |
| SPIRVValue* |
| SPIRVModuleImpl::addPipeStorageConstant(SPIRVType* TheType, |
| SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity) { |
| return addConstant(new SPIRVConstantPipeStorage(this, TheType, getId(), |
| PacketSize, PacketAlign, Capacity)); |
| } |
| |
| void |
| SPIRVModuleImpl::addCapability(SPIRVCapabilityKind Cap) { |
| addCapabilities(SPIRV::getCapability(Cap)); |
| SPIRVDBG(spvdbgs() << "addCapability: " << Cap << '\n'); |
| if (hasCapability(Cap)) |
| return; |
| |
| CapMap.insert(std::make_pair(Cap, new SPIRVCapability(this, Cap))); |
| } |
| |
| void |
| SPIRVModuleImpl::addCapabilityInternal(SPIRVCapabilityKind Cap) { |
| if (AutoAddCapability) { |
| if (hasCapability(Cap)) |
| return; |
| |
| CapMap.insert(std::make_pair(Cap, new SPIRVCapability(this, Cap))); |
| } |
| } |
| |
| SPIRVConstant* |
| SPIRVModuleImpl::getLiteralAsConstant(unsigned Literal) { |
| auto Loc = LiteralMap.find(Literal); |
| if (Loc != LiteralMap.end()) |
| return Loc->second; |
| auto Ty = addIntegerType(32); |
| auto V = new SPIRVConstant(this, Ty, getId(), static_cast<uint64_t>(Literal)); |
| LiteralMap[Literal] = V; |
| addConstant(V); |
| return V; |
| } |
| |
| void |
| SPIRVModuleImpl::layoutEntry(SPIRVEntry* E) { |
| auto OC = E->getOpCode(); |
| switch (OC) { |
| case OpString: |
| addTo(StringVec, E); |
| break; |
| case OpMemberName: |
| addTo(MemberNameVec, E); |
| break; |
| case OpLine: |
| addTo(LineVec, E); |
| break; |
| case OpVariable: { |
| auto BV = static_cast<SPIRVVariable*>(E); |
| if (!BV->getParent()) |
| addTo(VariableVec, E); |
| } |
| break; |
| default: |
| if (isTypeOpCode(OC)) |
| TypeVec.push_back(static_cast<SPIRVType*>(E)); |
| else if (isConstantOpCode(OC)) |
| ConstVec.push_back(static_cast<SPIRVConstant*>(E)); |
| break; |
| } |
| } |
| |
| // Add an entry to the id to entry map. |
| // Assert if the id is mapped to a different entry. |
| // Certain entries need to be add to specific collectors to maintain |
| // logic layout of SPIRV. |
| SPIRVEntry * |
| SPIRVModuleImpl::addEntry(SPIRVEntry *Entry) { |
| assert(Entry && "Invalid entry"); |
| if (Entry->hasId()) { |
| SPIRVId Id = Entry->getId(); |
| assert(Entry->getId() != SPIRVID_INVALID && "Invalid id"); |
| SPIRVEntry *Mapped = nullptr; |
| if (exist(Id, &Mapped)) { |
| if (Mapped->getOpCode() == OpForward) { |
| replaceForward(static_cast<SPIRVForward *>(Mapped), Entry); |
| } else { |
| assert(Mapped == Entry && "Id used twice"); |
| } |
| } else |
| IdEntryMap[Id] = Entry; |
| } else { |
| EntryNoId.push_back(Entry); |
| } |
| |
| Entry->setModule(this); |
| |
| layoutEntry(Entry); |
| if (AutoAddCapability) { |
| for (auto &I:Entry->getRequiredCapability()) { |
| addCapability(I); |
| } |
| } |
| if (ValidateCapability) { |
| for (auto &I:Entry->getRequiredCapability()) { |
| (void) I; |
| assert(CapMap.count(I)); |
| } |
| } |
| return Entry; |
| } |
| |
| bool |
| SPIRVModuleImpl::exist(SPIRVId Id) const { |
| return exist(Id, nullptr); |
| } |
| |
| bool |
| SPIRVModuleImpl::exist(SPIRVId Id, SPIRVEntry **Entry) const { |
| assert (Id != SPIRVID_INVALID && "Invalid Id"); |
| SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id); |
| if (Loc == IdEntryMap.end()) |
| return false; |
| if (Entry) |
| *Entry = Loc->second; |
| return true; |
| } |
| |
| // If Id is invalid, returns the next available id. |
| // Otherwise returns the given id and adjust the next available id by increment. |
| SPIRVId |
| SPIRVModuleImpl::getId(SPIRVId Id, unsigned increment) { |
| if (!isValidId(Id)) |
| Id = NextId; |
| else |
| NextId = std::max(Id, NextId); |
| NextId += increment; |
| return Id; |
| } |
| |
| SPIRVEntry * |
| SPIRVModuleImpl::getEntry(SPIRVId Id) const { |
| assert (Id != SPIRVID_INVALID && "Invalid Id"); |
| SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id); |
| assert (Loc != IdEntryMap.end() && "Id is not in map"); |
| return Loc->second; |
| } |
| |
| SPIRVExtInstSetKind |
| SPIRVModuleImpl::getBuiltinSet(SPIRVId SetId) const { |
| auto Loc = IdBuiltinMap.find(SetId); |
| assert(Loc != IdBuiltinMap.end() && "Invalid builtin set id"); |
| return Loc->second; |
| } |
| |
| bool |
| SPIRVModuleImpl::isEntryPoint(SPIRVExecutionModelKind ExecModel, SPIRVId EP) |
| const { |
| assert(isValid(ExecModel) && "Invalid execution model"); |
| assert(EP != SPIRVID_INVALID && "Invalid function id"); |
| auto Loc = EntryPointSet.find(ExecModel); |
| if (Loc == EntryPointSet.end()) |
| return false; |
| return Loc->second.count(EP); |
| } |
| |
| // Module change functions |
| bool |
| SPIRVModuleImpl::importBuiltinSet(const std::string& BuiltinSetName, |
| SPIRVId *BuiltinSetId) { |
| SPIRVId TmpBuiltinSetId = getId(); |
| if (!importBuiltinSetWithId(BuiltinSetName, TmpBuiltinSetId)) |
| return false; |
| if (BuiltinSetId) |
| *BuiltinSetId = TmpBuiltinSetId; |
| return true; |
| } |
| |
| bool |
| SPIRVModuleImpl::importBuiltinSetWithId(const std::string& BuiltinSetName, |
| SPIRVId BuiltinSetId) { |
| SPIRVExtInstSetKind BuiltinSet = SPIRVEIS_Count; |
| SPIRVCKRT(SPIRVBuiltinSetNameMap::rfind(BuiltinSetName, &BuiltinSet), |
| InvalidBuiltinSetName, "Actual is " + BuiltinSetName); |
| IdBuiltinMap[BuiltinSetId] = BuiltinSet; |
| return true; |
| } |
| |
| void |
| SPIRVModuleImpl::setAlignment(SPIRVValue *V, SPIRVWord A) { |
| V->setAlignment(A); |
| } |
| |
| void |
| SPIRVModuleImpl::setName(SPIRVEntry *E, const std::string &Name) { |
| E->setName(Name); |
| if (!E->hasId()) |
| return; |
| if (!Name.empty()) |
| NamedId.insert(E->getId()); |
| else |
| NamedId.erase(E->getId()); |
| } |
| |
| void SPIRVModuleImpl::resolveUnknownStructFields() { |
| for (auto &KV : UnknownStructFieldMap) { |
| auto *Struct = KV.first; |
| for (auto &Indices : KV.second) { |
| unsigned I = Indices.first; |
| SPIRVId ID = Indices.second; |
| |
| auto Ty = static_cast<SPIRVType *>(getEntry(ID)); |
| Struct->setMemberType(I, Ty); |
| } |
| } |
| } |
| |
| // Type creation functions |
| template<class T> |
| T * |
| SPIRVModuleImpl::addType(T *Ty) { |
| add(Ty); |
| if (!Ty->getName().empty()) |
| setName(Ty, Ty->getName()); |
| return Ty; |
| } |
| |
| SPIRVTypeVoid * |
| SPIRVModuleImpl::addVoidType() { |
| return addType(new SPIRVTypeVoid(this, getId())); |
| } |
| |
| SPIRVTypeArray * |
| SPIRVModuleImpl::addArrayType(SPIRVType *ElementType, SPIRVConstant *Length) { |
| return addType(new SPIRVTypeArray(this, getId(), ElementType, Length)); |
| } |
| |
| SPIRVTypeBool * |
| SPIRVModuleImpl::addBoolType() { |
| return addType(new SPIRVTypeBool(this, getId())); |
| } |
| |
| SPIRVTypeInt * |
| SPIRVModuleImpl::addIntegerType(unsigned BitWidth) { |
| auto Loc = IntTypeMap.find(BitWidth); |
| if (Loc != IntTypeMap.end()) |
| return Loc->second; |
| auto Ty = new SPIRVTypeInt(this, getId(), BitWidth, false); |
| IntTypeMap[BitWidth] = Ty; |
| return addType(Ty); |
| } |
| |
| SPIRVTypeFloat * |
| SPIRVModuleImpl::addFloatType(unsigned BitWidth) { |
| SPIRVTypeFloat *T = addType(new SPIRVTypeFloat(this, getId(), BitWidth)); |
| return T; |
| } |
| |
| SPIRVTypePointer * |
| SPIRVModuleImpl::addPointerType(SPIRVStorageClassKind StorageClass, |
| SPIRVType *ElementType) { |
| return addType(new SPIRVTypePointer(this, getId(), StorageClass, |
| ElementType)); |
| } |
| |
| SPIRVTypeFunction * |
| SPIRVModuleImpl::addFunctionType(SPIRVType *ReturnType, |
| const std::vector<SPIRVType *>& ParameterTypes) { |
| return addType(new SPIRVTypeFunction(this, getId(), ReturnType, |
| ParameterTypes)); |
| } |
| |
| SPIRVTypeOpaque* |
| SPIRVModuleImpl::addOpaqueType(const std::string& Name) { |
| return addType(new SPIRVTypeOpaque(this, getId(), Name)); |
| } |
| |
| SPIRVTypeStruct *SPIRVModuleImpl::openStructType(unsigned NumMembers, |
| const std::string &Name) { |
| auto T = new SPIRVTypeStruct(this, getId(), NumMembers, Name); |
| return T; |
| } |
| |
| void SPIRVModuleImpl::closeStructType(SPIRVTypeStruct *T, bool Packed) { |
| addType(T); |
| T->setPacked(Packed); |
| } |
| |
| SPIRVTypeVector* |
| SPIRVModuleImpl::addVectorType(SPIRVType* CompType, SPIRVWord CompCount) { |
| return addType(new SPIRVTypeVector(this, getId(), CompType, CompCount)); |
| } |
| SPIRVType * |
| SPIRVModuleImpl::addOpaqueGenericType(Op TheOpCode) { |
| return addType(new SPIRVTypeOpaqueGeneric(TheOpCode, this, getId())); |
| } |
| |
| SPIRVTypeDeviceEvent * |
| SPIRVModuleImpl::addDeviceEventType() { |
| return addType(new SPIRVTypeDeviceEvent(this, getId())); |
| } |
| |
| SPIRVTypeQueue * |
| SPIRVModuleImpl::addQueueType() { |
| return addType(new SPIRVTypeQueue(this, getId())); |
| } |
| |
| SPIRVTypePipe* |
| SPIRVModuleImpl::addPipeType() { |
| return addType(new SPIRVTypePipe(this, getId())); |
| } |
| |
| SPIRVTypeImage * |
| SPIRVModuleImpl::addImageType(SPIRVType *SampledType, |
| const SPIRVTypeImageDescriptor &Desc) { |
| return addType(new SPIRVTypeImage(this, getId(), |
| SampledType ? SampledType->getId() : 0, Desc)); |
| } |
| |
| SPIRVTypeImage * |
| SPIRVModuleImpl::addImageType(SPIRVType *SampledType, |
| const SPIRVTypeImageDescriptor &Desc, SPIRVAccessQualifierKind Acc) { |
| return addType(new SPIRVTypeImage(this, getId(), |
| SampledType ? SampledType->getId() : 0, Desc, Acc)); |
| } |
| |
| SPIRVTypeSampler * |
| SPIRVModuleImpl::addSamplerType() { |
| return addType(new SPIRVTypeSampler(this, getId())); |
| } |
| |
| SPIRVTypePipeStorage* |
| SPIRVModuleImpl::addPipeStorageType() { |
| return addType(new SPIRVTypePipeStorage(this, getId())); |
| } |
| |
| SPIRVTypeSampledImage * |
| SPIRVModuleImpl::addSampledImageType(SPIRVTypeImage *T) { |
| return addType(new SPIRVTypeSampledImage(this, getId(), T)); |
| } |
| |
| void SPIRVModuleImpl::createForwardPointers() { |
| std::unordered_set<SPIRVId> Seen; |
| |
| for (auto *T : TypeVec) { |
| if (T->hasId()) |
| Seen.insert(T->getId()); |
| |
| if (!T->isTypeStruct()) |
| continue; |
| |
| auto ST = static_cast<SPIRVTypeStruct *>(T); |
| |
| for (unsigned i = 0; i < ST->getStructMemberCount(); ++i) { |
| auto MemberTy = ST->getStructMemberType(i); |
| if (!MemberTy->isTypePointer()) continue; |
| auto Ptr = static_cast<SPIRVTypePointer *>(MemberTy); |
| |
| if (Seen.find(Ptr->getId()) == Seen.end()) { |
| ForwardPointerVec.push_back(new SPIRVTypeForwardPointer( |
| this, Ptr, Ptr->getPointerStorageClass())); |
| } |
| } |
| } |
| } |
| |
| SPIRVFunction * |
| SPIRVModuleImpl::addFunction(SPIRVFunction *Func) { |
| FuncVec.push_back(add(Func)); |
| return Func; |
| } |
| |
| SPIRVFunction * |
| SPIRVModuleImpl::addFunction(SPIRVTypeFunction *FuncType, SPIRVId Id) { |
| return addFunction(new SPIRVFunction(this, FuncType, |
| getId(Id, FuncType->getNumParameters() + 1))); |
| } |
| |
| SPIRVBasicBlock * |
| SPIRVModuleImpl::addBasicBlock(SPIRVFunction *Func, SPIRVId Id) { |
| return Func->addBasicBlock(new SPIRVBasicBlock(getId(Id), Func)); |
| } |
| |
| const SPIRVDecorateGeneric * |
| SPIRVModuleImpl::addDecorate(const SPIRVDecorateGeneric *Dec) { |
| SPIRVId Id = Dec->getTargetId(); |
| SPIRVEntry *Target = nullptr; |
| bool Found = exist(Id, &Target); |
| (void) Found; |
| assert (Found && "Decorate target does not exist"); |
| if (!Dec->getOwner()) |
| DecorateSet.insert(Dec); |
| addCapabilities(Dec->getRequiredCapability()); |
| return Dec; |
| } |
| |
| void |
| SPIRVModuleImpl::addEntryPoint(SPIRVExecutionModelKind ExecModel, |
| SPIRVId EntryPoint){ |
| assert(isValid(ExecModel) && "Invalid execution model"); |
| assert(EntryPoint != SPIRVID_INVALID && "Invalid entry point"); |
| EntryPointSet[ExecModel].insert(EntryPoint); |
| EntryPointVec[ExecModel].push_back(EntryPoint); |
| addCapabilities(SPIRV::getCapability(ExecModel)); |
| } |
| |
| SPIRVForward * |
| SPIRVModuleImpl::addForward(SPIRVType *Ty) { |
| return add(new SPIRVForward(this, Ty, getId())); |
| } |
| |
| SPIRVForward * |
| SPIRVModuleImpl::addForward(SPIRVId Id, SPIRVType *Ty) { |
| return add(new SPIRVForward(this, Ty, Id)); |
| } |
| |
| SPIRVEntry * |
| SPIRVModuleImpl::replaceForward(SPIRVForward *Forward, SPIRVEntry *Entry) { |
| SPIRVId Id = Entry->getId(); |
| SPIRVId ForwardId = Forward->getId(); |
| if (ForwardId == Id) |
| IdEntryMap[Id] = Entry; |
| else { |
| auto Loc = IdEntryMap.find(Id); |
| assert(Loc != IdEntryMap.end()); |
| IdEntryMap.erase(Loc); |
| Entry->setId(ForwardId); |
| IdEntryMap[ForwardId] = Entry; |
| } |
| // Annotations include name, decorations, execution modes |
| Entry->takeAnnotations(Forward); |
| delete Forward; |
| return Entry; |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addConstant(SPIRVValue *C) { |
| return add(C); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addConstant(SPIRVType *Ty, uint64_t V) { |
| if (Ty->isTypeBool()) { |
| if (V) |
| return addConstant(new SPIRVConstantTrue(this, Ty, getId())); |
| else |
| return addConstant(new SPIRVConstantFalse(this, Ty, getId())); |
| } |
| if (Ty->isTypeInt()) |
| return addIntegerConstant(static_cast<SPIRVTypeInt*>(Ty), V); |
| return addConstant(new SPIRVConstant(this, Ty, getId(), V)); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addIntegerConstant(SPIRVTypeInt *Ty, uint64_t V) { |
| if (Ty->getBitWidth() == 32) { |
| unsigned I32 = V; |
| assert(I32 == V && "Integer value truncated"); |
| return getLiteralAsConstant(I32); |
| } |
| return addConstant(new SPIRVConstant(this, Ty, getId(), V)); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addFloatConstant(SPIRVTypeFloat *Ty, float V) { |
| return addConstant(new SPIRVConstant(this, Ty, getId(), V)); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addDoubleConstant(SPIRVTypeFloat *Ty, double V) { |
| return addConstant(new SPIRVConstant(this, Ty, getId(), V)); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addNullConstant(SPIRVType *Ty) { |
| return addConstant(new SPIRVConstantNull(this, Ty, getId())); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addCompositeConstant(SPIRVType *Ty, |
| const std::vector<SPIRVValue*>& Elements) { |
| return addConstant(new SPIRVConstantComposite(this, Ty, getId(), Elements)); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addUndef(SPIRVType *TheType) { |
| return addConstant(new SPIRVUndef(this, TheType, getId())); |
| } |
| |
| // Instruction creation functions |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addStoreInst(SPIRVValue *Target, SPIRVValue *Source, |
| const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { |
| return BB->addInstruction(new SPIRVStore(Target->getId(), |
| Source->getId(), TheMemoryAccess, BB)); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addSwitchInst(SPIRVValue *Select, SPIRVBasicBlock *Default, |
| const std::vector<std::pair<SPIRVWord, SPIRVBasicBlock *>>& Pairs, |
| SPIRVBasicBlock *BB) { |
| return BB->addInstruction(new SPIRVSwitch(Select, Default, Pairs, BB)); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addGroupInst(Op OpCode, SPIRVType *Type, |
| Scope Scope, const std::vector<SPIRVValue *> &Ops, |
| SPIRVBasicBlock *BB) { |
| assert(!Type || !Type->isTypeVoid()); |
| auto WordOps = getIds(Ops); |
| WordOps.insert(WordOps.begin(), Scope); |
| return addInstTemplate(OpCode, WordOps, BB, Type); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addInstruction(SPIRVInstruction *Inst, SPIRVBasicBlock *BB) { |
| if (BB) |
| return BB->addInstruction(Inst); |
| if (Inst->getOpCode() != OpSpecConstantOp) |
| Inst = createSpecConstantOpInst(Inst); |
| return static_cast<SPIRVInstruction *>(addConstant(Inst)); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addLoadInst(SPIRVValue *Source, |
| const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVLoad(getId(), Source->getId(), |
| TheMemoryAccess, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addPhiInst(SPIRVType *Type, |
| std::vector<SPIRVValue *> IncomingPairs, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVPhi(Type, getId(), IncomingPairs, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addExtInst(SPIRVType *TheType, SPIRVWord BuiltinSet, |
| SPIRVWord EntryPoint, const std::vector<SPIRVWord> &Args, |
| SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVExtInst(TheType, getId(), |
| BuiltinSet, EntryPoint, Args, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addExtInst(SPIRVType *TheType, SPIRVWord BuiltinSet, |
| SPIRVWord EntryPoint, const std::vector<SPIRVValue *> &Args, |
| SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVExtInst(TheType, getId(), |
| BuiltinSet, EntryPoint, Args, BB), BB); |
| } |
| |
| SPIRVInstruction* |
| SPIRVModuleImpl::addCallInst(SPIRVFunction* TheFunction, |
| const std::vector<SPIRVWord> &TheArguments, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVFunctionCall(getId(), TheFunction, |
| TheArguments, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addBinaryInst(Op TheOpCode, SPIRVType *Type, |
| SPIRVValue *Op1, SPIRVValue *Op2, SPIRVBasicBlock *BB){ |
| return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, Type, getId(), |
| getVec(Op1->getId(), Op2->getId()), BB, this), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addReturnInst(SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVReturn(BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addReturnValueInst(SPIRVValue *ReturnValue, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVReturnValue(ReturnValue, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addUnaryInst(Op TheOpCode, SPIRVType *TheType, |
| SPIRVValue *Op, SPIRVBasicBlock *BB) { |
| return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, |
| TheType, getId(), getVec(Op->getId()), BB, this), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addVectorExtractDynamicInst(SPIRVValue *TheVector, |
| SPIRVValue *Index, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVVectorExtractDynamic(getId(), TheVector, |
| Index, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addVectorInsertDynamicInst(SPIRVValue *TheVector, |
| SPIRVValue *TheComponent, SPIRVValue*Index, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVVectorInsertDynamic(getId(), TheVector, |
| TheComponent, Index, BB), BB); |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::addVectorShuffleInst(SPIRVType * Type, SPIRVValue *Vec1, |
| SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components, |
| SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVVectorShuffle(getId(), Type, Vec1, Vec2, |
| Components, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addBranchInst(SPIRVLabel *TargetLabel, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVBranch(TargetLabel, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addBranchConditionalInst(SPIRVValue *Condition, |
| SPIRVLabel *TrueLabel, SPIRVLabel *FalseLabel, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVBranchConditional(Condition, TrueLabel, |
| FalseLabel, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addCmpInst(Op TheOpCode, SPIRVType *TheType, |
| SPIRVValue *Op1, SPIRVValue *Op2, SPIRVBasicBlock *BB) { |
| return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, |
| TheType, getId(), getVec(Op1->getId(), Op2->getId()), BB, this), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addControlBarrierInst(SPIRVValue *ExecKind, |
| SPIRVValue *MemKind, SPIRVValue *MemSema, SPIRVBasicBlock *BB) { |
| return addInstruction( |
| new SPIRVControlBarrier(ExecKind, MemKind, MemSema, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addMemoryBarrierInst(Scope ScopeKind, |
| SPIRVWord MemFlag, SPIRVBasicBlock *BB) { |
| return addInstruction(SPIRVInstTemplateBase::create(OpMemoryBarrier, |
| nullptr, SPIRVID_INVALID, |
| getVec(static_cast<SPIRVWord>(ScopeKind), MemFlag), BB, this), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addSelectInst(SPIRVValue *Condition, SPIRVValue *Op1, |
| SPIRVValue *Op2, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVSelect(getId(), Condition->getId(), |
| Op1->getId(), Op2->getId(), BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addPtrAccessChainInst(SPIRVType *Type, SPIRVValue *Base, |
| std::vector<SPIRVValue *> Indices, SPIRVBasicBlock *BB, bool IsInBounds){ |
| return addInstruction(SPIRVInstTemplateBase::create( |
| IsInBounds?OpInBoundsPtrAccessChain:OpPtrAccessChain, |
| Type, getId(), getVec(Base->getId(), Base->getIds(Indices)), |
| BB, this), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addAsyncGroupCopy(SPIRVValue *Scope, |
| SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride, |
| SPIRVValue *Event, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVGroupAsyncCopy(Scope, getId(), Dest, Src, |
| NumElems, Stride, Event, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addCompositeExtractInst(SPIRVType *Type, SPIRVValue *TheVector, |
| const std::vector<SPIRVWord>& Indices, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVCompositeExtract(Type, getId(), TheVector, |
| Indices, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addCompositeInsertInst(SPIRVValue *Object, |
| SPIRVValue *Composite, const std::vector<SPIRVWord>& Indices, |
| SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVCompositeInsert(getId(), Object, Composite, |
| Indices, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addCopyObjectInst(SPIRVType *TheType, SPIRVValue *Operand, |
| SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVCopyObject(TheType, getId(), Operand, BB), BB); |
| |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addCopyMemoryInst(SPIRVValue *TheTarget, SPIRVValue *TheSource, |
| const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVCopyMemory(TheTarget, TheSource, |
| TheMemoryAccess, BB), BB); |
| } |
| |
| SPIRVInstruction * |
| SPIRVModuleImpl::addCopyMemorySizedInst(SPIRVValue *TheTarget, |
| SPIRVValue *TheSource, SPIRVValue *TheSize, |
| const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { |
| return addInstruction(new SPIRVCopyMemorySized(TheTarget, TheSource, TheSize, |
| TheMemoryAccess, BB), BB); |
| } |
| |
| SPIRVInstruction* |
| SPIRVModuleImpl::addVariable(SPIRVType *Type, bool IsConstant, |
| SPIRVLinkageTypeKind LinkageType, SPIRVValue *Initializer, |
| const std::string &Name, SPIRVStorageClassKind StorageClass, |
| SPIRVBasicBlock *BB) { |
| SPIRVVariable *Variable = new SPIRVVariable(Type, getId(), Initializer, |
| Name, StorageClass, BB, this); |
| if (BB) |
| return addInstruction(Variable, BB); |
| |
| add(Variable); |
| if (LinkageType != LinkageTypeInternal) |
| Variable->setLinkageType(LinkageType); |
| Variable->setIsConstant(IsConstant); |
| return Variable; |
| } |
| |
| template<class T> |
| spv_ostream & |
| operator<< (spv_ostream &O, const std::vector<T *>& V) { |
| for (auto &I: V) |
| O << *I; |
| return O; |
| } |
| |
| template<class T, class B> |
| spv_ostream & |
| operator<< (spv_ostream &O, const std::multiset<T *, B>& V) { |
| for (auto &I: V) |
| O << *I; |
| return O; |
| } |
| |
| // To satisfy SPIR-V spec requirement: |
| // "All operands must be declared before being used", |
| // we do DFS based topological sort |
| // https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search |
| class TopologicalSort { |
| enum DFSState : char { |
| Unvisited, |
| Discovered, |
| Visited |
| }; |
| typedef std::vector<SPIRVType *> SPIRVTypeVec; |
| typedef std::vector<SPIRVValue *> SPIRVConstantVector; |
| typedef std::vector<SPIRVVariable *> SPIRVVariableVec; |
| typedef std::vector<SPIRVTypeForwardPointer *> SPIRVForwardPointerVec; |
| typedef std::function<bool(SPIRVEntry*, SPIRVEntry*)> IdComp; |
| typedef std::map<SPIRVEntry*, DFSState, IdComp> EntryStateMapTy; |
| |
| SPIRVTypeVec TypeIntVec; |
| SPIRVConstantVector ConstIntVec; |
| SPIRVTypeVec TypeVec; |
| SPIRVConstantVector ConstVec; |
| SPIRVVariableVec VariableVec; |
| const SPIRVForwardPointerVec& ForwardPointerVec; |
| EntryStateMapTy EntryStateMap; |
| |
| friend spv_ostream & operator<<(spv_ostream &O, const TopologicalSort &S); |
| |
| // This method implements recursive depth-first search among all Entries in |
| // EntryStateMap. Traversing entries and adding them to corresponding container |
| // after visiting all dependent entries(post-order traversal) guarantees that |
| // the entry's operands will appear in the container before the entry itslef. |
| void visit(SPIRVEntry* E) { |
| DFSState& State = EntryStateMap[E]; |
| assert(State != Discovered && "Cyclic dependency detected"); |
| if (State == Visited) |
| return; |
| State = Discovered; |
| for (SPIRVEntry *Op : E->getNonLiteralOperands()) { |
| auto Comp = [&Op](SPIRVTypeForwardPointer *FwdPtr) { |
| return FwdPtr->getPointer() == Op; |
| }; |
| // Skip forward referenced pointers |
| if (Op->getOpCode() == OpTypePointer && |
| find_if(ForwardPointerVec.begin(), ForwardPointerVec.end(), Comp) != |
| ForwardPointerVec.end()) |
| continue; |
| visit(Op); |
| } |
| State = Visited; |
| Op OC = E->getOpCode(); |
| if (OC == OpTypeInt) |
| TypeIntVec.push_back(static_cast<SPIRVType*>(E)); |
| else if (isConstantOpCode(OC)) { |
| SPIRVConstant *C = static_cast<SPIRVConstant*>(E); |
| if (C->getType()->isTypeInt()) |
| ConstIntVec.push_back(C); |
| else |
| ConstVec.push_back(C); |
| } else if (isTypeOpCode(OC)) |
| TypeVec.push_back(static_cast<SPIRVType*>(E)); |
| else if (E->isVariable()) |
| VariableVec.push_back(static_cast<SPIRVVariable*>(E)); |
| } |
| public: |
| TopologicalSort(const SPIRVTypeVec &_TypeVec, |
| const SPIRVConstantVector &_ConstVec, |
| const SPIRVVariableVec &_VariableVec, |
| const SPIRVForwardPointerVec &_ForwardPointerVec) : |
| ForwardPointerVec(_ForwardPointerVec), |
| EntryStateMap([](SPIRVEntry* a, SPIRVEntry* b) -> bool { |
| return a->getId() < b->getId(); |
| }) |
| { |
| // Collect entries for sorting |
| for (auto *T : _TypeVec) |
| EntryStateMap[T] = DFSState::Unvisited; |
| for (auto *C : _ConstVec) |
| EntryStateMap[C] = DFSState::Unvisited; |
| for (auto *V : _VariableVec) |
| EntryStateMap[V] = DFSState::Unvisited; |
| // Run topoligical sort |
| for (auto ES : EntryStateMap) |
| visit(ES.first); |
| } |
| }; |
| |
| spv_ostream & |
| operator<< (spv_ostream &O, const TopologicalSort &S) { |
| O << S.TypeIntVec |
| << S.ConstIntVec |
| << S.TypeVec |
| << S.ConstVec |
| << S.VariableVec; |
| return O; |
| } |
| |
| spv_ostream & |
| operator<< (spv_ostream &O, SPIRVModule &M) { |
| SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl*>(&M); |
| |
| SPIRVEncoder Encoder(O); |
| Encoder << MagicNumber |
| << MI.SPIRVVersion |
| << (((SPIRVWord)MI.GeneratorId << 16) | MI.GeneratorVer) |
| << MI.NextId /* Bound for Id */ |
| << MI.InstSchema; |
| O << SPIRVNL(); |
| |
| for (auto &I:MI.CapMap) |
| O << *I.second; |
| |
| for (auto &I:M.getExtension()) { |
| assert(!I.empty() && "Invalid extension"); |
| O << SPIRVExtension(&M, I); |
| } |
| |
| for (auto &I:MI.IdBuiltinMap) |
| O << SPIRVExtInstImport(&M, I.first, SPIRVBuiltinSetNameMap::map(I.second)); |
| |
| O << SPIRVMemoryModel(&M); |
| |
| for (auto &I:MI.EntryPointVec) |
| for (auto &II:I.second) |
| O << SPIRVEntryPoint(&M, I.first, II, |
| M.get<SPIRVFunction>(II)->getName()); |
| |
| for (auto &I:MI.EntryPointVec) |
| for (auto &II:I.second) |
| MI.get<SPIRVFunction>(II)->encodeExecutionModes(O); |
| |
| O << MI.StringVec; |
| |
| for (auto &I:M.getSourceExtension()) { |
| assert(!I.empty() && "Invalid source extension"); |
| O << SPIRVSourceExtension(&M, I); |
| } |
| |
| O << SPIRVSource(&M); |
| |
| for (auto &I:MI.NamedId) { |
| // Don't output name for entry point since it is redundant |
| bool IsEntryPoint = false; |
| for (auto &EPS:MI.EntryPointSet) |
| if (EPS.second.count(I)) { |
| IsEntryPoint = true; |
| break; |
| } |
| if (!IsEntryPoint) |
| M.getEntry(I)->encodeName(O); |
| } |
| |
| O << MI.MemberNameVec |
| << MI.LineVec |
| << MI.DecGroupVec |
| << MI.DecorateSet |
| << MI.GroupDecVec |
| << MI.ForwardPointerVec |
| << TopologicalSort(MI.TypeVec, MI.ConstVec, MI.VariableVec, |
| MI.ForwardPointerVec) |
| << SPIRVNL() |
| << MI.FuncVec; |
| return O; |
| } |
| |
| template<class T> |
| void SPIRVModuleImpl::addTo(std::vector<T*>& V, SPIRVEntry* E) { |
| V.push_back(static_cast<T *>(E)); |
| } |
| |
| // The first decoration group includes all the previously defined decorates. |
| // The second decoration group includes all the decorates defined between the |
| // first and second decoration group. So long so forth. |
| SPIRVDecorationGroup* |
| SPIRVModuleImpl::addDecorationGroup() { |
| return addDecorationGroup(new SPIRVDecorationGroup(this, getId())); |
| } |
| |
| SPIRVDecorationGroup* |
| SPIRVModuleImpl::addDecorationGroup(SPIRVDecorationGroup* Group) { |
| add(Group); |
| Group->takeDecorates(DecorateSet); |
| DecGroupVec.push_back(Group); |
| SPIRVDBG(spvdbgs() << "[addDecorationGroup] {" << *Group << "}\n"; |
| spvdbgs() << " Remaining DecorateSet: {" << DecorateSet << "}\n"); |
| assert(DecorateSet.empty()); |
| return Group; |
| } |
| |
| SPIRVGroupDecorateGeneric* |
| SPIRVModuleImpl::addGroupDecorateGeneric(SPIRVGroupDecorateGeneric *GDec) { |
| add(GDec); |
| GDec->decorateTargets(); |
| GroupDecVec.push_back(GDec); |
| return GDec; |
| } |
| SPIRVGroupDecorate* |
| SPIRVModuleImpl::addGroupDecorate( |
| SPIRVDecorationGroup* Group, const std::vector<SPIRVEntry*>& Targets) { |
| auto GD = new SPIRVGroupDecorate(Group, getIds(Targets)); |
| addGroupDecorateGeneric(GD); |
| return GD; |
| } |
| |
| SPIRVGroupMemberDecorate* |
| SPIRVModuleImpl::addGroupMemberDecorate( |
| SPIRVDecorationGroup* Group, const std::vector<SPIRVEntry*>& Targets) { |
| auto GMD = new SPIRVGroupMemberDecorate(Group, getIds(Targets)); |
| addGroupDecorateGeneric(GMD); |
| return GMD; |
| } |
| |
| SPIRVString* |
| SPIRVModuleImpl::getString(const std::string& Str) { |
| auto Loc = StrMap.find(Str); |
| if (Loc != StrMap.end()) |
| return Loc->second; |
| auto S = add(new SPIRVString(this, getId(), Str)); |
| StrMap[Str] = S; |
| return S; |
| } |
| |
| SPIRVMemberName* |
| SPIRVModuleImpl::addMemberName(SPIRVTypeStruct* ST, |
| SPIRVWord MemberNumber, const std::string& Name) { |
| return add(new SPIRVMemberName(ST, MemberNumber, Name)); |
| } |
| |
| void SPIRVModuleImpl::addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I, |
| SPIRVId ID) { |
| UnknownStructFieldMap[Struct].push_back(std::make_pair(I, ID)); |
| } |
| |
| std::istream & |
| operator>> (std::istream &I, SPIRVModule &M) { |
| SPIRVDecoder Decoder(I, M); |
| SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl*>(&M); |
| // Disable automatic capability filling. |
| MI.setAutoAddCapability(false); |
| |
| SPIRVWord Magic; |
| Decoder >> Magic; |
| assert(Magic == MagicNumber && "Invalid magic number"); |
| |
| Decoder >> MI.SPIRVVersion; |
| assert(MI.SPIRVVersion <= SPV_VERSION && "Unsupported SPIRV version number"); |
| |
| SPIRVWord Generator = 0; |
| Decoder >> Generator; |
| MI.GeneratorId = Generator >> 16; |
| MI.GeneratorVer = Generator & 0xFFFF; |
| |
| // Bound for Id |
| Decoder >> MI.NextId; |
| |
| Decoder >> MI.InstSchema; |
| assert(MI.InstSchema == SPIRVISCH_Default && "Unsupported instruction schema"); |
| |
| while(Decoder.getWordCountAndOpCode()) |
| Decoder.getEntry(); |
| |
| MI.optimizeDecorates(); |
| MI.resolveUnknownStructFields(); |
| MI.createForwardPointers(); |
| return I; |
| } |
| |
| SPIRVModule * |
| SPIRVModule::createSPIRVModule() { |
| return new SPIRVModuleImpl; |
| } |
| |
| SPIRVValue * |
| SPIRVModuleImpl::getValue(SPIRVId TheId)const { |
| return get<SPIRVValue>(TheId); |
| } |
| |
| SPIRVType * |
| SPIRVModuleImpl::getValueType(SPIRVId TheId)const { |
| return get<SPIRVValue>(TheId)->getType(); |
| } |
| |
| std::vector<SPIRVValue *> |
| SPIRVModuleImpl::getValues(const std::vector<SPIRVId>& IdVec)const { |
| std::vector<SPIRVValue *> ValueVec; |
| for (auto i:IdVec) |
| ValueVec.push_back(getValue(i)); |
| return ValueVec; |
| } |
| |
| std::vector<SPIRVType *> |
| SPIRVModuleImpl::getValueTypes(const std::vector<SPIRVId>& IdVec)const { |
| std::vector<SPIRVType *> TypeVec; |
| for (auto i:IdVec) |
| TypeVec.push_back(getValue(i)->getType()); |
| return TypeVec; |
| } |
| |
| std::vector<SPIRVId> |
| SPIRVModuleImpl::getIds(const std::vector<SPIRVEntry *> &ValueVec)const { |
| std::vector<SPIRVId> IdVec; |
| for (auto i:ValueVec) |
| IdVec.push_back(i->getId()); |
| return IdVec; |
| } |
| |
| std::vector<SPIRVId> |
| SPIRVModuleImpl::getIds(const std::vector<SPIRVValue *> &ValueVec)const { |
| std::vector<SPIRVId> IdVec; |
| for (auto i:ValueVec) |
| IdVec.push_back(i->getId()); |
| return IdVec; |
| } |
| |
| SPIRVInstTemplateBase* |
| SPIRVModuleImpl::addInstTemplate(Op OC, |
| SPIRVBasicBlock* BB, SPIRVType *Ty) { |
| assert (!Ty || !Ty->isTypeVoid()); |
| SPIRVId Id = Ty ? getId() : SPIRVID_INVALID; |
| auto Ins = SPIRVInstTemplateBase::create(OC, Ty, Id, BB, this); |
| BB->addInstruction(Ins); |
| return Ins; |
| } |
| |
| SPIRVInstTemplateBase* |
| SPIRVModuleImpl::addInstTemplate(Op OC, |
| const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty) { |
| assert (!Ty || !Ty->isTypeVoid()); |
| SPIRVId Id = Ty ? getId() : SPIRVID_INVALID; |
| auto Ins = SPIRVInstTemplateBase::create(OC, Ty, Id, Ops, BB, this); |
| BB->addInstruction(Ins); |
| return Ins; |
| } |
| |
| SPIRVDbgInfo::SPIRVDbgInfo(SPIRVModule *TM) |
| :M(TM){ |
| } |
| |
| std::string |
| SPIRVDbgInfo::getEntryPointFileStr(SPIRVExecutionModelKind EM, unsigned I) { |
| if (M->getNumEntryPoints(EM) == 0) |
| return ""; |
| return getFunctionFileStr(M->getEntryPoint(EM, I)); |
| } |
| |
| std::string |
| SPIRVDbgInfo::getFunctionFileStr(SPIRVFunction *F) { |
| if (F->hasLine()) |
| return F->getLine()->getFileNameStr(); |
| return ""; |
| } |
| |
| unsigned |
| SPIRVDbgInfo::getFunctionLineNo(SPIRVFunction *F) { |
| if (F->hasLine()) |
| return F->getLine()->getLine(); |
| return 0; |
| } |
| |
| bool IsSPIRVBinary(const std::string &Img) { |
| if (Img.size() < sizeof(unsigned)) |
| return false; |
| auto Magic = reinterpret_cast<const unsigned*>(Img.data()); |
| return *Magic == MagicNumber; |
| } |
| |
| #ifdef _SPIRV_SUPPORT_TEXT_FMT |
| |
| bool ConvertSPIRV(std::istream &IS, spv_ostream &OS, |
| std::string &ErrMsg, bool FromText, bool ToText) { |
| auto SaveOpt = SPIRVUseTextFormat; |
| SPIRVUseTextFormat = FromText; |
| SPIRVModuleImpl M; |
| IS >> M; |
| if (M.getError(ErrMsg) != SPIRVEC_Success) { |
| SPIRVUseTextFormat = SaveOpt; |
| return false; |
| } |
| SPIRVUseTextFormat = ToText; |
| OS << M; |
| if (M.getError(ErrMsg) != SPIRVEC_Success) { |
| SPIRVUseTextFormat = SaveOpt; |
| return false; |
| } |
| SPIRVUseTextFormat = SaveOpt; |
| return true; |
| } |
| |
| bool IsSPIRVText(const std::string &Img) { |
| std::istringstream SS(Img); |
| unsigned Magic = 0; |
| SS >> Magic; |
| if (SS.bad()) |
| return false; |
| return Magic == MagicNumber; |
| } |
| |
| bool ConvertSPIRV(std::string &Input, std::string &Out, |
| std::string &ErrMsg, bool ToText) { |
| auto FromText = IsSPIRVText(Input); |
| if (ToText == FromText) { |
| Out = Input; |
| return true; |
| } |
| std::istringstream IS(Input); |
| #ifdef _SPIRV_LLVM_API |
| llvm::raw_string_ostream OS(Out); |
| #else |
| std::ostringstream OS; |
| #endif |
| if (!ConvertSPIRV(IS, OS, ErrMsg, FromText, ToText)) |
| return false; |
| Out = OS.str(); |
| return true; |
| } |
| |
| #endif // _SPIRV_SUPPORT_TEXT_FMT |
| |
| } |