1589 lines
52 KiB
C++
1589 lines
52 KiB
C++
//===- 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
|
|
|
|
}
|