Home | History | Annotate | Download | only in libSPIRV
      1 //===- SPIRVValue.h - Class to represent a SPIR-V Value ----------*- C++ -*-===//
      2 //
      3 //                     The LLVM/SPIRV Translator
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
      9 //
     10 // Permission is hereby granted, free of charge, to any person obtaining a
     11 // copy of this software and associated documentation files (the "Software"),
     12 // to deal with the Software without restriction, including without limitation
     13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
     14 // and/or sell copies of the Software, and to permit persons to whom the
     15 // Software is furnished to do so, subject to the following conditions:
     16 //
     17 // Redistributions of source code must retain the above copyright notice,
     18 // this list of conditions and the following disclaimers.
     19 // Redistributions in binary form must reproduce the above copyright notice,
     20 // this list of conditions and the following disclaimers in the documentation
     21 // and/or other materials provided with the distribution.
     22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
     23 // contributors may be used to endorse or promote products derived from this
     24 // Software without specific prior written permission.
     25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
     31 // THE SOFTWARE.
     32 //
     33 //===----------------------------------------------------------------------===//
     34 /// \file
     35 ///
     36 /// This file defines the values defined in SPIR-V spec with op codes.
     37 ///
     38 /// The name of the SPIR-V values follow the op code name in the spec.
     39 /// This is for readability and ease of using macro to handle types.
     40 //
     41 //===----------------------------------------------------------------------===//
     42 
     43 #ifndef SPIRVVALUE_HPP_
     44 #define SPIRVVALUE_HPP_
     45 
     46 #include "SPIRVEntry.h"
     47 #include "SPIRVType.h"
     48 #include "SPIRVDecorate.h"
     49 
     50 #include <iostream>
     51 #include <map>
     52 #include <memory>
     53 
     54 namespace SPIRV{
     55 
     56 class SPIRVValue: public SPIRVEntry {
     57 public:
     58   // Complete constructor for value with id and type
     59   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
     60       SPIRVType *TheType, SPIRVId TheId)
     61     :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) {
     62     validate();
     63   }
     64   // Complete constructor for value with type but without id
     65   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
     66       SPIRVType *TheType)
     67     :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) {
     68     setHasNoId();
     69     validate();
     70   }
     71   // Complete constructor for value with id but without type
     72   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
     73       SPIRVId TheId)
     74     :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) {
     75     setHasNoType();
     76     validate();
     77   }
     78   // Complete constructor for value without id and type
     79   SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
     80     :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) {
     81     setHasNoId();
     82     setHasNoType();
     83     validate();
     84   }
     85   // Incomplete constructor
     86   SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {}
     87 
     88   bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);}
     89   SPIRVType *getType()const {
     90     assert(hasType() && "value has no type");
     91     return Type;
     92   }
     93   bool isVolatile()const;
     94   bool hasAlignment(SPIRVWord *Result=0)const;
     95 
     96   void setAlignment(SPIRVWord);
     97   void setVolatile(bool IsVolatile);
     98 
     99   void validate()const {
    100     SPIRVEntry::validate();
    101     assert((!hasType() || Type) && "Invalid type");
    102   }
    103 
    104   void setType(SPIRVType *Ty) {
    105     Type = Ty;
    106     assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction);
    107     if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction))
    108       setHasType();
    109     else
    110       setHasNoType();
    111   }
    112 
    113   SPIRVCapVec getRequiredCapability() const {
    114     SPIRVCapVec CV;
    115     if (!hasType())
    116       return CV;
    117     return Type->getRequiredCapability();
    118   }
    119 
    120 protected:
    121   void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;}
    122   void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;}
    123 
    124   SPIRVType *Type;                 // Value Type
    125 };
    126 
    127 class SPIRVConstant: public SPIRVValue {
    128 public:
    129   // Complete constructor for integer constant
    130   SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
    131       uint64_t TheValue)
    132     :SPIRVValue(M, 0, OpConstant, TheType, TheId){
    133     Union.UInt64Val = TheValue;
    134     recalculateWordCount();
    135     validate();
    136   }
    137   // Complete constructor for float constant
    138   SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue)
    139     :SPIRVValue(M, 0, OpConstant, TheType, TheId){
    140     Union.FloatVal = TheValue;
    141     recalculateWordCount();
    142     validate();
    143   }
    144   // Complete constructor for double constant
    145   SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue)
    146     :SPIRVValue(M, 0, OpConstant, TheType, TheId){
    147     Union.DoubleVal = TheValue;
    148     recalculateWordCount();
    149     validate();
    150   }
    151   // Incomplete constructor
    152   SPIRVConstant():SPIRVValue(OpConstant), NumWords(0){}
    153   uint64_t getZExtIntValue() const { return Union.UInt64Val;}
    154   float getFloatValue() const { return Union.FloatVal;}
    155   double getDoubleValue() const { return Union.DoubleVal;}
    156 protected:
    157   void recalculateWordCount() {
    158     NumWords = Type->getBitWidth()/32;
    159     if (NumWords < 1)
    160       NumWords = 1;
    161     WordCount = 3 + NumWords;
    162   }
    163   void validate() const {
    164     SPIRVValue::validate();
    165     assert(NumWords >= 1 && NumWords <= 2 && "Invalid constant size");
    166   }
    167   void encode(spv_ostream &O) const {
    168     getEncoder(O) << Type << Id;
    169     for (unsigned i = 0; i < NumWords; ++i)
    170       getEncoder(O) << Union.Words[i];
    171   }
    172   void setWordCount(SPIRVWord WordCount) {
    173     SPIRVValue::setWordCount(WordCount);
    174     NumWords = WordCount - 3;
    175   }
    176   void decode(std::istream &I) {
    177     getDecoder(I) >> Type >> Id;
    178     for (unsigned i = 0; i < NumWords; ++i)
    179       getDecoder(I) >> Union.Words[i];
    180   }
    181 
    182   unsigned NumWords;
    183   union UnionType{
    184     uint64_t UInt64Val;
    185     float FloatVal;
    186     double DoubleVal;
    187     SPIRVWord Words[2];
    188     UnionType() {
    189       UInt64Val = 0;
    190     }
    191   } Union;
    192 };
    193 
    194 template<Op OC>
    195 class SPIRVConstantEmpty: public SPIRVValue {
    196 public:
    197   // Complete constructor
    198   SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
    199     :SPIRVValue(M, 3, OC, TheType, TheId){
    200     validate();
    201   }
    202   // Incomplete constructor
    203   SPIRVConstantEmpty():SPIRVValue(OC){}
    204 protected:
    205   void validate() const {
    206     SPIRVValue::validate();
    207   }
    208   _SPIRV_DEF_ENCDEC2(Type, Id)
    209 };
    210 
    211 template<Op OC>
    212 class SPIRVConstantBool: public SPIRVConstantEmpty<OC> {
    213 public:
    214   // Complete constructor
    215   SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
    216     :SPIRVConstantEmpty<OC>(M, TheType, TheId){}
    217   // Incomplete constructor
    218   SPIRVConstantBool(){}
    219 protected:
    220   void validate() const {
    221     SPIRVConstantEmpty<OC>::validate();
    222     assert(this->Type->isTypeBool() && "Invalid type");
    223   }
    224 };
    225 
    226 typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue;
    227 typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse;
    228 
    229 class SPIRVConstantNull:
    230     public SPIRVConstantEmpty<OpConstantNull> {
    231 public:
    232   // Complete constructor
    233   SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
    234     :SPIRVConstantEmpty(M, TheType, TheId){
    235     validate();
    236   }
    237   // Incomplete constructor
    238   SPIRVConstantNull(){}
    239 protected:
    240   void validate() const {
    241     SPIRVConstantEmpty::validate();
    242     assert((Type->isTypeComposite() ||
    243             Type->isTypeOpaque() ||
    244             Type->isTypeEvent() ||
    245             Type->isTypePointer() ||
    246             Type->isTypeReserveId() ||
    247             Type->isTypeDeviceEvent()) &&
    248             "Invalid type");
    249   }
    250 };
    251 
    252 class SPIRVUndef:
    253     public SPIRVConstantEmpty<OpUndef> {
    254 public:
    255   // Complete constructor
    256   SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
    257     :SPIRVConstantEmpty(M, TheType, TheId){
    258     validate();
    259   }
    260   // Incomplete constructor
    261   SPIRVUndef(){}
    262 protected:
    263   void validate() const {
    264     SPIRVConstantEmpty::validate();
    265   }
    266 };
    267 
    268 class SPIRVConstantComposite: public SPIRVValue {
    269 public:
    270   // Complete constructor for composite constant
    271   SPIRVConstantComposite(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
    272       const std::vector<SPIRVValue *> TheElements)
    273     :SPIRVValue(M, TheElements.size()+3, OpConstantComposite, TheType,
    274         TheId){
    275     Elements = getIds(TheElements);
    276     validate();
    277   }
    278   // Incomplete constructor
    279   SPIRVConstantComposite():SPIRVValue(OpConstantComposite){}
    280   std::vector<SPIRVValue*> getElements()const {
    281     return getValues(Elements);
    282   }
    283   std::vector<SPIRVEntry*> getNonLiteralOperands() const {
    284     std::vector<SPIRVValue*> Elements = getElements();
    285     return std::vector<SPIRVEntry*>(Elements.begin(), Elements.end());
    286   }
    287 protected:
    288   void validate() const {
    289     SPIRVValue::validate();
    290     for (auto &I:Elements)
    291       getValue(I)->validate();
    292   }
    293   void setWordCount(SPIRVWord WordCount) {
    294     Elements.resize(WordCount - 3);
    295   }
    296   _SPIRV_DEF_ENCDEC3(Type, Id, Elements)
    297 
    298   std::vector<SPIRVId> Elements;
    299 };
    300 
    301 class SPIRVConstantSampler: public SPIRVValue {
    302 public:
    303   const static Op OC = OpConstantSampler;
    304   const static SPIRVWord WC = 6;
    305   // Complete constructor
    306   SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
    307       SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode)
    308     :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode),
    309      Normalized(TheNormalized), FilterMode(TheFilterMode){
    310     validate();
    311   }
    312   // Incomplete constructor
    313   SPIRVConstantSampler():SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid),
    314       Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSFM_Invalid){}
    315 
    316   SPIRVWord getAddrMode() const {
    317     return AddrMode;
    318   }
    319 
    320   SPIRVWord getFilterMode() const {
    321     return FilterMode;
    322   }
    323 
    324   SPIRVWord getNormalized() const {
    325     return Normalized;
    326   }
    327   SPIRVCapVec getRequiredCapability() const {
    328     return getVec(CapabilityLiteralSampler);
    329   }
    330 protected:
    331   SPIRVWord AddrMode;
    332   SPIRVWord Normalized;
    333   SPIRVWord FilterMode;
    334   void validate() const {
    335     SPIRVValue::validate();
    336     assert(OpCode == OC);
    337     assert(WordCount == WC);
    338     assert(Type->isTypeSampler());
    339   }
    340   _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode)
    341 };
    342 
    343 class SPIRVConstantPipeStorage : public SPIRVValue {
    344 public:
    345   const static Op OC = OpConstantPipeStorage;
    346   const static SPIRVWord WC = 6;
    347   // Complete constructor
    348   SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
    349     SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign, SPIRVWord TheCapacity)
    350     :SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize),
    351     PacketAlign(ThePacketAlign), Capacity(TheCapacity){
    352     validate();
    353   }
    354   // Incomplete constructor
    355   SPIRVConstantPipeStorage() :SPIRVValue(OC), PacketSize(0),
    356     PacketAlign(0), Capacity(0){}
    357 
    358   SPIRVWord getPacketSize() const {
    359     return PacketSize;
    360   }
    361 
    362   SPIRVWord getPacketAlign() const {
    363     return PacketAlign;
    364   }
    365 
    366   SPIRVWord getCapacity() const {
    367     return Capacity;
    368   }
    369   SPIRVCapVec getRequiredCapability() const {
    370     return getVec(CapabilityPipes, CapabilityPipeStorage);
    371   }
    372 protected:
    373   SPIRVWord PacketSize;
    374   SPIRVWord PacketAlign;
    375   SPIRVWord Capacity;
    376   void validate() const {
    377     SPIRVValue::validate();
    378     assert(OpCode == OC);
    379     assert(WordCount == WC);
    380     assert(Type->isTypePipeStorage());
    381   }
    382   _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity)
    383 };
    384 
    385 class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes {
    386 public:
    387   const static Op OC = OpForward;
    388   // Complete constructor
    389   SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId):
    390     SPIRVValue(TheModule, 0, OC, TheId){
    391     if (TheTy)
    392       setType(TheTy);
    393   }
    394   SPIRVForward():SPIRVValue(OC) {
    395     assert(0 && "should never be called");
    396   }
    397   _SPIRV_DEF_ENCDEC1(Id)
    398   friend class SPIRVFunction;
    399 protected:
    400   void validate() const {}
    401 };
    402 
    403 }
    404 
    405 
    406 #endif /* SPIRVVALUE_HPP_ */
    407