//===- SPIRVValue.h - Class to represent a SPIR-V Value ----------*- 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 the values defined in SPIR-V spec with op codes. /// /// The name of the SPIR-V values follow the op code name in the spec. /// This is for readability and ease of using macro to handle types. // //===----------------------------------------------------------------------===// #ifndef SPIRVVALUE_HPP_ #define SPIRVVALUE_HPP_ #include "SPIRVEntry.h" #include "SPIRVType.h" #include "SPIRVDecorate.h" #include <iostream> #include <map> #include <memory> namespace SPIRV{ class SPIRVValue: public SPIRVEntry { public: // Complete constructor for value with id and type SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVType *TheType, SPIRVId TheId) :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) { validate(); } // Complete constructor for value with type but without id SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVType *TheType) :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) { setHasNoId(); validate(); } // Complete constructor for value with id but without type SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId) :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) { setHasNoType(); validate(); } // Complete constructor for value without id and type SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode) :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) { setHasNoId(); setHasNoType(); validate(); } // Incomplete constructor SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {} bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);} SPIRVType *getType()const { assert(hasType() && "value has no type"); return Type; } bool isVolatile()const; bool hasAlignment(SPIRVWord *Result=0)const; void setAlignment(SPIRVWord); void setVolatile(bool IsVolatile); void validate()const { SPIRVEntry::validate(); assert((!hasType() || Type) && "Invalid type"); } void setType(SPIRVType *Ty) { Type = Ty; assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction); if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction)) setHasType(); else setHasNoType(); } SPIRVCapVec getRequiredCapability() const { SPIRVCapVec CV; if (!hasType()) return CV; return Type->getRequiredCapability(); } protected: void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;} void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;} SPIRVType *Type; // Value Type }; class SPIRVConstant: public SPIRVValue { public: // Complete constructor for integer constant SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, uint64_t TheValue) :SPIRVValue(M, 0, OpConstant, TheType, TheId){ Union.UInt64Val = TheValue; recalculateWordCount(); validate(); } // Complete constructor for float constant SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue) :SPIRVValue(M, 0, OpConstant, TheType, TheId){ Union.FloatVal = TheValue; recalculateWordCount(); validate(); } // Complete constructor for double constant SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue) :SPIRVValue(M, 0, OpConstant, TheType, TheId){ Union.DoubleVal = TheValue; recalculateWordCount(); validate(); } // Incomplete constructor SPIRVConstant():SPIRVValue(OpConstant), NumWords(0){} uint64_t getZExtIntValue() const { return Union.UInt64Val;} float getFloatValue() const { return Union.FloatVal;} double getDoubleValue() const { return Union.DoubleVal;} protected: void recalculateWordCount() { NumWords = Type->getBitWidth()/32; if (NumWords < 1) NumWords = 1; WordCount = 3 + NumWords; } void validate() const { SPIRVValue::validate(); assert(NumWords >= 1 && NumWords <= 2 && "Invalid constant size"); } void encode(spv_ostream &O) const { getEncoder(O) << Type << Id; for (unsigned i = 0; i < NumWords; ++i) getEncoder(O) << Union.Words[i]; } void setWordCount(SPIRVWord WordCount) { SPIRVValue::setWordCount(WordCount); NumWords = WordCount - 3; } void decode(std::istream &I) { getDecoder(I) >> Type >> Id; for (unsigned i = 0; i < NumWords; ++i) getDecoder(I) >> Union.Words[i]; } unsigned NumWords; union UnionType{ uint64_t UInt64Val; float FloatVal; double DoubleVal; SPIRVWord Words[2]; UnionType() { UInt64Val = 0; } } Union; }; template<Op OC> class SPIRVConstantEmpty: public SPIRVValue { public: // Complete constructor SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) :SPIRVValue(M, 3, OC, TheType, TheId){ validate(); } // Incomplete constructor SPIRVConstantEmpty():SPIRVValue(OC){} protected: void validate() const { SPIRVValue::validate(); } _SPIRV_DEF_ENCDEC2(Type, Id) }; template<Op OC> class SPIRVConstantBool: public SPIRVConstantEmpty<OC> { public: // Complete constructor SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) :SPIRVConstantEmpty<OC>(M, TheType, TheId){} // Incomplete constructor SPIRVConstantBool(){} protected: void validate() const { SPIRVConstantEmpty<OC>::validate(); assert(this->Type->isTypeBool() && "Invalid type"); } }; typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue; typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse; class SPIRVConstantNull: public SPIRVConstantEmpty<OpConstantNull> { public: // Complete constructor SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) :SPIRVConstantEmpty(M, TheType, TheId){ validate(); } // Incomplete constructor SPIRVConstantNull(){} protected: void validate() const { SPIRVConstantEmpty::validate(); assert((Type->isTypeComposite() || Type->isTypeOpaque() || Type->isTypeEvent() || Type->isTypePointer() || Type->isTypeReserveId() || Type->isTypeDeviceEvent()) && "Invalid type"); } }; class SPIRVUndef: public SPIRVConstantEmpty<OpUndef> { public: // Complete constructor SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) :SPIRVConstantEmpty(M, TheType, TheId){ validate(); } // Incomplete constructor SPIRVUndef(){} protected: void validate() const { SPIRVConstantEmpty::validate(); } }; class SPIRVConstantComposite: public SPIRVValue { public: // Complete constructor for composite constant SPIRVConstantComposite(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, const std::vector<SPIRVValue *> TheElements) :SPIRVValue(M, TheElements.size()+3, OpConstantComposite, TheType, TheId){ Elements = getIds(TheElements); validate(); } // Incomplete constructor SPIRVConstantComposite():SPIRVValue(OpConstantComposite){} std::vector<SPIRVValue*> getElements()const { return getValues(Elements); } std::vector<SPIRVEntry*> getNonLiteralOperands() const { std::vector<SPIRVValue*> Elements = getElements(); return std::vector<SPIRVEntry*>(Elements.begin(), Elements.end()); } protected: void validate() const { SPIRVValue::validate(); for (auto &I:Elements) getValue(I)->validate(); } void setWordCount(SPIRVWord WordCount) { Elements.resize(WordCount - 3); } _SPIRV_DEF_ENCDEC3(Type, Id, Elements) std::vector<SPIRVId> Elements; }; class SPIRVConstantSampler: public SPIRVValue { public: const static Op OC = OpConstantSampler; const static SPIRVWord WC = 6; // Complete constructor SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode) :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode), Normalized(TheNormalized), FilterMode(TheFilterMode){ validate(); } // Incomplete constructor SPIRVConstantSampler():SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid), Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSFM_Invalid){} SPIRVWord getAddrMode() const { return AddrMode; } SPIRVWord getFilterMode() const { return FilterMode; } SPIRVWord getNormalized() const { return Normalized; } SPIRVCapVec getRequiredCapability() const { return getVec(CapabilityLiteralSampler); } protected: SPIRVWord AddrMode; SPIRVWord Normalized; SPIRVWord FilterMode; void validate() const { SPIRVValue::validate(); assert(OpCode == OC); assert(WordCount == WC); assert(Type->isTypeSampler()); } _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode) }; class SPIRVConstantPipeStorage : public SPIRVValue { public: const static Op OC = OpConstantPipeStorage; const static SPIRVWord WC = 6; // Complete constructor SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign, SPIRVWord TheCapacity) :SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize), PacketAlign(ThePacketAlign), Capacity(TheCapacity){ validate(); } // Incomplete constructor SPIRVConstantPipeStorage() :SPIRVValue(OC), PacketSize(0), PacketAlign(0), Capacity(0){} SPIRVWord getPacketSize() const { return PacketSize; } SPIRVWord getPacketAlign() const { return PacketAlign; } SPIRVWord getCapacity() const { return Capacity; } SPIRVCapVec getRequiredCapability() const { return getVec(CapabilityPipes, CapabilityPipeStorage); } protected: SPIRVWord PacketSize; SPIRVWord PacketAlign; SPIRVWord Capacity; void validate() const { SPIRVValue::validate(); assert(OpCode == OC); assert(WordCount == WC); assert(Type->isTypePipeStorage()); } _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity) }; class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes { public: const static Op OC = OpForward; // Complete constructor SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId): SPIRVValue(TheModule, 0, OC, TheId){ if (TheTy) setType(TheTy); } SPIRVForward():SPIRVValue(OC) { assert(0 && "should never be called"); } _SPIRV_DEF_ENCDEC1(Id) friend class SPIRVFunction; protected: void validate() const {} }; } #endif /* SPIRVVALUE_HPP_ */