You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1875 lines
58 KiB
1875 lines
58 KiB
//===- SPIRVInstruction.h - Class to represent SPIRV instruction -*- 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 defines Instruction class for SPIR-V. |
|
/// |
|
//===----------------------------------------------------------------------===// |
|
|
|
#ifndef SPIRVINSTRUCTION_HPP_ |
|
#define SPIRVINSTRUCTION_HPP_ |
|
|
|
#include "SPIRVEnum.h" |
|
#include "SPIRVIsValidEnum.h" |
|
#include "SPIRVStream.h" |
|
#include "SPIRVValue.h" |
|
#include "SPIRVBasicBlock.h" |
|
#include "SPIRVOpCode.h" |
|
|
|
#include <cassert> |
|
#include <cstdint> |
|
#include <functional> |
|
#include <iostream> |
|
#include <map> |
|
#include <utility> |
|
#include <vector> |
|
#include <unordered_set> |
|
|
|
namespace SPIRV{ |
|
|
|
typedef std::vector<SPIRVValue *> ValueVec; |
|
typedef std::pair<ValueVec::iterator, ValueVec::iterator> ValueRange; |
|
|
|
class SPIRVBasicBlock; |
|
class SPIRVFunction; |
|
|
|
bool isSpecConstantOpAllowedOp(Op OC); |
|
|
|
class SPIRVComponentExecutionScope { |
|
public: |
|
SPIRVComponentExecutionScope(Scope TheScope = ScopeInvocation): |
|
ExecScope(TheScope){} |
|
Scope ExecScope; |
|
}; |
|
|
|
class SPIRVComponentMemorySemanticsMask { |
|
public: |
|
SPIRVComponentMemorySemanticsMask(SPIRVWord TheSema = SPIRVWORD_MAX): |
|
MemSema(TheSema){} |
|
SPIRVWord MemSema; |
|
}; |
|
|
|
class SPIRVComponentOperands { |
|
public: |
|
SPIRVComponentOperands(){}; |
|
SPIRVComponentOperands(const std::vector<SPIRVValue *> &TheOperands): |
|
Operands(TheOperands){}; |
|
SPIRVComponentOperands(std::vector<SPIRVValue *> &&TheOperands): |
|
Operands(std::move(TheOperands)){}; |
|
std::vector<SPIRVValue *> getCompOperands() { |
|
return Operands; |
|
} |
|
std::vector<SPIRVType *> getCompOperandTypes() { |
|
std::vector<SPIRVType *> Tys; |
|
for (auto &I:getCompOperands()) |
|
Tys.push_back(I->getType()); |
|
return Tys; |
|
} |
|
protected: |
|
std::vector<SPIRVValue *> Operands; |
|
}; |
|
|
|
class SPIRVInstruction: public SPIRVValue { |
|
public: |
|
// Complete constructor for instruction with type and id |
|
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, |
|
SPIRVId TheId, SPIRVBasicBlock *TheBB); |
|
// Complete constructor for instruction with module, type and id |
|
SPIRVInstruction(unsigned TheWordCount, Op TheOC, |
|
SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, |
|
SPIRVModule *TheBM); |
|
// Complete constructor for instruction with id but no type |
|
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId, |
|
SPIRVBasicBlock *TheBB); |
|
// Complete constructor for instruction without type and id |
|
SPIRVInstruction(unsigned TheWordCount, Op TheOC, |
|
SPIRVBasicBlock *TheBB); |
|
// Complete constructor for instruction with type but no id |
|
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, |
|
SPIRVBasicBlock *TheBB); |
|
// Incomplete constructor |
|
SPIRVInstruction(Op TheOC = OpNop):SPIRVValue(TheOC), BB(NULL){} |
|
|
|
virtual bool isInst() const { return true;} |
|
SPIRVBasicBlock *getParent() const {return BB;} |
|
SPIRVInstruction *getPrevious() const { return BB->getPrevious(this);} |
|
SPIRVInstruction *getNext() const { return BB->getNext(this);} |
|
virtual std::vector<SPIRVValue *> getOperands(); |
|
std::vector<SPIRVType*> getOperandTypes(); |
|
static std::vector<SPIRVType*> getOperandTypes( |
|
const std::vector<SPIRVValue *> &Ops); |
|
|
|
void setParent(SPIRVBasicBlock *); |
|
void setScope(SPIRVEntry *); |
|
void addFPRoundingMode(SPIRVFPRoundingModeKind Kind) { |
|
addDecorate(DecorationFPRoundingMode, Kind); |
|
} |
|
void eraseFPRoundingMode() { |
|
eraseDecorate(DecorationFPRoundingMode); |
|
} |
|
void setSaturatedConversion(bool Enable) { |
|
if (Enable) |
|
addDecorate(DecorationSaturatedConversion); |
|
else |
|
eraseDecorate(DecorationSaturatedConversion); |
|
} |
|
bool hasFPRoundingMode(SPIRVFPRoundingModeKind *Kind = nullptr) { |
|
SPIRVWord V; |
|
auto Found = hasDecorate(DecorationFPRoundingMode, 0, &V); |
|
if (Found && Kind) |
|
*Kind = static_cast<SPIRVFPRoundingModeKind>(V); |
|
return Found; |
|
} |
|
bool isSaturatedConversion() { |
|
return hasDecorate(DecorationSaturatedConversion) || |
|
OpCode == OpSatConvertSToU || |
|
OpCode == OpSatConvertUToS; |
|
} |
|
|
|
SPIRVBasicBlock* getBasicBlock() const { |
|
return BB; |
|
} |
|
|
|
void setBasicBlock(SPIRVBasicBlock* TheBB) { |
|
BB = TheBB; |
|
if (TheBB) |
|
setModule(TheBB->getModule()); |
|
} |
|
|
|
protected: |
|
void validate()const { |
|
SPIRVValue::validate(); |
|
} |
|
private: |
|
SPIRVBasicBlock *BB; |
|
}; |
|
|
|
class SPIRVInstTemplateBase:public SPIRVInstruction { |
|
public: |
|
/// Create an empty instruction. Mainly for getting format information, |
|
/// e.g. whether an operand is literal. |
|
static SPIRVInstTemplateBase *create(Op TheOC){ |
|
auto Inst = static_cast<SPIRVInstTemplateBase *>(SPIRVEntry::create(TheOC)); |
|
assert(Inst); |
|
Inst->init(); |
|
return Inst; |
|
} |
|
/// Create a instruction without operands. |
|
static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, |
|
SPIRVId TheId, SPIRVBasicBlock *TheBB, |
|
SPIRVModule *TheModule){ |
|
auto Inst = create(TheOC); |
|
Inst->init(TheType, TheId, TheBB, TheModule); |
|
return Inst; |
|
} |
|
/// Create a complete and valid instruction. |
|
static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, |
|
SPIRVId TheId, const std::vector<SPIRVWord> &TheOps, SPIRVBasicBlock *TheBB, |
|
SPIRVModule *TheModule){ |
|
auto Inst = create(TheOC); |
|
Inst->init(TheType, TheId, TheBB, TheModule); |
|
Inst->setOpWords(TheOps); |
|
Inst->validate(); |
|
return Inst; |
|
} |
|
SPIRVInstTemplateBase(Op OC = OpNop) |
|
:SPIRVInstruction(OC), HasVariWC(false){ |
|
init(); |
|
} |
|
virtual ~SPIRVInstTemplateBase(){} |
|
SPIRVInstTemplateBase *init(SPIRVType *TheType, |
|
SPIRVId TheId, SPIRVBasicBlock *TheBB, |
|
SPIRVModule *TheModule){ |
|
assert((TheBB || TheModule) && "Invalid BB or Module"); |
|
if (TheBB) |
|
setBasicBlock(TheBB); |
|
else { |
|
setModule(TheModule); |
|
} |
|
setId(hasId() ? TheId : SPIRVID_INVALID); |
|
setType(hasType() ? TheType : nullptr); |
|
return this; |
|
} |
|
virtual void init() {} |
|
virtual void initImpl(Op OC, bool HasId = true, SPIRVWord WC = 0, |
|
bool VariWC = false, unsigned Lit1 = ~0U, |
|
unsigned Lit2 = ~0U, unsigned Lit3 = ~0U){ |
|
OpCode = OC; |
|
if (!HasId) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
if (WC) |
|
SPIRVEntry::setWordCount(WC); |
|
setHasVariableWordCount(VariWC); |
|
addLit(Lit1); |
|
addLit(Lit2); |
|
addLit(Lit3); |
|
} |
|
virtual bool isOperandLiteral(unsigned I) const { |
|
return Lit.count(I); |
|
} |
|
void addLit(unsigned L) { |
|
if (L != ~0U) |
|
Lit.insert(L); |
|
} |
|
/// \return Expected number of operands. If the instruction has variable |
|
/// number of words, return the minimum. |
|
SPIRVWord getExpectedNumOperands() const { |
|
assert(WordCount > 0 && "Word count not initialized"); |
|
auto Exp = WordCount - 1; |
|
if (hasId()) |
|
--Exp; |
|
if (hasType()) |
|
--Exp; |
|
return Exp; |
|
} |
|
virtual void setOpWordsAndValidate(const std::vector<SPIRVWord> &TheOps) { |
|
setOpWords(TheOps); |
|
validate(); |
|
} |
|
virtual void setOpWords(const std::vector<SPIRVWord> &TheOps) { |
|
SPIRVWord WC = TheOps.size() + 1; |
|
if (hasId()) |
|
++WC; |
|
if (hasType()) |
|
++WC; |
|
if (WordCount) { |
|
if (WordCount == WC) { |
|
// do nothing |
|
} else { |
|
assert(HasVariWC && WC >= WordCount && "Invalid word count"); |
|
SPIRVEntry::setWordCount(WC); |
|
} |
|
} else |
|
SPIRVEntry::setWordCount(WC); |
|
Ops = TheOps; |
|
} |
|
virtual void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
auto NumOps = WordCount - 1; |
|
if (hasId()) |
|
--NumOps; |
|
if (hasType()) |
|
--NumOps; |
|
Ops.resize(NumOps); |
|
} |
|
|
|
std::vector<SPIRVWord> &getOpWords() { |
|
return Ops; |
|
} |
|
|
|
const std::vector<SPIRVWord> &getOpWords() const { |
|
return Ops; |
|
} |
|
|
|
SPIRVWord getOpWord(int I) const { |
|
return Ops[I]; |
|
} |
|
|
|
/// Get operand as value. |
|
/// If the operand is a literal, return it as a uint32 constant. |
|
SPIRVValue *getOpValue(int I) { |
|
return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I]) : |
|
getValue(Ops[I]); |
|
} |
|
|
|
// Get the offset of operands. |
|
// Some instructions skip literals when returning operands. |
|
size_t getOperandOffset() const { |
|
if (hasExecScope() && !isGroupOpCode(OpCode) && !isPipeOpCode(OpCode)) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
// Get operands which are values. |
|
// Drop execution scope and group operation literals. |
|
// Return other literals as uint32 constants. |
|
virtual std::vector<SPIRVValue *> getOperands() { |
|
std::vector<SPIRVValue*> VOps; |
|
auto Offset = getOperandOffset(); |
|
for (size_t I = 0, E = Ops.size() - Offset; I != E; ++I) |
|
VOps.push_back(getOperand(I)); |
|
return VOps; |
|
} |
|
|
|
virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { |
|
std::vector<SPIRVEntry*> Operands; |
|
for (size_t I = getOperandOffset(), E = Ops.size(); I < E; ++I) |
|
if (!isOperandLiteral(I)) |
|
Operands.push_back(getEntry(Ops[I])); |
|
return Operands; |
|
} |
|
|
|
virtual SPIRVValue *getOperand(unsigned I) { |
|
return getOpValue(I + getOperandOffset()); |
|
} |
|
|
|
bool hasExecScope() const { |
|
return SPIRV::hasExecScope(OpCode); |
|
} |
|
|
|
bool hasGroupOperation() const { |
|
return SPIRV::hasGroupOperation(OpCode); |
|
} |
|
|
|
bool getSPIRVGroupOperation(SPIRVGroupOperationKind &GroupOp) const { |
|
if (!hasGroupOperation()) |
|
return false; |
|
GroupOp = static_cast<SPIRVGroupOperationKind>(Ops[1]); |
|
return true; |
|
} |
|
|
|
Scope getExecutionScope() const { |
|
if(!hasExecScope()) |
|
return ScopeInvocation; |
|
return static_cast<Scope>( |
|
static_cast<SPIRVConstant*>(getValue(Ops[0]))->getZExtIntValue()); |
|
} |
|
|
|
bool hasVariableWordCount() const { |
|
return HasVariWC; |
|
} |
|
|
|
void setHasVariableWordCount(bool VariWC) { |
|
HasVariWC = VariWC; |
|
} |
|
|
|
protected: |
|
virtual void encode(spv_ostream &O) const { |
|
auto E = getEncoder(O); |
|
if (hasType()) |
|
E << Type; |
|
if (hasId()) |
|
E << Id; |
|
E << Ops; |
|
} |
|
virtual void decode(std::istream &I) { |
|
auto D = getDecoder(I); |
|
if (hasType()) |
|
D >> Type; |
|
if (hasId()) |
|
D >> Id; |
|
D >> Ops; |
|
} |
|
std::vector<SPIRVWord> Ops; |
|
bool HasVariWC; |
|
std::unordered_set<unsigned> Lit; // Literal operand index |
|
}; |
|
|
|
template<typename BT = SPIRVInstTemplateBase, |
|
Op OC = OpNop, |
|
bool HasId = true, |
|
SPIRVWord WC = 0, |
|
bool HasVariableWC = false, |
|
unsigned Literal1 = ~0U, |
|
unsigned Literal2 = ~0U, |
|
unsigned Literal3 = ~0U> |
|
class SPIRVInstTemplate:public BT { |
|
public: |
|
typedef BT BaseTy; |
|
SPIRVInstTemplate(){ |
|
init(); |
|
} |
|
virtual ~SPIRVInstTemplate(){} |
|
virtual void init() { |
|
this->initImpl(OC, HasId, WC, HasVariableWC, Literal1, Literal2, Literal3); |
|
} |
|
}; |
|
|
|
class SPIRVMemoryAccess { |
|
public: |
|
SPIRVMemoryAccess(const std::vector<SPIRVWord> &TheMemoryAccess): |
|
TheMemoryAccessMask(0), Alignment(0) { |
|
MemoryAccessUpdate(TheMemoryAccess); |
|
} |
|
|
|
SPIRVMemoryAccess() : TheMemoryAccessMask(0), Alignment(0){} |
|
|
|
void MemoryAccessUpdate(const std::vector<SPIRVWord> &MemoryAccess) { |
|
if (!MemoryAccess.size()) |
|
return; |
|
assert((MemoryAccess.size() == 1 || MemoryAccess.size() == 2) && "Invalid memory access operand size"); |
|
TheMemoryAccessMask = MemoryAccess[0]; |
|
if (MemoryAccess[0] & MemoryAccessAlignedMask) { |
|
assert(MemoryAccess.size() == 2 && "Alignment operand is missing"); |
|
Alignment = MemoryAccess[1]; |
|
} |
|
} |
|
SPIRVWord isVolatile() const { return getMemoryAccessMask() & MemoryAccessVolatileMask; } |
|
SPIRVWord isNonTemporal() const { return getMemoryAccessMask() & MemoryAccessNontemporalMask; } |
|
SPIRVWord getMemoryAccessMask() const { return TheMemoryAccessMask; } |
|
SPIRVWord getAlignment() const { return Alignment; } |
|
|
|
protected: |
|
SPIRVWord TheMemoryAccessMask; |
|
SPIRVWord Alignment; |
|
}; |
|
|
|
class SPIRVVariable : public SPIRVInstruction { |
|
public: |
|
// Complete constructor for integer constant |
|
SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, |
|
SPIRVValue *TheInitializer, const std::string &TheName, |
|
SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB, |
|
SPIRVModule *TheM) |
|
:SPIRVInstruction(TheInitializer ? 5 : 4, OpVariable, TheType, |
|
TheId, TheBB, TheM), |
|
StorageClass(TheStorageClass){ |
|
if (TheInitializer) |
|
Initializer.push_back(TheInitializer->getId()); |
|
Name = TheName; |
|
validate(); |
|
} |
|
// Incomplete constructor |
|
SPIRVVariable() :SPIRVInstruction(OpVariable), |
|
StorageClass(StorageClassFunction){} |
|
|
|
SPIRVStorageClassKind getStorageClass() const { return StorageClass; } |
|
SPIRVValue *getInitializer() const { |
|
if (Initializer.empty()) |
|
return nullptr; |
|
assert(Initializer.size() == 1); |
|
return getValue(Initializer[0]); |
|
} |
|
bool isConstant() const { |
|
return hasDecorate(DecorationConstant); |
|
} |
|
bool isBuiltin(SPIRVBuiltinVariableKind *BuiltinKind = nullptr) const { |
|
SPIRVWord Kind; |
|
bool Found = hasDecorate(DecorationBuiltIn, 0, &Kind); |
|
if (!Found) |
|
return false; |
|
if (BuiltinKind) |
|
*BuiltinKind = static_cast<SPIRVBuiltinVariableKind>(Kind); |
|
return true; |
|
} |
|
void setBuiltin(SPIRVBuiltinVariableKind Kind) { |
|
assert(isValid(Kind)); |
|
addDecorate(new SPIRVDecorate(DecorationBuiltIn, this, Kind)); |
|
} |
|
void setIsConstant(bool Is) { |
|
if (Is) |
|
addDecorate(new SPIRVDecorate(DecorationConstant, this)); |
|
else |
|
eraseDecorate(DecorationConstant); |
|
} |
|
virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { |
|
if (SPIRVValue *V = getInitializer()) |
|
return std::vector<SPIRVEntry*>(1, V); |
|
return std::vector<SPIRVEntry*>(); |
|
} |
|
protected: |
|
void validate() const { |
|
SPIRVValue::validate(); |
|
assert(isValid(StorageClass)); |
|
assert(Initializer.size() == 1 || Initializer.empty()); |
|
} |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Initializer.resize(WordCount - 4); |
|
} |
|
_SPIRV_DEF_ENCDEC4(Type, Id, StorageClass, Initializer) |
|
|
|
SPIRVStorageClassKind StorageClass; |
|
std::vector<SPIRVId> Initializer; |
|
}; |
|
|
|
class SPIRVStore:public SPIRVInstruction, public SPIRVMemoryAccess { |
|
public: |
|
const static SPIRVWord FixedWords = 3; |
|
// Complete constructor |
|
SPIRVStore(SPIRVId PointerId, SPIRVId ValueId, |
|
const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OpStore, |
|
TheBB), |
|
SPIRVMemoryAccess(TheMemoryAccess), |
|
MemoryAccess(TheMemoryAccess), |
|
PtrId(PointerId), |
|
ValId(ValueId){ |
|
setAttr(); |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVStore():SPIRVInstruction(OpStore), SPIRVMemoryAccess(), |
|
PtrId(SPIRVID_INVALID), ValId(SPIRVID_INVALID){ |
|
setAttr(); |
|
} |
|
|
|
SPIRVValue *getSrc() const { return getValue(ValId);} |
|
SPIRVValue *getDst() const { return getValue(PtrId);} |
|
protected: |
|
void setAttr() { |
|
setHasNoType(); |
|
setHasNoId(); |
|
} |
|
|
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
MemoryAccess.resize(TheWordCount - FixedWords); |
|
} |
|
void encode(spv_ostream &O) const { |
|
getEncoder(O) << PtrId << ValId << MemoryAccess; |
|
} |
|
|
|
void decode(std::istream &I) { |
|
getDecoder(I) >> PtrId >> ValId >> MemoryAccess; |
|
MemoryAccessUpdate(MemoryAccess); |
|
} |
|
|
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
if (getSrc()->isForward() || getDst()->isForward()) |
|
return; |
|
assert(getValueType(PtrId)->getPointerElementType() == getValueType(ValId) |
|
&& "Inconsistent operand types"); |
|
} |
|
private: |
|
std::vector<SPIRVWord> MemoryAccess; |
|
SPIRVId PtrId; |
|
SPIRVId ValId; |
|
}; |
|
|
|
class SPIRVLoad:public SPIRVInstruction, public SPIRVMemoryAccess { |
|
public: |
|
const static SPIRVWord FixedWords = 4; |
|
// Complete constructor |
|
SPIRVLoad(SPIRVId TheId, SPIRVId PointerId, |
|
const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(FixedWords + TheMemoryAccess.size() , OpLoad, |
|
TheBB->getValueType(PointerId)->getPointerElementType(), TheId, TheBB), |
|
SPIRVMemoryAccess(TheMemoryAccess), PtrId(PointerId), |
|
MemoryAccess(TheMemoryAccess) { |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVLoad():SPIRVInstruction(OpLoad), SPIRVMemoryAccess(), |
|
PtrId(SPIRVID_INVALID){} |
|
|
|
SPIRVValue *getSrc() const { return Module->get<SPIRVValue>(PtrId);} |
|
|
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
MemoryAccess.resize(TheWordCount - FixedWords); |
|
} |
|
|
|
void encode(spv_ostream &O) const { |
|
getEncoder(O) << Type << Id << PtrId << MemoryAccess; |
|
} |
|
|
|
void decode(std::istream &I) { |
|
getDecoder(I) >> Type >> Id >> PtrId >> MemoryAccess; |
|
MemoryAccessUpdate(MemoryAccess); |
|
} |
|
|
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
assert((getValue(PtrId)->isForward() || |
|
Type == getValueType(PtrId)->getPointerElementType()) && |
|
"Inconsistent types"); |
|
} |
|
private: |
|
SPIRVId PtrId; |
|
std::vector<SPIRVWord> MemoryAccess; |
|
}; |
|
|
|
class SPIRVBinary:public SPIRVInstTemplateBase { |
|
protected: |
|
void validate()const { |
|
SPIRVId Op1 = Ops[0]; |
|
SPIRVId Op2 = Ops[1]; |
|
SPIRVType *op1Ty, *op2Ty; |
|
SPIRVInstruction::validate(); |
|
if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) |
|
return; |
|
if (getValueType(Op1)->isTypeVector()) { |
|
op1Ty = getValueType(Op1)->getVectorComponentType(); |
|
op2Ty = getValueType(Op2)->getVectorComponentType(); |
|
assert(getValueType(Op1)->getVectorComponentCount() == |
|
getValueType(Op2)->getVectorComponentCount() && |
|
"Inconsistent Vector component width"); |
|
} |
|
else { |
|
op1Ty = getValueType(Op1); |
|
op2Ty = getValueType(Op2); |
|
} |
|
|
|
if (isBinaryOpCode(OpCode)) { |
|
assert(getValueType(Op1)== getValueType(Op2) && |
|
"Invalid type for binary instruction"); |
|
assert((op1Ty->isTypeInt() || op2Ty->isTypeFloat()) && |
|
"Invalid type for Binary instruction"); |
|
assert((op1Ty->getBitWidth() == op2Ty->getBitWidth()) && |
|
"Inconsistent BitWidth"); |
|
} else if (isShiftOpCode(OpCode)) { |
|
assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && |
|
"Invalid type for shift instruction"); |
|
} else if (isLogicalOpCode(OpCode)) { |
|
assert((op1Ty->isTypeBool() || op2Ty->isTypeBool()) && |
|
"Invalid type for logical instruction"); |
|
} else if (isBitwiseOpCode(OpCode)) { |
|
assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && |
|
"Invalid type for bitwise instruction"); |
|
assert((op1Ty->getIntegerBitWidth() == op2Ty->getIntegerBitWidth()) && |
|
"Inconsistent BitWidth"); |
|
} else { |
|
assert(0 && "Invalid op code!"); |
|
} |
|
} |
|
}; |
|
|
|
template<Op OC> |
|
class SPIRVBinaryInst:public SPIRVInstTemplate<SPIRVBinary, OC, true, 5, false> { |
|
}; |
|
|
|
/* ToDo: SMod and FMod to be added */ |
|
#define _SPIRV_OP(x) typedef SPIRVBinaryInst<Op##x> SPIRV##x; |
|
_SPIRV_OP(IAdd) |
|
_SPIRV_OP(FAdd) |
|
_SPIRV_OP(ISub) |
|
_SPIRV_OP(FSub) |
|
_SPIRV_OP(IMul) |
|
_SPIRV_OP(FMul) |
|
_SPIRV_OP(UDiv) |
|
_SPIRV_OP(SDiv) |
|
_SPIRV_OP(FDiv) |
|
_SPIRV_OP(SRem) |
|
_SPIRV_OP(FRem) |
|
_SPIRV_OP(UMod) |
|
_SPIRV_OP(ShiftLeftLogical) |
|
_SPIRV_OP(ShiftRightLogical) |
|
_SPIRV_OP(ShiftRightArithmetic) |
|
_SPIRV_OP(LogicalAnd) |
|
_SPIRV_OP(LogicalOr) |
|
_SPIRV_OP(LogicalEqual) |
|
_SPIRV_OP(LogicalNotEqual) |
|
_SPIRV_OP(BitwiseAnd) |
|
_SPIRV_OP(BitwiseOr) |
|
_SPIRV_OP(BitwiseXor) |
|
_SPIRV_OP(Dot) |
|
#undef _SPIRV_OP |
|
|
|
template<Op TheOpCode> |
|
class SPIRVInstNoOperand:public SPIRVInstruction { |
|
public: |
|
// Complete constructor |
|
SPIRVInstNoOperand(SPIRVBasicBlock *TheBB):SPIRVInstruction(1, TheOpCode, |
|
TheBB){ |
|
setAttr(); |
|
validate(); |
|
} |
|
// Incomplete constructor |
|
SPIRVInstNoOperand():SPIRVInstruction(TheOpCode){ |
|
setAttr(); |
|
} |
|
protected: |
|
void setAttr() { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
_SPIRV_DEF_ENCDEC0 |
|
}; |
|
|
|
typedef SPIRVInstNoOperand<OpReturn> SPIRVReturn; |
|
|
|
class SPIRVReturnValue:public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpReturnValue; |
|
// Complete constructor |
|
SPIRVReturnValue(SPIRVValue *TheReturnValue, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(2, OC, TheBB), ReturnValueId(TheReturnValue->getId()){ |
|
setAttr(); |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVReturnValue():SPIRVInstruction(OC), ReturnValueId(SPIRVID_INVALID) { |
|
setAttr(); |
|
} |
|
|
|
SPIRVValue *getReturnValue() const { |
|
return getValue(ReturnValueId); |
|
} |
|
protected: |
|
void setAttr() { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
_SPIRV_DEF_ENCDEC1(ReturnValueId) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
} |
|
SPIRVId ReturnValueId; |
|
}; |
|
|
|
class SPIRVBranch:public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpBranch; |
|
// Complete constructor |
|
SPIRVBranch(SPIRVLabel *TheTargetLabel,SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(2, OC, TheBB), TargetLabelId(TheTargetLabel->getId()) { |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVBranch():SPIRVInstruction(OC), TargetLabelId(SPIRVID_INVALID) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
SPIRVValue *getTargetLabel() const { |
|
return getValue(TargetLabelId); |
|
} |
|
protected: |
|
_SPIRV_DEF_ENCDEC1(TargetLabelId) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
assert(WordCount == 2); |
|
assert(OpCode == OC); |
|
assert(getTargetLabel()->isLabel() || getTargetLabel()->isForward()); |
|
} |
|
SPIRVId TargetLabelId; |
|
}; |
|
|
|
class SPIRVBranchConditional:public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpBranchConditional; |
|
// Complete constructor |
|
SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel, |
|
SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(4, OC, TheBB), ConditionId(TheCondition->getId()), |
|
TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){ |
|
validate(); |
|
} |
|
SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel, |
|
SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB, SPIRVWord TrueWeight, |
|
SPIRVWord FalseWeight) |
|
:SPIRVInstruction(6, OC, TheBB), ConditionId(TheCondition->getId()), |
|
TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){ |
|
BranchWeights.push_back(TrueWeight); |
|
BranchWeights.push_back(FalseWeight); |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVBranchConditional():SPIRVInstruction(OC), ConditionId(SPIRVID_INVALID), |
|
TrueLabelId(SPIRVID_INVALID), FalseLabelId(SPIRVID_INVALID) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
SPIRVValue *getCondition() const { |
|
return getValue(ConditionId); |
|
} |
|
SPIRVLabel *getTrueLabel() const { |
|
return get<SPIRVLabel>(TrueLabelId); |
|
} |
|
SPIRVLabel *getFalseLabel() const { |
|
return get<SPIRVLabel>(FalseLabelId); |
|
} |
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
BranchWeights.resize(TheWordCount - 4); |
|
} |
|
_SPIRV_DEF_ENCDEC4(ConditionId, TrueLabelId, FalseLabelId, BranchWeights) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
assert(WordCount == 4 || WordCount == 6); |
|
assert(WordCount == BranchWeights.size() + 4); |
|
assert(OpCode == OC); |
|
assert(getCondition()->isForward() || |
|
getCondition()->getType()->isTypeBool()); |
|
assert(getTrueLabel()->isForward() || getTrueLabel()->isLabel()); |
|
assert(getFalseLabel()->isForward() || getFalseLabel()->isLabel()); |
|
} |
|
SPIRVId ConditionId; |
|
SPIRVId TrueLabelId; |
|
SPIRVId FalseLabelId; |
|
std::vector<SPIRVWord> BranchWeights; |
|
}; |
|
|
|
class SPIRVPhi: public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpPhi; |
|
static const SPIRVWord FixedWordCount = 3; |
|
SPIRVPhi(SPIRVType *TheType, SPIRVId TheId, |
|
const std::vector<SPIRVValue *> &ThePairs, SPIRVBasicBlock *BB) |
|
:SPIRVInstruction(ThePairs.size() + FixedWordCount, OC, TheType, TheId, BB){ |
|
Pairs = getIds(ThePairs); |
|
validate(); |
|
assert(BB && "Invalid BB"); |
|
} |
|
SPIRVPhi():SPIRVInstruction(OC) {} |
|
std::vector<SPIRVValue *> getPairs() { |
|
return getValues(Pairs); |
|
} |
|
void addPair(SPIRVValue *Value, SPIRVBasicBlock *BB) { |
|
Pairs.push_back(Value->getId()); |
|
Pairs.push_back(BB->getId()); |
|
WordCount = Pairs.size() + FixedWordCount; |
|
validate(); |
|
} |
|
void setPairs(const std::vector<SPIRVValue *> &ThePairs) { |
|
Pairs = getIds(ThePairs); |
|
WordCount = Pairs.size() + FixedWordCount; |
|
validate(); |
|
} |
|
void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *, |
|
size_t)> Func) { |
|
for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { |
|
SPIRVEntry *Value, *BB; |
|
if (!Module->exist(Pairs[2*I], &Value) || |
|
!Module->exist(Pairs[2*I+1], &BB)) |
|
continue; |
|
Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB), |
|
I); |
|
} |
|
} |
|
void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *)> Func) |
|
const { |
|
for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { |
|
SPIRVEntry *Value, *BB; |
|
if (!Module->exist(Pairs[2*I], &Value) || |
|
!Module->exist(Pairs[2*I+1], &BB)) |
|
continue; |
|
Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB)); |
|
} |
|
} |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Pairs.resize(TheWordCount - FixedWordCount); |
|
} |
|
_SPIRV_DEF_ENCDEC3(Type, Id, Pairs) |
|
void validate()const { |
|
assert(WordCount == Pairs.size() + FixedWordCount); |
|
assert(OpCode == OC); |
|
assert(Pairs.size() % 2 == 0); |
|
foreachPair([=](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB){ |
|
assert(IncomingV->isForward() || IncomingV->getType() == Type); |
|
assert(IncomingBB->isBasicBlock() || IncomingBB->isForward()); |
|
}); |
|
SPIRVInstruction::validate(); |
|
} |
|
protected: |
|
std::vector<SPIRVId> Pairs; |
|
}; |
|
|
|
class SPIRVCompare:public SPIRVInstTemplateBase { |
|
protected: |
|
void validate()const { |
|
auto Op1 = Ops[0]; |
|
auto Op2 = Ops[1]; |
|
SPIRVType *op1Ty, *op2Ty, *resTy; |
|
SPIRVInstruction::validate(); |
|
if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) |
|
return; |
|
|
|
if (getValueType(Op1)->isTypeVector()) { |
|
op1Ty = getValueType(Op1)->getVectorComponentType(); |
|
op2Ty = getValueType(Op2)->getVectorComponentType(); |
|
resTy = Type->getVectorComponentType(); |
|
assert(getValueType(Op1)->getVectorComponentCount() == |
|
getValueType(Op2)->getVectorComponentCount() && |
|
"Inconsistent Vector component width"); |
|
} |
|
else { |
|
op1Ty = getValueType(Op1); |
|
op2Ty = getValueType(Op2); |
|
resTy = Type; |
|
} |
|
assert(isCmpOpCode(OpCode) && "Invalid op code for cmp inst"); |
|
assert((resTy->isTypeBool() || resTy->isTypeInt()) && |
|
"Invalid type for compare instruction"); |
|
assert(op1Ty == op2Ty && "Inconsistent types"); |
|
} |
|
}; |
|
|
|
template<Op OC> |
|
class SPIRVCmpInst:public SPIRVInstTemplate<SPIRVCompare, OC, true, 5, false> { |
|
}; |
|
|
|
#define _SPIRV_OP(x) typedef SPIRVCmpInst<Op##x> SPIRV##x; |
|
_SPIRV_OP(IEqual) |
|
_SPIRV_OP(FOrdEqual) |
|
_SPIRV_OP(FUnordEqual) |
|
_SPIRV_OP(INotEqual) |
|
_SPIRV_OP(FOrdNotEqual) |
|
_SPIRV_OP(FUnordNotEqual) |
|
_SPIRV_OP(ULessThan) |
|
_SPIRV_OP(SLessThan) |
|
_SPIRV_OP(FOrdLessThan) |
|
_SPIRV_OP(FUnordLessThan) |
|
_SPIRV_OP(UGreaterThan) |
|
_SPIRV_OP(SGreaterThan) |
|
_SPIRV_OP(FOrdGreaterThan) |
|
_SPIRV_OP(FUnordGreaterThan) |
|
_SPIRV_OP(ULessThanEqual) |
|
_SPIRV_OP(SLessThanEqual) |
|
_SPIRV_OP(FOrdLessThanEqual) |
|
_SPIRV_OP(FUnordLessThanEqual) |
|
_SPIRV_OP(UGreaterThanEqual) |
|
_SPIRV_OP(SGreaterThanEqual) |
|
_SPIRV_OP(FOrdGreaterThanEqual) |
|
_SPIRV_OP(FUnordGreaterThanEqual) |
|
_SPIRV_OP(LessOrGreater) |
|
_SPIRV_OP(Ordered) |
|
_SPIRV_OP(Unordered) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVSelect:public SPIRVInstruction { |
|
public: |
|
// Complete constructor |
|
SPIRVSelect(SPIRVId TheId, SPIRVId TheCondition, SPIRVId TheOp1, SPIRVId TheOp2, |
|
SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(6, OpSelect, TheBB->getValueType(TheOp1), TheId, |
|
TheBB), Condition(TheCondition), Op1(TheOp1), Op2(TheOp2){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVSelect():SPIRVInstruction(OpSelect), Condition(SPIRVID_INVALID), |
|
Op1(SPIRVID_INVALID), Op2(SPIRVID_INVALID){} |
|
SPIRVValue *getCondition() { return getValue(Condition);} |
|
SPIRVValue *getTrueValue() { return getValue(Op1);} |
|
SPIRVValue *getFalseValue() { return getValue(Op2);} |
|
protected: |
|
_SPIRV_DEF_ENCDEC5(Type, Id, Condition, Op1, Op2) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
if (getValue(Condition)->isForward() || |
|
getValue(Op1)->isForward() || |
|
getValue(Op2)->isForward()) |
|
return; |
|
|
|
SPIRVType *conTy = getValueType(Condition)->isTypeVector() ? |
|
getValueType(Condition)->getVectorComponentType() : |
|
getValueType(Condition); |
|
(void) conTy; |
|
assert(conTy->isTypeBool() && "Invalid type"); |
|
assert(getType() == getValueType(Op1) && getType() == getValueType(Op2) && |
|
"Inconsistent type"); |
|
} |
|
SPIRVId Condition; |
|
SPIRVId Op1; |
|
SPIRVId Op2; |
|
}; |
|
|
|
class SPIRVSwitch: public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpSwitch; |
|
static const SPIRVWord FixedWordCount = 3; |
|
SPIRVSwitch(SPIRVValue *TheSelect, SPIRVBasicBlock *TheDefault, |
|
const std::vector<std::pair<SPIRVWord, SPIRVBasicBlock *>> &ThePairs, |
|
SPIRVBasicBlock *BB) |
|
:SPIRVInstruction(ThePairs.size() * 2 + FixedWordCount, OC, BB), |
|
Select(TheSelect->getId()), Default(TheDefault->getId()) { |
|
for (auto &I:ThePairs) { |
|
Pairs.push_back(I.first); |
|
Pairs.push_back(I.second->getId()); |
|
} |
|
validate(); |
|
assert(BB && "Invalid BB"); |
|
} |
|
SPIRVSwitch():SPIRVInstruction(OC), Select(SPIRVWORD_MAX), |
|
Default(SPIRVWORD_MAX) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
std::vector<SPIRVValue *> getPairs() { |
|
return getValues(Pairs); |
|
} |
|
SPIRVValue *getSelect() const { return getValue(Select);} |
|
SPIRVBasicBlock *getDefault() const { |
|
return static_cast<SPIRVBasicBlock *>(getValue(Default)); |
|
} |
|
size_t getNumPairs() const { return Pairs.size()/2;} |
|
void foreachPair(std::function<void(SPIRVWord, SPIRVBasicBlock *, size_t)> Func) |
|
const { |
|
for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { |
|
SPIRVEntry *BB; |
|
if (!Module->exist(Pairs[2*I+1], &BB)) |
|
continue; |
|
Func(Pairs[2*I], static_cast<SPIRVBasicBlock *>(BB), I); |
|
} |
|
} |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Pairs.resize(TheWordCount - FixedWordCount); |
|
} |
|
_SPIRV_DEF_ENCDEC3(Select, Default, Pairs) |
|
void validate()const { |
|
assert(WordCount == Pairs.size() + FixedWordCount); |
|
assert(OpCode == OC); |
|
assert(Pairs.size() % 2 == 0); |
|
foreachPair([=](SPIRVWord Literal, SPIRVBasicBlock *BB, size_t Index){ |
|
assert(BB->isBasicBlock() || BB->isForward()); |
|
}); |
|
SPIRVInstruction::validate(); |
|
} |
|
protected: |
|
SPIRVId Select; |
|
SPIRVId Default; |
|
std::vector<SPIRVWord> Pairs; |
|
}; |
|
|
|
class SPIRVUnary:public SPIRVInstTemplateBase { |
|
protected: |
|
void validate()const { |
|
auto Op = Ops[0]; |
|
SPIRVInstruction::validate(); |
|
if (getValue(Op)->isForward()) |
|
return; |
|
if (isGenericNegateOpCode(OpCode)) { |
|
SPIRVType *resTy = Type->isTypeVector() ? |
|
Type->getVectorComponentType() : Type; |
|
SPIRVType *opTy = Type->isTypeVector() ? |
|
getValueType(Op)->getVectorComponentType() : getValueType(Op); |
|
|
|
assert(getType() == getValueType(Op) && |
|
"Inconsistent type"); |
|
(void) resTy; |
|
assert((resTy->isTypeInt() || resTy->isTypeFloat()) && |
|
"Invalid type for Generic Negate instruction"); |
|
(void) opTy; |
|
assert((resTy->getBitWidth() == opTy->getBitWidth()) && |
|
"Invalid bitwidth for Generic Negate instruction"); |
|
assert((Type->isTypeVector() ? (Type->getVectorComponentCount() == |
|
getValueType(Op)->getVectorComponentCount()): 1) && |
|
"Invalid vector component Width for Generic Negate instruction"); |
|
} |
|
} |
|
}; |
|
|
|
template<Op OC> |
|
class SPIRVUnaryInst:public SPIRVInstTemplate<SPIRVUnary, OC, true, 4, false> { |
|
}; |
|
|
|
#define _SPIRV_OP(x) typedef SPIRVUnaryInst<Op##x> SPIRV##x; |
|
_SPIRV_OP(ConvertFToU) |
|
_SPIRV_OP(ConvertFToS) |
|
_SPIRV_OP(ConvertSToF) |
|
_SPIRV_OP(ConvertUToF) |
|
_SPIRV_OP(UConvert) |
|
_SPIRV_OP(SConvert) |
|
_SPIRV_OP(FConvert) |
|
_SPIRV_OP(SatConvertSToU) |
|
_SPIRV_OP(SatConvertUToS) |
|
_SPIRV_OP(ConvertPtrToU) |
|
_SPIRV_OP(ConvertUToPtr) |
|
_SPIRV_OP(PtrCastToGeneric) |
|
_SPIRV_OP(GenericCastToPtr) |
|
_SPIRV_OP(Bitcast) |
|
_SPIRV_OP(SNegate) |
|
_SPIRV_OP(FNegate) |
|
_SPIRV_OP(Not) |
|
_SPIRV_OP(LogicalNot) |
|
_SPIRV_OP(IsNan) |
|
_SPIRV_OP(IsInf) |
|
_SPIRV_OP(IsFinite) |
|
_SPIRV_OP(IsNormal) |
|
_SPIRV_OP(SignBitSet) |
|
_SPIRV_OP(Any) |
|
_SPIRV_OP(All) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVAccessChainBase :public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVValue *getBase() { return this->getValue(this->Ops[0]);} |
|
std::vector<SPIRVValue *> getIndices()const { |
|
std::vector<SPIRVWord> IndexWords(this->Ops.begin() + 1, this->Ops.end()); |
|
return this->getValues(IndexWords); |
|
} |
|
bool isInBounds() { |
|
return OpCode == OpInBoundsAccessChain || |
|
OpCode == OpInBoundsPtrAccessChain; |
|
} |
|
bool hasPtrIndex() { |
|
return OpCode == OpPtrAccessChain || |
|
OpCode == OpInBoundsPtrAccessChain; |
|
} |
|
}; |
|
|
|
template<Op OC, unsigned FixedWC> |
|
class SPIRVAccessChainGeneric |
|
:public SPIRVInstTemplate<SPIRVAccessChainBase, OC, true, FixedWC, true> { |
|
}; |
|
|
|
typedef SPIRVAccessChainGeneric<OpAccessChain, 4> SPIRVAccessChain; |
|
typedef SPIRVAccessChainGeneric<OpInBoundsAccessChain, 4> |
|
SPIRVInBoundsAccessChain; |
|
typedef SPIRVAccessChainGeneric<OpPtrAccessChain, 5> SPIRVPtrAccessChain; |
|
typedef SPIRVAccessChainGeneric<OpInBoundsPtrAccessChain, 5> |
|
SPIRVInBoundsPtrAccessChain; |
|
|
|
template<Op OC, SPIRVWord FixedWordCount> |
|
class SPIRVFunctionCallGeneric: public SPIRVInstruction { |
|
public: |
|
SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, |
|
const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) |
|
:SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB), |
|
Args(TheArgs){ |
|
validate(); |
|
assert(BB && "Invalid BB"); |
|
} |
|
SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, |
|
const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB) |
|
:SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB) { |
|
Args = getIds(TheArgs); |
|
validate(); |
|
assert(BB && "Invalid BB"); |
|
} |
|
SPIRVFunctionCallGeneric():SPIRVInstruction(OC) {} |
|
const std::vector<SPIRVWord> &getArguments() { |
|
return Args; |
|
} |
|
std::vector<SPIRVValue *> getArgumentValues() { |
|
return getValues(Args); |
|
} |
|
std::vector<SPIRVType *> getArgumentValueTypes()const { |
|
std::vector<SPIRVType *> ArgTypes; |
|
for (auto &I:Args) |
|
ArgTypes.push_back(getValue(I)->getType()); |
|
return ArgTypes; |
|
} |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Args.resize(TheWordCount - FixedWordCount); |
|
} |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
} |
|
protected: |
|
std::vector<SPIRVWord> Args; |
|
}; |
|
|
|
class SPIRVFunctionCall: |
|
public SPIRVFunctionCallGeneric<OpFunctionCall, 4> { |
|
public: |
|
SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction, |
|
const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB); |
|
SPIRVFunctionCall():FunctionId(SPIRVID_INVALID) {} |
|
SPIRVFunction *getFunction()const { |
|
return get<SPIRVFunction>(FunctionId); |
|
} |
|
_SPIRV_DEF_ENCDEC4(Type, Id, FunctionId, Args) |
|
void validate()const; |
|
bool isOperandLiteral(unsigned Index) const { return false;} |
|
protected: |
|
SPIRVId FunctionId; |
|
}; |
|
|
|
class SPIRVExtInst: public SPIRVFunctionCallGeneric<OpExtInst, 5> { |
|
public: |
|
SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, |
|
SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint, |
|
const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) |
|
:SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB), |
|
ExtSetId(TheBuiltinSet), |
|
ExtOp(TheEntryPoint) { |
|
setExtSetKindById(); |
|
validate(); |
|
} |
|
SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, |
|
SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint, |
|
const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB) |
|
:SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB), |
|
ExtSetId(TheBuiltinSet), |
|
ExtOp(TheEntryPoint) { |
|
setExtSetKindById(); |
|
validate(); |
|
} |
|
SPIRVExtInst(SPIRVExtInstSetKind SetKind = SPIRVEIS_Count, |
|
unsigned ExtOC = SPIRVWORD_MAX) |
|
:ExtSetId(SPIRVWORD_MAX), ExtOp(ExtOC), ExtSetKind(SetKind) {} |
|
void setExtSetId(unsigned Set) { ExtSetId = Set;} |
|
void setExtOp(unsigned ExtOC) { ExtOp = ExtOC;} |
|
SPIRVId getExtSetId()const { |
|
return ExtSetId; |
|
} |
|
SPIRVWord getExtOp()const { |
|
return ExtOp; |
|
} |
|
void setExtSetKindById() { |
|
assert(Module && "Invalid module"); |
|
ExtSetKind = Module->getBuiltinSet(ExtSetId); |
|
assert(ExtSetKind == SPIRVEIS_OpenCL && "not supported"); |
|
} |
|
void encode(spv_ostream &O) const { |
|
getEncoder(O) << Type << Id << ExtSetId; |
|
switch(ExtSetKind) { |
|
case SPIRVEIS_OpenCL: |
|
getEncoder(O) << ExtOpOCL; |
|
break; |
|
default: |
|
assert(0 && "not supported"); |
|
getEncoder(O) << ExtOp; |
|
} |
|
getEncoder(O) << Args; |
|
} |
|
void decode(std::istream &I) { |
|
getDecoder(I) >> Type >> Id >> ExtSetId; |
|
setExtSetKindById(); |
|
switch(ExtSetKind) { |
|
case SPIRVEIS_OpenCL: |
|
getDecoder(I) >> ExtOpOCL; |
|
break; |
|
default: |
|
assert(0 && "not supported"); |
|
getDecoder(I) >> ExtOp; |
|
} |
|
getDecoder(I) >> Args; |
|
} |
|
void validate()const { |
|
SPIRVFunctionCallGeneric::validate(); |
|
validateBuiltin(ExtSetId, ExtOp); |
|
} |
|
bool isOperandLiteral(unsigned Index) const { |
|
assert(ExtSetKind == SPIRVEIS_OpenCL && |
|
"Unsupported extended instruction set"); |
|
auto EOC = static_cast<OCLExtOpKind>(ExtOp); |
|
switch(EOC) { |
|
default: |
|
return false; |
|
case OpenCLLIB::Vloadn: |
|
case OpenCLLIB::Vload_halfn: |
|
case OpenCLLIB::Vloada_halfn: |
|
return Index == 2; |
|
case OpenCLLIB::Vstore_half_r: |
|
case OpenCLLIB::Vstore_halfn_r: |
|
case OpenCLLIB::Vstorea_halfn_r: |
|
return Index == 3; |
|
} |
|
} |
|
protected: |
|
SPIRVId ExtSetId; |
|
union { |
|
SPIRVWord ExtOp; |
|
OCLExtOpKind ExtOpOCL; |
|
}; |
|
SPIRVExtInstSetKind ExtSetKind; |
|
}; |
|
|
|
class SPIRVCompositeExtract:public SPIRVInstruction { |
|
public: |
|
const static Op OC = OpCompositeExtract; |
|
// Complete constructor |
|
SPIRVCompositeExtract(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheComposite, |
|
const std::vector<SPIRVWord>& TheIndices, SPIRVBasicBlock *TheBB): |
|
SPIRVInstruction(TheIndices.size() + 4, OC, TheType, TheId, TheBB), |
|
Composite(TheComposite->getId()), Indices(TheIndices){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVCompositeExtract():SPIRVInstruction(OC), Composite(SPIRVID_INVALID){} |
|
|
|
SPIRVValue *getComposite() { return getValue(Composite);} |
|
const std::vector<SPIRVWord>& getIndices()const { return Indices;} |
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Indices.resize(TheWordCount - 4); |
|
} |
|
_SPIRV_DEF_ENCDEC4(Type, Id, Composite, Indices) |
|
// ToDo: validate the result type is consistent with the base type and indices |
|
// need to trace through the base type for struct types |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
assert(getValueType(Composite)->isTypeArray() || |
|
getValueType(Composite)->isTypeStruct() || |
|
getValueType(Composite)->isTypeVector()); |
|
} |
|
SPIRVId Composite; |
|
std::vector<SPIRVWord> Indices; |
|
}; |
|
|
|
class SPIRVCompositeInsert:public SPIRVInstruction { |
|
public: |
|
const static Op OC = OpCompositeInsert; |
|
const static SPIRVWord FixedWordCount = 5; |
|
// Complete constructor |
|
SPIRVCompositeInsert(SPIRVId TheId, SPIRVValue *TheObject, |
|
SPIRVValue *TheComposite, const std::vector<SPIRVWord>& TheIndices, |
|
SPIRVBasicBlock *TheBB): |
|
SPIRVInstruction(TheIndices.size() + FixedWordCount, OC, |
|
TheComposite->getType(), TheId, TheBB), |
|
Object(TheObject->getId()), Composite(TheComposite->getId()), |
|
Indices(TheIndices){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVCompositeInsert():SPIRVInstruction(OC), Object(SPIRVID_INVALID), |
|
Composite(SPIRVID_INVALID){} |
|
|
|
SPIRVValue *getObject() { return getValue(Object);} |
|
SPIRVValue *getComposite() { return getValue(Composite);} |
|
const std::vector<SPIRVWord>& getIndices()const { return Indices;} |
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Indices.resize(TheWordCount - FixedWordCount); |
|
} |
|
_SPIRV_DEF_ENCDEC5(Type, Id, Object, Composite, Indices) |
|
// ToDo: validate the object type is consistent with the base type and indices |
|
// need to trace through the base type for struct types |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
assert(OpCode == OC); |
|
assert(WordCount == Indices.size() + FixedWordCount); |
|
assert(getValueType(Composite)->isTypeArray() || |
|
getValueType(Composite)->isTypeStruct() || |
|
getValueType(Composite)->isTypeVector()); |
|
assert(Type == getValueType(Composite)); |
|
} |
|
SPIRVId Object; |
|
SPIRVId Composite; |
|
std::vector<SPIRVWord> Indices; |
|
}; |
|
|
|
class SPIRVCopyObject :public SPIRVInstruction { |
|
public: |
|
const static Op OC = OpCopyObject; |
|
|
|
// Complete constructor |
|
SPIRVCopyObject(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheOperand, |
|
SPIRVBasicBlock *TheBB) : |
|
SPIRVInstruction(4, OC, TheType, TheId, TheBB), |
|
Operand(TheOperand->getId()) { |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVCopyObject() :SPIRVInstruction(OC), Operand(SPIRVID_INVALID) {} |
|
|
|
SPIRVValue *getOperand() { return getValue(Operand); } |
|
|
|
protected: |
|
_SPIRV_DEF_ENCDEC3(Type, Id, Operand) |
|
|
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
} |
|
SPIRVId Operand; |
|
}; |
|
|
|
|
|
class SPIRVCopyMemory :public SPIRVInstruction, public SPIRVMemoryAccess { |
|
public: |
|
const static Op OC = OpCopyMemory; |
|
const static SPIRVWord FixedWords = 3; |
|
// Complete constructor |
|
SPIRVCopyMemory(SPIRVValue *TheTarget, SPIRVValue *TheSource, |
|
const std::vector<SPIRVWord> &TheMemoryAccess, |
|
SPIRVBasicBlock *TheBB) : |
|
SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB), |
|
SPIRVMemoryAccess(TheMemoryAccess), |
|
MemoryAccess(TheMemoryAccess), |
|
Target(TheTarget->getId()), |
|
Source(TheSource->getId()) { |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
|
|
// Incomplete constructor |
|
SPIRVCopyMemory() :SPIRVInstruction(OC), SPIRVMemoryAccess(), |
|
Target(SPIRVID_INVALID), |
|
Source(SPIRVID_INVALID) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
|
|
SPIRVValue *getSource() { return getValue(Source); } |
|
SPIRVValue *getTarget() { return getValue(Target); } |
|
|
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
MemoryAccess.resize(TheWordCount - FixedWords); |
|
} |
|
|
|
void encode(spv_ostream &O) const { |
|
getEncoder(O) << Target << Source << MemoryAccess; |
|
} |
|
|
|
void decode(std::istream &I) { |
|
getDecoder(I) >> Target >> Source >> MemoryAccess; |
|
MemoryAccessUpdate(MemoryAccess); |
|
} |
|
|
|
void validate()const { |
|
assert((getValueType(Id) == getValueType(Source)) && "Inconsistent type"); |
|
assert(getValueType(Id)->isTypePointer() && "Invalid type"); |
|
assert(!(getValueType(Id)->getPointerElementType()->isTypeVoid()) && |
|
"Invalid type"); |
|
SPIRVInstruction::validate(); |
|
} |
|
|
|
std::vector<SPIRVWord> MemoryAccess; |
|
SPIRVId Target; |
|
SPIRVId Source; |
|
}; |
|
|
|
class SPIRVCopyMemorySized :public SPIRVInstruction, public SPIRVMemoryAccess { |
|
public: |
|
const static Op OC = OpCopyMemorySized; |
|
const static SPIRVWord FixedWords = 4; |
|
// Complete constructor |
|
SPIRVCopyMemorySized(SPIRVValue *TheTarget, SPIRVValue *TheSource, |
|
SPIRVValue *TheSize, const std::vector<SPIRVWord> &TheMemoryAccess, |
|
SPIRVBasicBlock *TheBB) : |
|
SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB), |
|
SPIRVMemoryAccess(TheMemoryAccess), |
|
MemoryAccess(TheMemoryAccess), |
|
Target(TheTarget->getId()), |
|
Source(TheSource->getId()), |
|
Size(TheSize->getId()) { |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVCopyMemorySized() :SPIRVInstruction(OC), SPIRVMemoryAccess(), |
|
Target(SPIRVID_INVALID), Source(SPIRVID_INVALID), Size(0) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
|
|
SPIRVValue *getSource() { return getValue(Source); } |
|
SPIRVValue *getTarget() { return getValue(Target); } |
|
SPIRVValue *getSize() { return getValue(Size); } |
|
|
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
MemoryAccess.resize(TheWordCount - FixedWords); |
|
} |
|
|
|
void encode(spv_ostream &O) const { |
|
getEncoder(O) << Target << Source << Size << MemoryAccess; |
|
} |
|
|
|
void decode(std::istream &I) { |
|
getDecoder(I) >> Target >> Source >> Size >> MemoryAccess; |
|
MemoryAccessUpdate(MemoryAccess); |
|
} |
|
|
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
} |
|
|
|
std::vector<SPIRVWord> MemoryAccess; |
|
SPIRVId Target; |
|
SPIRVId Source; |
|
SPIRVId Size; |
|
}; |
|
|
|
class SPIRVVectorExtractDynamic:public SPIRVInstruction { |
|
public: |
|
const static Op OC = OpVectorExtractDynamic; |
|
// Complete constructor |
|
SPIRVVectorExtractDynamic(SPIRVId TheId, SPIRVValue *TheVector, |
|
SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(5, OC, TheVector->getType()->getVectorComponentType(), |
|
TheId, TheBB), VectorId(TheVector->getId()), |
|
IndexId(TheIndex->getId()){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVVectorExtractDynamic():SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), |
|
IndexId(SPIRVID_INVALID){} |
|
|
|
SPIRVValue *getVector() { return getValue(VectorId);} |
|
SPIRVValue *getIndex()const { return getValue(IndexId);} |
|
protected: |
|
_SPIRV_DEF_ENCDEC4(Type, Id, VectorId, IndexId) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
if (getValue(VectorId)->isForward()) |
|
return; |
|
assert(getValueType(VectorId)->isTypeVector()); |
|
} |
|
SPIRVId VectorId; |
|
SPIRVId IndexId; |
|
}; |
|
|
|
class SPIRVVectorInsertDynamic :public SPIRVInstruction { |
|
public: |
|
const static Op OC = OpVectorInsertDynamic; |
|
// Complete constructor |
|
SPIRVVectorInsertDynamic(SPIRVId TheId, SPIRVValue *TheVector, |
|
SPIRVValue* TheComponent, SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(6, OC, TheVector->getType()->getVectorComponentType(), |
|
TheId, TheBB), VectorId(TheVector->getId()), |
|
IndexId(TheIndex->getId()), ComponentId(TheComponent->getId()){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVVectorInsertDynamic() :SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), |
|
IndexId(SPIRVID_INVALID), ComponentId(SPIRVID_INVALID){} |
|
|
|
SPIRVValue *getVector() { return getValue(VectorId); } |
|
SPIRVValue *getIndex()const { return getValue(IndexId); } |
|
SPIRVValue *getComponent() { return getValue(ComponentId); } |
|
protected: |
|
_SPIRV_DEF_ENCDEC5(Type, Id, VectorId, ComponentId, IndexId) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
if (getValue(VectorId)->isForward()) |
|
return; |
|
assert(getValueType(VectorId)->isTypeVector()); |
|
} |
|
SPIRVId VectorId; |
|
SPIRVId IndexId; |
|
SPIRVId ComponentId; |
|
}; |
|
|
|
class SPIRVVectorShuffle:public SPIRVInstruction { |
|
public: |
|
const static Op OC = OpVectorShuffle; |
|
const static SPIRVWord FixedWordCount = 5; |
|
// Complete constructor |
|
SPIRVVectorShuffle(SPIRVId TheId, SPIRVType *TheType, SPIRVValue *TheVector1, |
|
SPIRVValue *TheVector2, const std::vector<SPIRVWord>& TheComponents, |
|
SPIRVBasicBlock *TheBB): |
|
SPIRVInstruction(TheComponents.size() + FixedWordCount, OC, TheType, |
|
TheId, TheBB), |
|
Vector1(TheVector1->getId()), Vector2(TheVector2->getId()), |
|
Components(TheComponents){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVVectorShuffle():SPIRVInstruction(OC), Vector1(SPIRVID_INVALID), |
|
Vector2(SPIRVID_INVALID){} |
|
|
|
SPIRVValue *getVector1() { return getValue(Vector1);} |
|
SPIRVValue *getVector2() { return getValue(Vector2);} |
|
const std::vector<SPIRVWord>& getComponents()const { return Components;} |
|
protected: |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
Components.resize(TheWordCount - FixedWordCount); |
|
} |
|
_SPIRV_DEF_ENCDEC5(Type, Id, Vector1, Vector2, Components) |
|
void validate()const { |
|
SPIRVInstruction::validate(); |
|
assert(OpCode == OC); |
|
assert(WordCount == Components.size() + FixedWordCount); |
|
assert(Type->isTypeVector()); |
|
assert(Type->getVectorComponentType() == |
|
getValueType(Vector1)->getVectorComponentType()); |
|
if (getValue(Vector1)->isForward() || |
|
getValue(Vector2)->isForward()) |
|
return; |
|
assert(getValueType(Vector1) == getValueType(Vector2)); |
|
size_t CompCount = Type->getVectorComponentCount(); |
|
(void) CompCount; |
|
assert(Components.size() == CompCount); |
|
assert(Components.size() > 1); |
|
} |
|
SPIRVId Vector1; |
|
SPIRVId Vector2; |
|
std::vector<SPIRVWord> Components; |
|
}; |
|
|
|
class SPIRVControlBarrier:public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpControlBarrier; |
|
// Complete constructor |
|
SPIRVControlBarrier(SPIRVValue *TheScope, |
|
SPIRVValue *TheMemScope, SPIRVValue *TheMemSema, |
|
SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(4, OC, TheBB), ExecScope(TheScope->getId()), |
|
MemScope(TheMemScope->getId()), MemSema(TheMemSema->getId()){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVControlBarrier():SPIRVInstruction(OC), ExecScope(ScopeInvocation) { |
|
setHasNoId(); |
|
setHasNoType(); |
|
} |
|
void setWordCount(SPIRVWord TheWordCount) { |
|
SPIRVEntry::setWordCount(TheWordCount); |
|
} |
|
SPIRVValue *getExecScope() const { return getValue(ExecScope); } |
|
SPIRVValue *getMemScope() const { return getValue(MemScope); } |
|
SPIRVValue *getMemSemantic() const { return getValue(MemSema); } |
|
std::vector<SPIRVValue *> getOperands() { |
|
std::vector<SPIRVId> Operands; |
|
Operands.push_back(ExecScope); |
|
Operands.push_back(MemScope); |
|
Operands.push_back(MemSema); |
|
return getValues(Operands); |
|
} |
|
protected: |
|
_SPIRV_DEF_ENCDEC3(ExecScope, MemScope, MemSema) |
|
void validate()const { |
|
assert(OpCode == OC); |
|
assert(WordCount == 4); |
|
SPIRVInstruction::validate(); |
|
} |
|
SPIRVId ExecScope; |
|
SPIRVId MemScope; |
|
SPIRVId MemSema; |
|
}; |
|
|
|
class SPIRVGroupAsyncCopy:public SPIRVInstruction { |
|
public: |
|
static const Op OC = OpGroupAsyncCopy; |
|
static const SPIRVWord WC = 9; |
|
// Complete constructor |
|
SPIRVGroupAsyncCopy(SPIRVValue *TheScope, SPIRVId TheId, |
|
SPIRVValue *TheDest, SPIRVValue *TheSrc, SPIRVValue *TheNumElems, |
|
SPIRVValue *TheStride, SPIRVValue *TheEvent, SPIRVBasicBlock *TheBB) |
|
:SPIRVInstruction(WC, OC, TheEvent->getType(), TheId, TheBB), |
|
ExecScope(TheScope->getId()), Destination(TheDest->getId()), |
|
Source(TheSrc->getId()), NumElements(TheNumElems->getId()), |
|
Stride(TheStride->getId()), Event(TheEvent->getId()){ |
|
validate(); |
|
assert(TheBB && "Invalid BB"); |
|
} |
|
// Incomplete constructor |
|
SPIRVGroupAsyncCopy():SPIRVInstruction(OC), ExecScope(SPIRVID_INVALID), |
|
Destination(SPIRVID_INVALID), Source(SPIRVID_INVALID), |
|
NumElements(SPIRVID_INVALID), Stride(SPIRVID_INVALID), |
|
Event(SPIRVID_INVALID){ |
|
} |
|
SPIRVValue *getExecScope() const { return getValue(ExecScope); } |
|
SPIRVValue *getDestination()const { return getValue(Destination);} |
|
SPIRVValue *getSource()const { return getValue(Source);} |
|
SPIRVValue *getNumElements()const { return getValue(NumElements);} |
|
SPIRVValue *getStride()const { return getValue(Stride);} |
|
SPIRVValue *getEvent()const { return getValue(Event);} |
|
std::vector<SPIRVValue *> getOperands() { |
|
std::vector<SPIRVId> Operands; |
|
Operands.push_back(Destination); |
|
Operands.push_back(Source); |
|
Operands.push_back(NumElements); |
|
Operands.push_back(Stride); |
|
Operands.push_back(Event); |
|
return getValues(Operands); |
|
} |
|
|
|
protected: |
|
_SPIRV_DEF_ENCDEC8(Type, Id, ExecScope, Destination, Source, NumElements, |
|
Stride, Event) |
|
void validate()const { |
|
assert(OpCode == OC); |
|
assert(WordCount == WC); |
|
SPIRVInstruction::validate(); |
|
} |
|
SPIRVId ExecScope; |
|
SPIRVId Destination; |
|
SPIRVId Source; |
|
SPIRVId NumElements; |
|
SPIRVId Stride; |
|
SPIRVId Event; |
|
}; |
|
|
|
enum SPIRVOpKind { |
|
SPIRVOPK_Id, |
|
SPIRVOPK_Literal, |
|
SPIRVOPK_Count |
|
}; |
|
|
|
class SPIRVDevEnqInstBase:public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVCapVec getRequiriedCapability() const { |
|
return getVec(CapabilityDeviceEnqueue); |
|
} |
|
}; |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVDevEnqInstBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
// CL 2.0 enqueue kernel builtins |
|
_SPIRV_OP(EnqueueMarker, true, 7) |
|
_SPIRV_OP(EnqueueKernel, true, 13, true) |
|
_SPIRV_OP(GetKernelNDrangeSubGroupCount, true, 8) |
|
_SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, true, 8) |
|
_SPIRV_OP(GetKernelWorkGroupSize, true, 7) |
|
_SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, true, 7) |
|
_SPIRV_OP(RetainEvent, false, 2) |
|
_SPIRV_OP(ReleaseEvent, false, 2) |
|
_SPIRV_OP(CreateUserEvent, true, 3) |
|
_SPIRV_OP(IsValidEvent, true, 4) |
|
_SPIRV_OP(SetUserEventStatus, false, 3) |
|
_SPIRV_OP(CaptureEventProfilingInfo, false, 4) |
|
_SPIRV_OP(GetDefaultQueue, true, 3) |
|
_SPIRV_OP(BuildNDRange, true, 6) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVPipeInstBase:public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVCapVec getRequiriedCapability() const { |
|
return getVec(CapabilityPipes); |
|
} |
|
}; |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVPipeInstBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
// CL 2.0 pipe builtins |
|
_SPIRV_OP(ReadPipe, true, 7) |
|
_SPIRV_OP(WritePipe, true, 7) |
|
_SPIRV_OP(ReservedReadPipe, true, 9) |
|
_SPIRV_OP(ReservedWritePipe, true, 9) |
|
_SPIRV_OP(ReserveReadPipePackets, true, 7) |
|
_SPIRV_OP(ReserveWritePipePackets, true, 7) |
|
_SPIRV_OP(CommitReadPipe, false, 5) |
|
_SPIRV_OP(CommitWritePipe, false, 5) |
|
_SPIRV_OP(IsValidReserveId, true, 4) |
|
_SPIRV_OP(GetNumPipePackets, true, 6) |
|
_SPIRV_OP(GetMaxPipePackets, true, 6) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVPipeStorageInstBase :public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVCapVec getRequiriedCapability() const { |
|
return getVec(CapabilityPipeStorage, CapabilityPipes); |
|
} |
|
}; |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVPipeStorageInstBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
|
|
_SPIRV_OP(CreatePipeFromPipeStorage, true, 4) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVGroupInstBase:public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVCapVec getRequiriedCapability() const { |
|
return getVec(CapabilityGroups); |
|
} |
|
}; |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVGroupInstBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
// Group instructions |
|
_SPIRV_OP(GroupWaitEvents, false, 4) |
|
_SPIRV_OP(GroupAll, true, 5) |
|
_SPIRV_OP(GroupAny, true, 5) |
|
_SPIRV_OP(GroupBroadcast, true, 6) |
|
_SPIRV_OP(GroupIAdd, true, 6, false, 1) |
|
_SPIRV_OP(GroupFAdd, true, 6, false, 1) |
|
_SPIRV_OP(GroupFMin, true, 6, false, 1) |
|
_SPIRV_OP(GroupUMin, true, 6, false, 1) |
|
_SPIRV_OP(GroupSMin, true, 6, false, 1) |
|
_SPIRV_OP(GroupFMax, true, 6, false, 1) |
|
_SPIRV_OP(GroupUMax, true, 6, false, 1) |
|
_SPIRV_OP(GroupSMax, true, 6, false, 1) |
|
_SPIRV_OP(GroupReserveReadPipePackets, true, 8) |
|
_SPIRV_OP(GroupReserveWritePipePackets, true, 8) |
|
_SPIRV_OP(GroupCommitReadPipe, false, 6) |
|
_SPIRV_OP(GroupCommitWritePipe, false, 6) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVAtomicInstBase:public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVCapVec getRequiriedCapability() const { |
|
return getVec(CapabilityInt64Atomics); |
|
} |
|
}; |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVAtomicInstBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
// Atomic builtins |
|
_SPIRV_OP(AtomicFlagTestAndSet, true, 6) |
|
_SPIRV_OP(AtomicFlagClear, false, 4) |
|
_SPIRV_OP(AtomicLoad, true, 6) |
|
_SPIRV_OP(AtomicStore, false, 5) |
|
_SPIRV_OP(AtomicExchange, true, 7) |
|
_SPIRV_OP(AtomicCompareExchange, true, 9) |
|
_SPIRV_OP(AtomicCompareExchangeWeak, true, 9) |
|
_SPIRV_OP(AtomicIIncrement, true, 6) |
|
_SPIRV_OP(AtomicIDecrement, true, 6) |
|
_SPIRV_OP(AtomicIAdd, true, 7) |
|
_SPIRV_OP(AtomicISub, true, 7) |
|
_SPIRV_OP(AtomicUMin, true, 7) |
|
_SPIRV_OP(AtomicUMax, true, 7) |
|
_SPIRV_OP(AtomicSMin, true, 7) |
|
_SPIRV_OP(AtomicSMax, true, 7) |
|
_SPIRV_OP(AtomicAnd, true, 7) |
|
_SPIRV_OP(AtomicOr, true, 7) |
|
_SPIRV_OP(AtomicXor, true, 7) |
|
_SPIRV_OP(MemoryBarrier, false, 3) |
|
#undef _SPIRV_OP |
|
|
|
class SPIRVImageInstBase:public SPIRVInstTemplateBase { |
|
public: |
|
SPIRVCapVec getRequiriedCapability() const { |
|
return getVec(CapabilityImageBasic); |
|
} |
|
}; |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVImageInstBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
// Image instructions |
|
_SPIRV_OP(SampledImage, true, 5) |
|
_SPIRV_OP(ImageSampleImplicitLod, true, 5, true) |
|
_SPIRV_OP(ImageSampleExplicitLod, true, 7, true, 2) |
|
_SPIRV_OP(ImageRead, true, 5, true, 2) |
|
_SPIRV_OP(ImageWrite, false, 4, true, 3) |
|
_SPIRV_OP(ImageQueryFormat, true, 4) |
|
_SPIRV_OP(ImageQueryOrder, true, 4) |
|
_SPIRV_OP(ImageQuerySizeLod, true, 5) |
|
_SPIRV_OP(ImageQuerySize, true, 4) |
|
_SPIRV_OP(ImageQueryLod, true, 5) |
|
_SPIRV_OP(ImageQueryLevels, true, 4) |
|
_SPIRV_OP(ImageQuerySamples, true, 4) |
|
#undef _SPIRV_OP |
|
|
|
#define _SPIRV_OP(x, ...) \ |
|
typedef SPIRVInstTemplate<SPIRVInstTemplateBase, Op##x, __VA_ARGS__> \ |
|
SPIRV##x; |
|
// Other instructions |
|
_SPIRV_OP(SpecConstantOp, true, 4, true, 0) |
|
_SPIRV_OP(GenericPtrMemSemantics, true, 4, false) |
|
_SPIRV_OP(GenericCastToPtrExplicit, true, 5, false, 1) |
|
#undef _SPIRV_OP |
|
|
|
SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst); |
|
SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *C); |
|
} |
|
|
|
#endif // SPIRVINSTRUCTION_HPP_
|
|
|