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 SPIRV_LIBSPIRV_SPIRVVALUE_H 44 #define SPIRV_LIBSPIRV_SPIRVVALUE_H 45 46 #include "SPIRVDecorate.h" 47 #include "SPIRVEntry.h" 48 #include "SPIRVType.h" 49 50 namespace llvm { 51 class APInt; 52 } // namespace llvm 53 54 #include <iostream> 55 56 namespace SPIRV { 57 58 class SPIRVValue : public SPIRVEntry { 59 public: 60 // Complete constructor for value with id and type SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType,SPIRVId TheId)61 SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, 62 SPIRVType *TheType, SPIRVId TheId) 63 : SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) { 64 validate(); 65 } 66 // Complete constructor for value with type but without id SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVType * TheType)67 SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, 68 SPIRVType *TheType) 69 : SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) { 70 setHasNoId(); 71 SPIRVValue::validate(); 72 } 73 // Complete constructor for value with id but without type SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode,SPIRVId TheId)74 SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId) 75 : SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) { 76 setHasNoType(); 77 SPIRVValue::validate(); 78 } 79 // Complete constructor for value without id and type SPIRVValue(SPIRVModule * M,unsigned TheWordCount,Op TheOpCode)80 SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode) 81 : SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) { 82 setHasNoId(); 83 setHasNoType(); 84 SPIRVValue::validate(); 85 } 86 // Incomplete constructor SPIRVValue(Op TheOpCode)87 SPIRVValue(Op TheOpCode) : SPIRVEntry(TheOpCode), Type(NULL) {} 88 hasType()89 bool hasType() const { return !(Attrib & SPIRVEA_NOTYPE); } getType()90 SPIRVType *getType() const { 91 assert(hasType() && "value has no type"); 92 return Type; 93 } 94 bool isVolatile() const; 95 bool hasAlignment(SPIRVWord *Result = 0) const; 96 bool hasNoSignedWrap() const; 97 bool hasNoUnsignedWrap() const; 98 99 void setAlignment(SPIRVWord); 100 void setVolatile(bool IsVolatile); 101 void setNoSignedWrap(bool HasNoSignedWrap); 102 void setNoUnsignedWrap(bool HasNoUnsignedWrap); 103 void setFPFastMathMode(SPIRVWord FPFastMathMode); 104 validate()105 void validate() const override { 106 SPIRVEntry::validate(); 107 assert((!hasType() || Type) && "Invalid type"); 108 } 109 setType(SPIRVType * Ty)110 void setType(SPIRVType *Ty) { 111 Type = Ty; 112 assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction); 113 if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction)) 114 setHasType(); 115 else 116 setHasNoType(); 117 } 118 getRequiredCapability()119 SPIRVCapVec getRequiredCapability() const override { 120 SPIRVCapVec CV; 121 if (!hasType()) 122 return CV; 123 return Type->getRequiredCapability(); 124 } 125 getRequiredExtension()126 llvm::Optional<ExtensionID> getRequiredExtension() const override { 127 llvm::Optional<ExtensionID> EV; 128 if (!hasType()) 129 return EV; 130 EV = Type->getRequiredExtension(); 131 assert(Module && 132 (!EV.hasValue() || Module->isAllowedToUseExtension(EV.getValue()))); 133 return EV; 134 } 135 136 protected: setHasNoType()137 void setHasNoType() { Attrib |= SPIRVEA_NOTYPE; } setHasType()138 void setHasType() { Attrib &= ~SPIRVEA_NOTYPE; } 139 140 SPIRVType *Type; // Value Type 141 }; 142 143 template <spv::Op OC> class SPIRVConstantBase : public SPIRVValue { 144 public: 145 // Complete constructor for integer constant SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,uint64_t TheValue)146 SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 147 uint64_t TheValue) 148 : SPIRVValue(M, 0, OC, TheType, TheId) { 149 setWords(&TheValue); 150 } 151 // Incomplete constructor for AP integer constant 152 SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 153 const llvm::APInt &TheValue); 154 // Complete constructor for float constant SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,float TheValue)155 SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 156 float TheValue) 157 : SPIRVValue(M, 0, OC, TheType, TheId) { 158 setWords(reinterpret_cast<uint64_t *>(&TheValue)); 159 } 160 // Complete constructor for double constant SPIRVConstantBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,double TheValue)161 SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 162 double TheValue) 163 : SPIRVValue(M, 0, OC, TheType, TheId) { 164 setWords(reinterpret_cast<uint64_t *>(&TheValue)); 165 } 166 // Incomplete constructor SPIRVConstantBase()167 SPIRVConstantBase() : SPIRVValue(OC), NumWords(0) {} getZExtIntValue()168 uint64_t getZExtIntValue() const { return getValue<uint64_t>(); } getFloatValue()169 float getFloatValue() const { return getValue<float>(); } getDoubleValue()170 double getDoubleValue() const { return getValue<double>(); } getNumWords()171 unsigned getNumWords() const { return NumWords; } getSPIRVWords()172 const std::vector<SPIRVWord> &getSPIRVWords() { return Words; } 173 174 protected: 175 constexpr static SPIRVWord FixedWC = 3; 176 177 // Common method for getting values of size less or equal to 64 bits. getValue()178 template <typename T> T getValue() const { 179 constexpr auto ValueSize = static_cast<unsigned>(sizeof(T)); 180 assert((ValueSize <= 8) && "Incorrect result type of requested value"); 181 T TheValue{}; 182 unsigned CopyBytes = std::min(ValueSize, NumWords * SpirvWordSize); 183 std::memcpy(&TheValue, Words.data(), CopyBytes); 184 return TheValue; 185 } 186 187 void setWords(const uint64_t *TheValue); recalculateWordCount()188 void recalculateWordCount() { 189 NumWords = 190 (Type->getBitWidth() + SpirvWordBitWidth - 1) / SpirvWordBitWidth; 191 WordCount = FixedWC + NumWords; 192 } validate()193 void validate() const override { 194 SPIRVValue::validate(); 195 assert(NumWords >= 1 && "Invalid constant size"); 196 } encode(spv_ostream & O)197 void encode(spv_ostream &O) const override { 198 getEncoder(O) << Type << Id; 199 for (const auto &Word : Words) 200 getEncoder(O) << Word; 201 } setWordCount(SPIRVWord WordCount)202 void setWordCount(SPIRVWord WordCount) override { 203 SPIRVValue::setWordCount(WordCount); 204 NumWords = WordCount - FixedWC; 205 } decode(std::istream & I)206 void decode(std::istream &I) override { 207 getDecoder(I) >> Type >> Id; 208 Words.resize(NumWords); 209 for (auto &Word : Words) 210 getDecoder(I) >> Word; 211 } 212 213 unsigned NumWords; 214 215 private: 216 std::vector<SPIRVWord> Words; 217 }; 218 219 using SPIRVConstant = SPIRVConstantBase<OpConstant>; 220 using SPIRVSpecConstant = SPIRVConstantBase<OpSpecConstant>; 221 222 template <Op OC> class SPIRVConstantEmpty : public SPIRVValue { 223 public: 224 // Complete constructor SPIRVConstantEmpty(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)225 SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 226 : SPIRVValue(M, 3, OC, TheType, TheId) { 227 validate(); 228 } 229 // Incomplete constructor SPIRVConstantEmpty()230 SPIRVConstantEmpty() : SPIRVValue(OC) {} 231 232 protected: validate()233 void validate() const override { SPIRVValue::validate(); } 234 _SPIRV_DEF_ENCDEC2(Type, Id) 235 }; 236 237 template <Op OC> class SPIRVConstantBool : public SPIRVConstantEmpty<OC> { 238 public: 239 // Complete constructor SPIRVConstantBool(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)240 SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 241 : SPIRVConstantEmpty<OC>(M, TheType, TheId) {} 242 // Incomplete constructor SPIRVConstantBool()243 SPIRVConstantBool() {} 244 245 protected: validate()246 void validate() const override { 247 SPIRVConstantEmpty<OC>::validate(); 248 assert(this->Type->isTypeBool() && "Invalid type"); 249 } 250 }; 251 252 typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue; 253 typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse; 254 typedef SPIRVConstantBool<OpSpecConstantTrue> SPIRVSpecConstantTrue; 255 typedef SPIRVConstantBool<OpSpecConstantFalse> SPIRVSpecConstantFalse; 256 257 class SPIRVConstantNull : public SPIRVConstantEmpty<OpConstantNull> { 258 public: 259 // Complete constructor SPIRVConstantNull(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)260 SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 261 : SPIRVConstantEmpty(M, TheType, TheId) { 262 validate(); 263 } 264 // Incomplete constructor SPIRVConstantNull()265 SPIRVConstantNull() {} 266 267 protected: validate()268 void validate() const override { 269 SPIRVConstantEmpty::validate(); 270 assert((Type->isTypeComposite() || Type->isTypeOpaque() || 271 Type->isTypeEvent() || Type->isTypePointer() || 272 Type->isTypeReserveId() || Type->isTypeDeviceEvent() || 273 (Type->isTypeSubgroupAvcINTEL() && 274 !Type->isTypeSubgroupAvcMceINTEL())) && 275 "Invalid type"); 276 } 277 }; 278 279 class SPIRVUndef : public SPIRVConstantEmpty<OpUndef> { 280 public: 281 // Complete constructor SPIRVUndef(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId)282 SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) 283 : SPIRVConstantEmpty(M, TheType, TheId) { 284 validate(); 285 } 286 // Incomplete constructor SPIRVUndef()287 SPIRVUndef() {} 288 289 protected: validate()290 void validate() const override { SPIRVConstantEmpty::validate(); } 291 }; 292 293 template <spv::Op OC> class SPIRVConstantCompositeBase : public SPIRVValue { 294 public: 295 // There are always 3 words in this instruction except constituents: 296 // 1) WordCount + OpCode 297 // 2) Result type 298 // 3) Result Id 299 constexpr static SPIRVWord FixedWC = 3; 300 using ContinuedInstType = typename InstToContinued<OC>::Type; 301 // Complete constructor for composite constant SPIRVConstantCompositeBase(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,const std::vector<SPIRVValue * > TheElements)302 SPIRVConstantCompositeBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 303 const std::vector<SPIRVValue *> TheElements) 304 : SPIRVValue(M, TheElements.size() + FixedWC, OC, TheType, TheId) { 305 Elements = getIds(TheElements); 306 validate(); 307 } 308 // Incomplete constructor SPIRVConstantCompositeBase()309 SPIRVConstantCompositeBase() : SPIRVValue(OC) {} getElements()310 std::vector<SPIRVValue *> getElements() const { return getValues(Elements); } 311 312 // TODO: Should we attach operands of continued instructions as well? getNonLiteralOperands()313 std::vector<SPIRVEntry *> getNonLiteralOperands() const override { 314 std::vector<SPIRVValue *> Elements = getElements(); 315 return std::vector<SPIRVEntry *>(Elements.begin(), Elements.end()); 316 } 317 getContinuedInstructions()318 std::vector<ContinuedInstType> getContinuedInstructions() { 319 return ContinuedInstructions; 320 } 321 addContinuedInstruction(ContinuedInstType Inst)322 void addContinuedInstruction(ContinuedInstType Inst) { 323 ContinuedInstructions.push_back(Inst); 324 } 325 encodeChildren(spv_ostream & O)326 void encodeChildren(spv_ostream &O) const override { 327 O << SPIRVNL(); 328 for (auto &I : ContinuedInstructions) 329 O << *I; 330 } 331 332 protected: validate()333 void validate() const override { 334 SPIRVValue::validate(); 335 for (auto &I : Elements) 336 getValue(I)->validate(); 337 } 338 setWordCount(SPIRVWord WordCount)339 void setWordCount(SPIRVWord WordCount) override { 340 SPIRVEntry::setWordCount(WordCount); 341 Elements.resize(WordCount - FixedWC); 342 } 343 encode(spv_ostream & O)344 void encode(spv_ostream &O) const override { 345 getEncoder(O) << Type << Id << Elements; 346 } 347 decode(std::istream & I)348 void decode(std::istream &I) override { 349 SPIRVDecoder Decoder = getDecoder(I); 350 Decoder >> Type >> Id >> Elements; 351 352 for (SPIRVEntry *E : Decoder.getContinuedInstructions(ContinuedOpCode)) { 353 addContinuedInstruction(static_cast<ContinuedInstType>(E)); 354 } 355 } 356 357 std::vector<SPIRVId> Elements; 358 std::vector<ContinuedInstType> ContinuedInstructions; 359 const spv::Op ContinuedOpCode = InstToContinued<OC>::OpCode; 360 }; 361 362 using SPIRVConstantComposite = SPIRVConstantCompositeBase<OpConstantComposite>; 363 using SPIRVSpecConstantComposite = 364 SPIRVConstantCompositeBase<OpSpecConstantComposite>; 365 366 class SPIRVConstantSampler : public SPIRVValue { 367 public: 368 const static Op OC = OpConstantSampler; 369 const static SPIRVWord WC = 6; 370 // Complete constructor SPIRVConstantSampler(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord TheAddrMode,SPIRVWord TheNormalized,SPIRVWord TheFilterMode)371 SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 372 SPIRVWord TheAddrMode, SPIRVWord TheNormalized, 373 SPIRVWord TheFilterMode) 374 : SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode), 375 Normalized(TheNormalized), FilterMode(TheFilterMode) { 376 validate(); 377 } 378 // Incomplete constructor SPIRVConstantSampler()379 SPIRVConstantSampler() 380 : SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid), Normalized(SPIRVWORD_MAX), 381 FilterMode(SPIRVSFM_Invalid) {} 382 getAddrMode()383 SPIRVWord getAddrMode() const { return AddrMode; } 384 getFilterMode()385 SPIRVWord getFilterMode() const { return FilterMode; } 386 getNormalized()387 SPIRVWord getNormalized() const { return Normalized; } getRequiredCapability()388 SPIRVCapVec getRequiredCapability() const override { 389 return getVec(CapabilityLiteralSampler); 390 } 391 392 protected: 393 SPIRVWord AddrMode; 394 SPIRVWord Normalized; 395 SPIRVWord FilterMode; validate()396 void validate() const override { 397 SPIRVValue::validate(); 398 assert(OpCode == OC); 399 assert(WordCount == WC); 400 assert(Type->isTypeSampler()); 401 } 402 _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode) 403 }; 404 405 class SPIRVConstantPipeStorage : public SPIRVValue { 406 public: 407 const static Op OC = OpConstantPipeStorage; 408 const static SPIRVWord WC = 6; 409 // Complete constructor SPIRVConstantPipeStorage(SPIRVModule * M,SPIRVType * TheType,SPIRVId TheId,SPIRVWord ThePacketSize,SPIRVWord ThePacketAlign,SPIRVWord TheCapacity)410 SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, 411 SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign, 412 SPIRVWord TheCapacity) 413 : SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize), 414 PacketAlign(ThePacketAlign), Capacity(TheCapacity) { 415 validate(); 416 } 417 // Incomplete constructor SPIRVConstantPipeStorage()418 SPIRVConstantPipeStorage() 419 : SPIRVValue(OC), PacketSize(0), PacketAlign(0), Capacity(0) {} 420 getPacketSize()421 SPIRVWord getPacketSize() const { return PacketSize; } 422 getPacketAlign()423 SPIRVWord getPacketAlign() const { return PacketAlign; } 424 getCapacity()425 SPIRVWord getCapacity() const { return Capacity; } getRequiredCapability()426 SPIRVCapVec getRequiredCapability() const override { 427 return getVec(CapabilityPipes, CapabilityPipeStorage); 428 } 429 430 protected: 431 SPIRVWord PacketSize; 432 SPIRVWord PacketAlign; 433 SPIRVWord Capacity; validate()434 void validate() const override { 435 SPIRVValue::validate(); 436 assert(OpCode == OC); 437 assert(WordCount == WC); 438 assert(Type->isTypePipeStorage()); 439 } 440 _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity) 441 }; 442 443 class SPIRVForward : public SPIRVValue, public SPIRVComponentExecutionModes { 444 public: 445 const static Op OC = internal::OpForward; 446 // Complete constructor SPIRVForward(SPIRVModule * TheModule,SPIRVType * TheTy,SPIRVId TheId)447 SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId) 448 : SPIRVValue(TheModule, 0, OC, TheId) { 449 if (TheTy) 450 setType(TheTy); 451 } SPIRVForward()452 SPIRVForward() : SPIRVValue(OC) { assert(0 && "should never be called"); } _SPIRV_DEF_ENCDEC1(Id)453 _SPIRV_DEF_ENCDEC1(Id) 454 friend class SPIRVFunction; 455 456 protected: 457 void validate() const override {} 458 }; 459 460 } // namespace SPIRV 461 462 #endif // SPIRV_LIBSPIRV_SPIRVVALUE_H 463