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 SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType,SPIRVId TheId)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 SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType)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 SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVId TheId)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 SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode)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 SPIRVValue(Op TheOpCode)86 SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {} 87 hasType()88 bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);} getType()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 validate()99 void validate()const { 100 SPIRVEntry::validate(); 101 assert((!hasType() || Type) && "Invalid type"); 102 } 103 setType(SPIRVType * Ty)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 getRequiredCapability()113 SPIRVCapVec getRequiredCapability() const { 114 SPIRVCapVec CV; 115 if (!hasType()) 116 return CV; 117 return Type->getRequiredCapability(); 118 } 119 120 protected: setHasNoType()121 void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;} setHasType()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 SPIRVConstant(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,uint64_t TheValue)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 SPIRVConstant(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,float TheValue)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 SPIRVConstant(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,double TheValue)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 SPIRVConstant()152 SPIRVConstant():SPIRVValue(OpConstant), NumWords(0){} getZExtIntValue()153 uint64_t getZExtIntValue() const { return Union.UInt64Val;} getFloatValue()154 float getFloatValue() const { return Union.FloatVal;} getDoubleValue()155 double getDoubleValue() const { return Union.DoubleVal;} 156 protected: recalculateWordCount()157 void recalculateWordCount() { 158 NumWords = Type->getBitWidth()/32; 159 if (NumWords < 1) 160 NumWords = 1; 161 WordCount = 3 + NumWords; 162 } validate()163 void validate() const { 164 SPIRVValue::validate(); 165 assert(NumWords >= 1 && NumWords <= 2 && "Invalid constant size"); 166 } encode(spv_ostream & O)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 } setWordCount(SPIRVWord WordCount)172 void setWordCount(SPIRVWord WordCount) { 173 SPIRVValue::setWordCount(WordCount); 174 NumWords = WordCount - 3; 175 } decode(std::istream & I)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]; UnionType()188 UnionType() { 189 UInt64Val = 0; 190 } 191 } Union; 192 }; 193 194 template<Op OC> 195 class SPIRVConstantEmpty: public SPIRVValue { 196 public: 197 // Complete constructor SPIRVConstantEmpty(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)198 SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 199 :SPIRVValue(M, 3, OC, TheType, TheId){ 200 validate(); 201 } 202 // Incomplete constructor SPIRVConstantEmpty()203 SPIRVConstantEmpty():SPIRVValue(OC){} 204 protected: validate()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 SPIRVConstantBool(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)215 SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 216 :SPIRVConstantEmpty<OC>(M, TheType, TheId){} 217 // Incomplete constructor SPIRVConstantBool()218 SPIRVConstantBool(){} 219 protected: validate()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 SPIRVConstantNull(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)233 SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 234 :SPIRVConstantEmpty(M, TheType, TheId){ 235 validate(); 236 } 237 // Incomplete constructor SPIRVConstantNull()238 SPIRVConstantNull(){} 239 protected: validate()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 SPIRVUndef(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)256 SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 257 :SPIRVConstantEmpty(M, TheType, TheId){ 258 validate(); 259 } 260 // Incomplete constructor SPIRVUndef()261 SPIRVUndef(){} 262 protected: validate()263 void validate() const { 264 SPIRVConstantEmpty::validate(); 265 } 266 }; 267 268 class SPIRVConstantComposite: public SPIRVValue { 269 public: 270 // Complete constructor for composite constant SPIRVConstantComposite(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,const std::vector<SPIRVValue * > TheElements)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 SPIRVConstantComposite()279 SPIRVConstantComposite():SPIRVValue(OpConstantComposite){} getElements()280 std::vector<SPIRVValue*> getElements()const { 281 return getValues(Elements); 282 } getNonLiteralOperands()283 std::vector<SPIRVEntry*> getNonLiteralOperands() const { 284 std::vector<SPIRVValue*> Elements = getElements(); 285 return std::vector<SPIRVEntry*>(Elements.begin(), Elements.end()); 286 } 287 protected: validate()288 void validate() const { 289 SPIRVValue::validate(); 290 for (auto &I:Elements) 291 getValue(I)->validate(); 292 } setWordCount(SPIRVWord WordCount)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 SPIRVConstantSampler(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord TheAddrMode,SPIRVWord TheNormalized,SPIRVWord TheFilterMode)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 SPIRVConstantSampler()313 SPIRVConstantSampler():SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid), 314 Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSFM_Invalid){} 315 getAddrMode()316 SPIRVWord getAddrMode() const { 317 return AddrMode; 318 } 319 getFilterMode()320 SPIRVWord getFilterMode() const { 321 return FilterMode; 322 } 323 getNormalized()324 SPIRVWord getNormalized() const { 325 return Normalized; 326 } getRequiredCapability()327 SPIRVCapVec getRequiredCapability() const { 328 return getVec(CapabilityLiteralSampler); 329 } 330 protected: 331 SPIRVWord AddrMode; 332 SPIRVWord Normalized; 333 SPIRVWord FilterMode; validate()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 SPIRVConstantPipeStorage(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord ThePacketSize,SPIRVWord ThePacketAlign,SPIRVWord TheCapacity)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 SPIRVConstantPipeStorage()355 SPIRVConstantPipeStorage() :SPIRVValue(OC), PacketSize(0), 356 PacketAlign(0), Capacity(0){} 357 getPacketSize()358 SPIRVWord getPacketSize() const { 359 return PacketSize; 360 } 361 getPacketAlign()362 SPIRVWord getPacketAlign() const { 363 return PacketAlign; 364 } 365 getCapacity()366 SPIRVWord getCapacity() const { 367 return Capacity; 368 } getRequiredCapability()369 SPIRVCapVec getRequiredCapability() const { 370 return getVec(CapabilityPipes, CapabilityPipeStorage); 371 } 372 protected: 373 SPIRVWord PacketSize; 374 SPIRVWord PacketAlign; 375 SPIRVWord Capacity; validate()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 SPIRVForward(SPIRVModule * TheModule,SPIRVType * TheTy,SPIRVId TheId)389 SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId): 390 SPIRVValue(TheModule, 0, OC, TheId){ 391 if (TheTy) 392 setType(TheTy); 393 } SPIRVForward()394 SPIRVForward():SPIRVValue(OC) { 395 assert(0 && "should never be called"); 396 } _SPIRV_DEF_ENCDEC1(Id)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