1 //===- SPIRVInstruction.h - Class to represent SPIRV instruction -*- 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 Instruction class for SPIR-V. 37 /// 38 //===----------------------------------------------------------------------===// 39 40 #ifndef SPIRVINSTRUCTION_HPP_ 41 #define SPIRVINSTRUCTION_HPP_ 42 43 #include "SPIRVEnum.h" 44 #include "SPIRVIsValidEnum.h" 45 #include "SPIRVStream.h" 46 #include "SPIRVValue.h" 47 #include "SPIRVBasicBlock.h" 48 #include "SPIRVOpCode.h" 49 50 #include <cassert> 51 #include <cstdint> 52 #include <functional> 53 #include <iostream> 54 #include <map> 55 #include <utility> 56 #include <vector> 57 #include <unordered_set> 58 59 namespace SPIRV{ 60 61 typedef std::vector<SPIRVValue *> ValueVec; 62 typedef std::pair<ValueVec::iterator, ValueVec::iterator> ValueRange; 63 64 class SPIRVBasicBlock; 65 class SPIRVFunction; 66 67 bool isSpecConstantOpAllowedOp(Op OC); 68 69 class SPIRVComponentExecutionScope { 70 public: 71 SPIRVComponentExecutionScope(Scope TheScope = ScopeInvocation): ExecScope(TheScope)72 ExecScope(TheScope){} 73 Scope ExecScope; 74 }; 75 76 class SPIRVComponentMemorySemanticsMask { 77 public: 78 SPIRVComponentMemorySemanticsMask(SPIRVWord TheSema = SPIRVWORD_MAX): MemSema(TheSema)79 MemSema(TheSema){} 80 SPIRVWord MemSema; 81 }; 82 83 class SPIRVComponentOperands { 84 public: SPIRVComponentOperands()85 SPIRVComponentOperands(){}; SPIRVComponentOperands(const std::vector<SPIRVValue * > & TheOperands)86 SPIRVComponentOperands(const std::vector<SPIRVValue *> &TheOperands): 87 Operands(TheOperands){}; SPIRVComponentOperands(std::vector<SPIRVValue * > && TheOperands)88 SPIRVComponentOperands(std::vector<SPIRVValue *> &&TheOperands): 89 Operands(std::move(TheOperands)){}; getCompOperands()90 std::vector<SPIRVValue *> getCompOperands() { 91 return Operands; 92 } getCompOperandTypes()93 std::vector<SPIRVType *> getCompOperandTypes() { 94 std::vector<SPIRVType *> Tys; 95 for (auto &I:getCompOperands()) 96 Tys.push_back(I->getType()); 97 return Tys; 98 } 99 protected: 100 std::vector<SPIRVValue *> Operands; 101 }; 102 103 class SPIRVInstruction: public SPIRVValue { 104 public: 105 // Complete constructor for instruction with type and id 106 SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, 107 SPIRVId TheId, SPIRVBasicBlock *TheBB); 108 // Complete constructor for instruction with module, type and id 109 SPIRVInstruction(unsigned TheWordCount, Op TheOC, 110 SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, 111 SPIRVModule *TheBM); 112 // Complete constructor for instruction with id but no type 113 SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId, 114 SPIRVBasicBlock *TheBB); 115 // Complete constructor for instruction without type and id 116 SPIRVInstruction(unsigned TheWordCount, Op TheOC, 117 SPIRVBasicBlock *TheBB); 118 // Complete constructor for instruction with type but no id 119 SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, 120 SPIRVBasicBlock *TheBB); 121 // Incomplete constructor SPIRVValue(TheOC)122 SPIRVInstruction(Op TheOC = OpNop):SPIRVValue(TheOC), BB(NULL){} 123 isInst()124 virtual bool isInst() const { return true;} getParent()125 SPIRVBasicBlock *getParent() const {return BB;} getPrevious()126 SPIRVInstruction *getPrevious() const { return BB->getPrevious(this);} getNext()127 SPIRVInstruction *getNext() const { return BB->getNext(this);} 128 virtual std::vector<SPIRVValue *> getOperands(); 129 std::vector<SPIRVType*> getOperandTypes(); 130 static std::vector<SPIRVType*> getOperandTypes( 131 const std::vector<SPIRVValue *> &Ops); 132 133 void setParent(SPIRVBasicBlock *); 134 void setScope(SPIRVEntry *); addFPRoundingMode(SPIRVFPRoundingModeKind Kind)135 void addFPRoundingMode(SPIRVFPRoundingModeKind Kind) { 136 addDecorate(DecorationFPRoundingMode, Kind); 137 } eraseFPRoundingMode()138 void eraseFPRoundingMode() { 139 eraseDecorate(DecorationFPRoundingMode); 140 } setSaturatedConversion(bool Enable)141 void setSaturatedConversion(bool Enable) { 142 if (Enable) 143 addDecorate(DecorationSaturatedConversion); 144 else 145 eraseDecorate(DecorationSaturatedConversion); 146 } 147 bool hasFPRoundingMode(SPIRVFPRoundingModeKind *Kind = nullptr) { 148 SPIRVWord V; 149 auto Found = hasDecorate(DecorationFPRoundingMode, 0, &V); 150 if (Found && Kind) 151 *Kind = static_cast<SPIRVFPRoundingModeKind>(V); 152 return Found; 153 } isSaturatedConversion()154 bool isSaturatedConversion() { 155 return hasDecorate(DecorationSaturatedConversion) || 156 OpCode == OpSatConvertSToU || 157 OpCode == OpSatConvertUToS; 158 } 159 getBasicBlock()160 SPIRVBasicBlock* getBasicBlock() const { 161 return BB; 162 } 163 setBasicBlock(SPIRVBasicBlock * TheBB)164 void setBasicBlock(SPIRVBasicBlock* TheBB) { 165 BB = TheBB; 166 if (TheBB) 167 setModule(TheBB->getModule()); 168 } 169 170 protected: validate()171 void validate()const { 172 SPIRVValue::validate(); 173 } 174 private: 175 SPIRVBasicBlock *BB; 176 }; 177 178 class SPIRVInstTemplateBase:public SPIRVInstruction { 179 public: 180 /// Create an empty instruction. Mainly for getting format information, 181 /// e.g. whether an operand is literal. create(Op TheOC)182 static SPIRVInstTemplateBase *create(Op TheOC){ 183 auto Inst = static_cast<SPIRVInstTemplateBase *>(SPIRVEntry::create(TheOC)); 184 assert(Inst); 185 Inst->init(); 186 return Inst; 187 } 188 /// Create a instruction without operands. create(Op TheOC,SPIRVType * TheType,SPIRVId TheId,SPIRVBasicBlock * TheBB,SPIRVModule * TheModule)189 static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, 190 SPIRVId TheId, SPIRVBasicBlock *TheBB, 191 SPIRVModule *TheModule){ 192 auto Inst = create(TheOC); 193 Inst->init(TheType, TheId, TheBB, TheModule); 194 return Inst; 195 } 196 /// Create a complete and valid instruction. create(Op TheOC,SPIRVType * TheType,SPIRVId TheId,const std::vector<SPIRVWord> & TheOps,SPIRVBasicBlock * TheBB,SPIRVModule * TheModule)197 static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, 198 SPIRVId TheId, const std::vector<SPIRVWord> &TheOps, SPIRVBasicBlock *TheBB, 199 SPIRVModule *TheModule){ 200 auto Inst = create(TheOC); 201 Inst->init(TheType, TheId, TheBB, TheModule); 202 Inst->setOpWords(TheOps); 203 Inst->validate(); 204 return Inst; 205 } 206 SPIRVInstTemplateBase(Op OC = OpNop) SPIRVInstruction(OC)207 :SPIRVInstruction(OC), HasVariWC(false){ 208 init(); 209 } ~SPIRVInstTemplateBase()210 virtual ~SPIRVInstTemplateBase(){} init(SPIRVType * TheType,SPIRVId TheId,SPIRVBasicBlock * TheBB,SPIRVModule * TheModule)211 SPIRVInstTemplateBase *init(SPIRVType *TheType, 212 SPIRVId TheId, SPIRVBasicBlock *TheBB, 213 SPIRVModule *TheModule){ 214 assert((TheBB || TheModule) && "Invalid BB or Module"); 215 if (TheBB) 216 setBasicBlock(TheBB); 217 else { 218 setModule(TheModule); 219 } 220 setId(hasId() ? TheId : SPIRVID_INVALID); 221 setType(hasType() ? TheType : nullptr); 222 return this; 223 } init()224 virtual void init() {} 225 virtual void initImpl(Op OC, bool HasId = true, SPIRVWord WC = 0, 226 bool VariWC = false, unsigned Lit1 = ~0U, 227 unsigned Lit2 = ~0U, unsigned Lit3 = ~0U){ 228 OpCode = OC; 229 if (!HasId) { 230 setHasNoId(); 231 setHasNoType(); 232 } 233 if (WC) 234 SPIRVEntry::setWordCount(WC); 235 setHasVariableWordCount(VariWC); 236 addLit(Lit1); 237 addLit(Lit2); 238 addLit(Lit3); 239 } isOperandLiteral(unsigned I)240 virtual bool isOperandLiteral(unsigned I) const { 241 return Lit.count(I); 242 } addLit(unsigned L)243 void addLit(unsigned L) { 244 if (L != ~0U) 245 Lit.insert(L); 246 } 247 /// \return Expected number of operands. If the instruction has variable 248 /// number of words, return the minimum. getExpectedNumOperands()249 SPIRVWord getExpectedNumOperands() const { 250 assert(WordCount > 0 && "Word count not initialized"); 251 auto Exp = WordCount - 1; 252 if (hasId()) 253 --Exp; 254 if (hasType()) 255 --Exp; 256 return Exp; 257 } setOpWordsAndValidate(const std::vector<SPIRVWord> & TheOps)258 virtual void setOpWordsAndValidate(const std::vector<SPIRVWord> &TheOps) { 259 setOpWords(TheOps); 260 validate(); 261 } setOpWords(const std::vector<SPIRVWord> & TheOps)262 virtual void setOpWords(const std::vector<SPIRVWord> &TheOps) { 263 SPIRVWord WC = TheOps.size() + 1; 264 if (hasId()) 265 ++WC; 266 if (hasType()) 267 ++WC; 268 if (WordCount) { 269 if (WordCount == WC) { 270 // do nothing 271 } else { 272 assert(HasVariWC && WC >= WordCount && "Invalid word count"); 273 SPIRVEntry::setWordCount(WC); 274 } 275 } else 276 SPIRVEntry::setWordCount(WC); 277 Ops = TheOps; 278 } setWordCount(SPIRVWord TheWordCount)279 virtual void setWordCount(SPIRVWord TheWordCount) { 280 SPIRVEntry::setWordCount(TheWordCount); 281 auto NumOps = WordCount - 1; 282 if (hasId()) 283 --NumOps; 284 if (hasType()) 285 --NumOps; 286 Ops.resize(NumOps); 287 } 288 getOpWords()289 std::vector<SPIRVWord> &getOpWords() { 290 return Ops; 291 } 292 getOpWords()293 const std::vector<SPIRVWord> &getOpWords() const { 294 return Ops; 295 } 296 getOpWord(int I)297 SPIRVWord getOpWord(int I) const { 298 return Ops[I]; 299 } 300 301 /// Get operand as value. 302 /// If the operand is a literal, return it as a uint32 constant. getOpValue(int I)303 SPIRVValue *getOpValue(int I) { 304 return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I]) : 305 getValue(Ops[I]); 306 } 307 308 // Get the offset of operands. 309 // Some instructions skip literals when returning operands. getOperandOffset()310 size_t getOperandOffset() const { 311 if (hasExecScope() && !isGroupOpCode(OpCode) && !isPipeOpCode(OpCode)) 312 return 1; 313 return 0; 314 } 315 316 // Get operands which are values. 317 // Drop execution scope and group operation literals. 318 // Return other literals as uint32 constants. getOperands()319 virtual std::vector<SPIRVValue *> getOperands() { 320 std::vector<SPIRVValue*> VOps; 321 auto Offset = getOperandOffset(); 322 for (size_t I = 0, E = Ops.size() - Offset; I != E; ++I) 323 VOps.push_back(getOperand(I)); 324 return VOps; 325 } 326 getNonLiteralOperands()327 virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { 328 std::vector<SPIRVEntry*> Operands; 329 for (size_t I = getOperandOffset(), E = Ops.size(); I < E; ++I) 330 if (!isOperandLiteral(I)) 331 Operands.push_back(getEntry(Ops[I])); 332 return Operands; 333 } 334 getOperand(unsigned I)335 virtual SPIRVValue *getOperand(unsigned I) { 336 return getOpValue(I + getOperandOffset()); 337 } 338 hasExecScope()339 bool hasExecScope() const { 340 return SPIRV::hasExecScope(OpCode); 341 } 342 hasGroupOperation()343 bool hasGroupOperation() const { 344 return SPIRV::hasGroupOperation(OpCode); 345 } 346 getSPIRVGroupOperation(SPIRVGroupOperationKind & GroupOp)347 bool getSPIRVGroupOperation(SPIRVGroupOperationKind &GroupOp) const { 348 if (!hasGroupOperation()) 349 return false; 350 GroupOp = static_cast<SPIRVGroupOperationKind>(Ops[1]); 351 return true; 352 } 353 getExecutionScope()354 Scope getExecutionScope() const { 355 if(!hasExecScope()) 356 return ScopeInvocation; 357 return static_cast<Scope>( 358 static_cast<SPIRVConstant*>(getValue(Ops[0]))->getZExtIntValue()); 359 } 360 hasVariableWordCount()361 bool hasVariableWordCount() const { 362 return HasVariWC; 363 } 364 setHasVariableWordCount(bool VariWC)365 void setHasVariableWordCount(bool VariWC) { 366 HasVariWC = VariWC; 367 } 368 369 protected: encode(spv_ostream & O)370 virtual void encode(spv_ostream &O) const { 371 auto E = getEncoder(O); 372 if (hasType()) 373 E << Type; 374 if (hasId()) 375 E << Id; 376 E << Ops; 377 } decode(std::istream & I)378 virtual void decode(std::istream &I) { 379 auto D = getDecoder(I); 380 if (hasType()) 381 D >> Type; 382 if (hasId()) 383 D >> Id; 384 D >> Ops; 385 } 386 std::vector<SPIRVWord> Ops; 387 bool HasVariWC; 388 std::unordered_set<unsigned> Lit; // Literal operand index 389 }; 390 391 template<typename BT = SPIRVInstTemplateBase, 392 Op OC = OpNop, 393 bool HasId = true, 394 SPIRVWord WC = 0, 395 bool HasVariableWC = false, 396 unsigned Literal1 = ~0U, 397 unsigned Literal2 = ~0U, 398 unsigned Literal3 = ~0U> 399 class SPIRVInstTemplate:public BT { 400 public: 401 typedef BT BaseTy; SPIRVInstTemplate()402 SPIRVInstTemplate(){ 403 init(); 404 } ~SPIRVInstTemplate()405 virtual ~SPIRVInstTemplate(){} init()406 virtual void init() { 407 this->initImpl(OC, HasId, WC, HasVariableWC, Literal1, Literal2, Literal3); 408 } 409 }; 410 411 class SPIRVMemoryAccess { 412 public: SPIRVMemoryAccess(const std::vector<SPIRVWord> & TheMemoryAccess)413 SPIRVMemoryAccess(const std::vector<SPIRVWord> &TheMemoryAccess): 414 TheMemoryAccessMask(0), Alignment(0) { 415 MemoryAccessUpdate(TheMemoryAccess); 416 } 417 SPIRVMemoryAccess()418 SPIRVMemoryAccess() : TheMemoryAccessMask(0), Alignment(0){} 419 MemoryAccessUpdate(const std::vector<SPIRVWord> & MemoryAccess)420 void MemoryAccessUpdate(const std::vector<SPIRVWord> &MemoryAccess) { 421 if (!MemoryAccess.size()) 422 return; 423 assert((MemoryAccess.size() == 1 || MemoryAccess.size() == 2) && "Invalid memory access operand size"); 424 TheMemoryAccessMask = MemoryAccess[0]; 425 if (MemoryAccess[0] & MemoryAccessAlignedMask) { 426 assert(MemoryAccess.size() == 2 && "Alignment operand is missing"); 427 Alignment = MemoryAccess[1]; 428 } 429 } isVolatile()430 SPIRVWord isVolatile() const { return getMemoryAccessMask() & MemoryAccessVolatileMask; } isNonTemporal()431 SPIRVWord isNonTemporal() const { return getMemoryAccessMask() & MemoryAccessNontemporalMask; } getMemoryAccessMask()432 SPIRVWord getMemoryAccessMask() const { return TheMemoryAccessMask; } getAlignment()433 SPIRVWord getAlignment() const { return Alignment; } 434 435 protected: 436 SPIRVWord TheMemoryAccessMask; 437 SPIRVWord Alignment; 438 }; 439 440 class SPIRVVariable : public SPIRVInstruction { 441 public: 442 // Complete constructor for integer constant SPIRVVariable(SPIRVType * TheType,SPIRVId TheId,SPIRVValue * TheInitializer,const std::string & TheName,SPIRVStorageClassKind TheStorageClass,SPIRVBasicBlock * TheBB,SPIRVModule * TheM)443 SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, 444 SPIRVValue *TheInitializer, const std::string &TheName, 445 SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB, 446 SPIRVModule *TheM) 447 :SPIRVInstruction(TheInitializer ? 5 : 4, OpVariable, TheType, 448 TheId, TheBB, TheM), 449 StorageClass(TheStorageClass){ 450 if (TheInitializer) 451 Initializer.push_back(TheInitializer->getId()); 452 Name = TheName; 453 validate(); 454 } 455 // Incomplete constructor SPIRVVariable()456 SPIRVVariable() :SPIRVInstruction(OpVariable), 457 StorageClass(StorageClassFunction){} 458 getStorageClass()459 SPIRVStorageClassKind getStorageClass() const { return StorageClass; } getInitializer()460 SPIRVValue *getInitializer() const { 461 if (Initializer.empty()) 462 return nullptr; 463 assert(Initializer.size() == 1); 464 return getValue(Initializer[0]); 465 } isConstant()466 bool isConstant() const { 467 return hasDecorate(DecorationConstant); 468 } 469 bool isBuiltin(SPIRVBuiltinVariableKind *BuiltinKind = nullptr) const { 470 SPIRVWord Kind; 471 bool Found = hasDecorate(DecorationBuiltIn, 0, &Kind); 472 if (!Found) 473 return false; 474 if (BuiltinKind) 475 *BuiltinKind = static_cast<SPIRVBuiltinVariableKind>(Kind); 476 return true; 477 } setBuiltin(SPIRVBuiltinVariableKind Kind)478 void setBuiltin(SPIRVBuiltinVariableKind Kind) { 479 assert(isValid(Kind)); 480 addDecorate(new SPIRVDecorate(DecorationBuiltIn, this, Kind)); 481 } setIsConstant(bool Is)482 void setIsConstant(bool Is) { 483 if (Is) 484 addDecorate(new SPIRVDecorate(DecorationConstant, this)); 485 else 486 eraseDecorate(DecorationConstant); 487 } getNonLiteralOperands()488 virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { 489 if (SPIRVValue *V = getInitializer()) 490 return std::vector<SPIRVEntry*>(1, V); 491 return std::vector<SPIRVEntry*>(); 492 } 493 protected: validate()494 void validate() const { 495 SPIRVValue::validate(); 496 assert(isValid(StorageClass)); 497 assert(Initializer.size() == 1 || Initializer.empty()); 498 } setWordCount(SPIRVWord TheWordCount)499 void setWordCount(SPIRVWord TheWordCount) { 500 SPIRVEntry::setWordCount(TheWordCount); 501 Initializer.resize(WordCount - 4); 502 } 503 _SPIRV_DEF_ENCDEC4(Type, Id, StorageClass, Initializer) 504 505 SPIRVStorageClassKind StorageClass; 506 std::vector<SPIRVId> Initializer; 507 }; 508 509 class SPIRVStore:public SPIRVInstruction, public SPIRVMemoryAccess { 510 public: 511 const static SPIRVWord FixedWords = 3; 512 // Complete constructor 513 SPIRVStore(SPIRVId PointerId, SPIRVId ValueId, 514 const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB) 515 :SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OpStore, 516 TheBB), 517 SPIRVMemoryAccess(TheMemoryAccess), 518 MemoryAccess(TheMemoryAccess), 519 PtrId(PointerId), 520 ValId(ValueId){ 521 setAttr(); 522 validate(); 523 assert(TheBB && "Invalid BB"); 524 } 525 // Incomplete constructor 526 SPIRVStore():SPIRVInstruction(OpStore), SPIRVMemoryAccess(), 527 PtrId(SPIRVID_INVALID), ValId(SPIRVID_INVALID){ 528 setAttr(); 529 } 530 531 SPIRVValue *getSrc() const { return getValue(ValId);} 532 SPIRVValue *getDst() const { return getValue(PtrId);} 533 protected: 534 void setAttr() { 535 setHasNoType(); 536 setHasNoId(); 537 } 538 539 void setWordCount(SPIRVWord TheWordCount) { 540 SPIRVEntry::setWordCount(TheWordCount); 541 MemoryAccess.resize(TheWordCount - FixedWords); 542 } 543 void encode(spv_ostream &O) const { 544 getEncoder(O) << PtrId << ValId << MemoryAccess; 545 } 546 547 void decode(std::istream &I) { 548 getDecoder(I) >> PtrId >> ValId >> MemoryAccess; 549 MemoryAccessUpdate(MemoryAccess); 550 } 551 552 void validate()const { 553 SPIRVInstruction::validate(); 554 if (getSrc()->isForward() || getDst()->isForward()) 555 return; 556 assert(getValueType(PtrId)->getPointerElementType() == getValueType(ValId) 557 && "Inconsistent operand types"); 558 } 559 private: 560 std::vector<SPIRVWord> MemoryAccess; 561 SPIRVId PtrId; 562 SPIRVId ValId; 563 }; 564 565 class SPIRVLoad:public SPIRVInstruction, public SPIRVMemoryAccess { 566 public: 567 const static SPIRVWord FixedWords = 4; 568 // Complete constructor 569 SPIRVLoad(SPIRVId TheId, SPIRVId PointerId, 570 const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB) 571 :SPIRVInstruction(FixedWords + TheMemoryAccess.size() , OpLoad, 572 TheBB->getValueType(PointerId)->getPointerElementType(), TheId, TheBB), 573 SPIRVMemoryAccess(TheMemoryAccess), PtrId(PointerId), 574 MemoryAccess(TheMemoryAccess) { 575 validate(); 576 assert(TheBB && "Invalid BB"); 577 } 578 // Incomplete constructor 579 SPIRVLoad():SPIRVInstruction(OpLoad), SPIRVMemoryAccess(), 580 PtrId(SPIRVID_INVALID){} 581 582 SPIRVValue *getSrc() const { return Module->get<SPIRVValue>(PtrId);} 583 584 protected: 585 void setWordCount(SPIRVWord TheWordCount) { 586 SPIRVEntry::setWordCount(TheWordCount); 587 MemoryAccess.resize(TheWordCount - FixedWords); 588 } 589 590 void encode(spv_ostream &O) const { 591 getEncoder(O) << Type << Id << PtrId << MemoryAccess; 592 } 593 594 void decode(std::istream &I) { 595 getDecoder(I) >> Type >> Id >> PtrId >> MemoryAccess; 596 MemoryAccessUpdate(MemoryAccess); 597 } 598 599 void validate()const { 600 SPIRVInstruction::validate(); 601 assert((getValue(PtrId)->isForward() || 602 Type == getValueType(PtrId)->getPointerElementType()) && 603 "Inconsistent types"); 604 } 605 private: 606 SPIRVId PtrId; 607 std::vector<SPIRVWord> MemoryAccess; 608 }; 609 610 class SPIRVBinary:public SPIRVInstTemplateBase { 611 protected: 612 void validate()const { 613 SPIRVId Op1 = Ops[0]; 614 SPIRVId Op2 = Ops[1]; 615 SPIRVType *op1Ty, *op2Ty; 616 SPIRVInstruction::validate(); 617 if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) 618 return; 619 if (getValueType(Op1)->isTypeVector()) { 620 op1Ty = getValueType(Op1)->getVectorComponentType(); 621 op2Ty = getValueType(Op2)->getVectorComponentType(); 622 assert(getValueType(Op1)->getVectorComponentCount() == 623 getValueType(Op2)->getVectorComponentCount() && 624 "Inconsistent Vector component width"); 625 } 626 else { 627 op1Ty = getValueType(Op1); 628 op2Ty = getValueType(Op2); 629 } 630 631 if (isBinaryOpCode(OpCode)) { 632 assert(getValueType(Op1)== getValueType(Op2) && 633 "Invalid type for binary instruction"); 634 assert((op1Ty->isTypeInt() || op2Ty->isTypeFloat()) && 635 "Invalid type for Binary instruction"); 636 assert((op1Ty->getBitWidth() == op2Ty->getBitWidth()) && 637 "Inconsistent BitWidth"); 638 } else if (isShiftOpCode(OpCode)) { 639 assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && 640 "Invalid type for shift instruction"); 641 } else if (isLogicalOpCode(OpCode)) { 642 assert((op1Ty->isTypeBool() || op2Ty->isTypeBool()) && 643 "Invalid type for logical instruction"); 644 } else if (isBitwiseOpCode(OpCode)) { 645 assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && 646 "Invalid type for bitwise instruction"); 647 assert((op1Ty->getIntegerBitWidth() == op2Ty->getIntegerBitWidth()) && 648 "Inconsistent BitWidth"); 649 } else { 650 assert(0 && "Invalid op code!"); 651 } 652 } 653 }; 654 655 template<Op OC> 656 class SPIRVBinaryInst:public SPIRVInstTemplate<SPIRVBinary, OC, true, 5, false> { 657 }; 658 659 /* ToDo: SMod and FMod to be added */ 660 #define _SPIRV_OP(x) typedef SPIRVBinaryInst<Op##x> SPIRV##x; 661 _SPIRV_OP(IAdd) 662 _SPIRV_OP(FAdd) 663 _SPIRV_OP(ISub) 664 _SPIRV_OP(FSub) 665 _SPIRV_OP(IMul) 666 _SPIRV_OP(FMul) 667 _SPIRV_OP(UDiv) 668 _SPIRV_OP(SDiv) 669 _SPIRV_OP(FDiv) 670 _SPIRV_OP(SRem) 671 _SPIRV_OP(FRem) 672 _SPIRV_OP(UMod) 673 _SPIRV_OP(ShiftLeftLogical) 674 _SPIRV_OP(ShiftRightLogical) 675 _SPIRV_OP(ShiftRightArithmetic) 676 _SPIRV_OP(LogicalAnd) 677 _SPIRV_OP(LogicalOr) 678 _SPIRV_OP(LogicalEqual) 679 _SPIRV_OP(LogicalNotEqual) 680 _SPIRV_OP(BitwiseAnd) 681 _SPIRV_OP(BitwiseOr) 682 _SPIRV_OP(BitwiseXor) 683 _SPIRV_OP(Dot) 684 #undef _SPIRV_OP 685 686 template<Op TheOpCode> 687 class SPIRVInstNoOperand:public SPIRVInstruction { 688 public: 689 // Complete constructor 690 SPIRVInstNoOperand(SPIRVBasicBlock *TheBB):SPIRVInstruction(1, TheOpCode, 691 TheBB){ 692 setAttr(); 693 validate(); 694 } 695 // Incomplete constructor 696 SPIRVInstNoOperand():SPIRVInstruction(TheOpCode){ 697 setAttr(); 698 } 699 protected: 700 void setAttr() { 701 setHasNoId(); 702 setHasNoType(); 703 } 704 _SPIRV_DEF_ENCDEC0 705 }; 706 707 typedef SPIRVInstNoOperand<OpReturn> SPIRVReturn; 708 709 class SPIRVReturnValue:public SPIRVInstruction { 710 public: 711 static const Op OC = OpReturnValue; 712 // Complete constructor 713 SPIRVReturnValue(SPIRVValue *TheReturnValue, SPIRVBasicBlock *TheBB) 714 :SPIRVInstruction(2, OC, TheBB), ReturnValueId(TheReturnValue->getId()){ 715 setAttr(); 716 validate(); 717 assert(TheBB && "Invalid BB"); 718 } 719 // Incomplete constructor 720 SPIRVReturnValue():SPIRVInstruction(OC), ReturnValueId(SPIRVID_INVALID) { 721 setAttr(); 722 } 723 724 SPIRVValue *getReturnValue() const { 725 return getValue(ReturnValueId); 726 } 727 protected: 728 void setAttr() { 729 setHasNoId(); 730 setHasNoType(); 731 } 732 _SPIRV_DEF_ENCDEC1(ReturnValueId) 733 void validate()const { 734 SPIRVInstruction::validate(); 735 } 736 SPIRVId ReturnValueId; 737 }; 738 739 class SPIRVBranch:public SPIRVInstruction { 740 public: 741 static const Op OC = OpBranch; 742 // Complete constructor 743 SPIRVBranch(SPIRVLabel *TheTargetLabel,SPIRVBasicBlock *TheBB) 744 :SPIRVInstruction(2, OC, TheBB), TargetLabelId(TheTargetLabel->getId()) { 745 validate(); 746 assert(TheBB && "Invalid BB"); 747 } 748 // Incomplete constructor 749 SPIRVBranch():SPIRVInstruction(OC), TargetLabelId(SPIRVID_INVALID) { 750 setHasNoId(); 751 setHasNoType(); 752 } 753 SPIRVValue *getTargetLabel() const { 754 return getValue(TargetLabelId); 755 } 756 protected: 757 _SPIRV_DEF_ENCDEC1(TargetLabelId) 758 void validate()const { 759 SPIRVInstruction::validate(); 760 assert(WordCount == 2); 761 assert(OpCode == OC); 762 assert(getTargetLabel()->isLabel() || getTargetLabel()->isForward()); 763 } 764 SPIRVId TargetLabelId; 765 }; 766 767 class SPIRVBranchConditional:public SPIRVInstruction { 768 public: 769 static const Op OC = OpBranchConditional; 770 // Complete constructor 771 SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel, 772 SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB) 773 :SPIRVInstruction(4, OC, TheBB), ConditionId(TheCondition->getId()), 774 TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){ 775 validate(); 776 } 777 SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel, 778 SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB, SPIRVWord TrueWeight, 779 SPIRVWord FalseWeight) 780 :SPIRVInstruction(6, OC, TheBB), ConditionId(TheCondition->getId()), 781 TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){ 782 BranchWeights.push_back(TrueWeight); 783 BranchWeights.push_back(FalseWeight); 784 validate(); 785 assert(TheBB && "Invalid BB"); 786 } 787 // Incomplete constructor 788 SPIRVBranchConditional():SPIRVInstruction(OC), ConditionId(SPIRVID_INVALID), 789 TrueLabelId(SPIRVID_INVALID), FalseLabelId(SPIRVID_INVALID) { 790 setHasNoId(); 791 setHasNoType(); 792 } 793 SPIRVValue *getCondition() const { 794 return getValue(ConditionId); 795 } 796 SPIRVLabel *getTrueLabel() const { 797 return get<SPIRVLabel>(TrueLabelId); 798 } 799 SPIRVLabel *getFalseLabel() const { 800 return get<SPIRVLabel>(FalseLabelId); 801 } 802 protected: 803 void setWordCount(SPIRVWord TheWordCount) { 804 SPIRVEntry::setWordCount(TheWordCount); 805 BranchWeights.resize(TheWordCount - 4); 806 } 807 _SPIRV_DEF_ENCDEC4(ConditionId, TrueLabelId, FalseLabelId, BranchWeights) 808 void validate()const { 809 SPIRVInstruction::validate(); 810 assert(WordCount == 4 || WordCount == 6); 811 assert(WordCount == BranchWeights.size() + 4); 812 assert(OpCode == OC); 813 assert(getCondition()->isForward() || 814 getCondition()->getType()->isTypeBool()); 815 assert(getTrueLabel()->isForward() || getTrueLabel()->isLabel()); 816 assert(getFalseLabel()->isForward() || getFalseLabel()->isLabel()); 817 } 818 SPIRVId ConditionId; 819 SPIRVId TrueLabelId; 820 SPIRVId FalseLabelId; 821 std::vector<SPIRVWord> BranchWeights; 822 }; 823 824 class SPIRVPhi: public SPIRVInstruction { 825 public: 826 static const Op OC = OpPhi; 827 static const SPIRVWord FixedWordCount = 3; 828 SPIRVPhi(SPIRVType *TheType, SPIRVId TheId, 829 const std::vector<SPIRVValue *> &ThePairs, SPIRVBasicBlock *BB) 830 :SPIRVInstruction(ThePairs.size() + FixedWordCount, OC, TheType, TheId, BB){ 831 Pairs = getIds(ThePairs); 832 validate(); 833 assert(BB && "Invalid BB"); 834 } 835 SPIRVPhi():SPIRVInstruction(OC) {} 836 std::vector<SPIRVValue *> getPairs() { 837 return getValues(Pairs); 838 } 839 void addPair(SPIRVValue *Value, SPIRVBasicBlock *BB) { 840 Pairs.push_back(Value->getId()); 841 Pairs.push_back(BB->getId()); 842 WordCount = Pairs.size() + FixedWordCount; 843 validate(); 844 } 845 void setPairs(const std::vector<SPIRVValue *> &ThePairs) { 846 Pairs = getIds(ThePairs); 847 WordCount = Pairs.size() + FixedWordCount; 848 validate(); 849 } 850 void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *, 851 size_t)> Func) { 852 for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { 853 SPIRVEntry *Value, *BB; 854 if (!Module->exist(Pairs[2*I], &Value) || 855 !Module->exist(Pairs[2*I+1], &BB)) 856 continue; 857 Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB), 858 I); 859 } 860 } 861 void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *)> Func) 862 const { 863 for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { 864 SPIRVEntry *Value, *BB; 865 if (!Module->exist(Pairs[2*I], &Value) || 866 !Module->exist(Pairs[2*I+1], &BB)) 867 continue; 868 Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB)); 869 } 870 } 871 void setWordCount(SPIRVWord TheWordCount) { 872 SPIRVEntry::setWordCount(TheWordCount); 873 Pairs.resize(TheWordCount - FixedWordCount); 874 } 875 _SPIRV_DEF_ENCDEC3(Type, Id, Pairs) 876 void validate()const { 877 assert(WordCount == Pairs.size() + FixedWordCount); 878 assert(OpCode == OC); 879 assert(Pairs.size() % 2 == 0); 880 foreachPair([=](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB){ 881 assert(IncomingV->isForward() || IncomingV->getType() == Type); 882 assert(IncomingBB->isBasicBlock() || IncomingBB->isForward()); 883 }); 884 SPIRVInstruction::validate(); 885 } 886 protected: 887 std::vector<SPIRVId> Pairs; 888 }; 889 890 class SPIRVCompare:public SPIRVInstTemplateBase { 891 protected: 892 void validate()const { 893 auto Op1 = Ops[0]; 894 auto Op2 = Ops[1]; 895 SPIRVType *op1Ty, *op2Ty, *resTy; 896 SPIRVInstruction::validate(); 897 if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) 898 return; 899 900 if (getValueType(Op1)->isTypeVector()) { 901 op1Ty = getValueType(Op1)->getVectorComponentType(); 902 op2Ty = getValueType(Op2)->getVectorComponentType(); 903 resTy = Type->getVectorComponentType(); 904 assert(getValueType(Op1)->getVectorComponentCount() == 905 getValueType(Op2)->getVectorComponentCount() && 906 "Inconsistent Vector component width"); 907 } 908 else { 909 op1Ty = getValueType(Op1); 910 op2Ty = getValueType(Op2); 911 resTy = Type; 912 } 913 assert(isCmpOpCode(OpCode) && "Invalid op code for cmp inst"); 914 assert((resTy->isTypeBool() || resTy->isTypeInt()) && 915 "Invalid type for compare instruction"); 916 assert(op1Ty == op2Ty && "Inconsistent types"); 917 } 918 }; 919 920 template<Op OC> 921 class SPIRVCmpInst:public SPIRVInstTemplate<SPIRVCompare, OC, true, 5, false> { 922 }; 923 924 #define _SPIRV_OP(x) typedef SPIRVCmpInst<Op##x> SPIRV##x; 925 _SPIRV_OP(IEqual) 926 _SPIRV_OP(FOrdEqual) 927 _SPIRV_OP(FUnordEqual) 928 _SPIRV_OP(INotEqual) 929 _SPIRV_OP(FOrdNotEqual) 930 _SPIRV_OP(FUnordNotEqual) 931 _SPIRV_OP(ULessThan) 932 _SPIRV_OP(SLessThan) 933 _SPIRV_OP(FOrdLessThan) 934 _SPIRV_OP(FUnordLessThan) 935 _SPIRV_OP(UGreaterThan) 936 _SPIRV_OP(SGreaterThan) 937 _SPIRV_OP(FOrdGreaterThan) 938 _SPIRV_OP(FUnordGreaterThan) 939 _SPIRV_OP(ULessThanEqual) 940 _SPIRV_OP(SLessThanEqual) 941 _SPIRV_OP(FOrdLessThanEqual) 942 _SPIRV_OP(FUnordLessThanEqual) 943 _SPIRV_OP(UGreaterThanEqual) 944 _SPIRV_OP(SGreaterThanEqual) 945 _SPIRV_OP(FOrdGreaterThanEqual) 946 _SPIRV_OP(FUnordGreaterThanEqual) 947 _SPIRV_OP(LessOrGreater) 948 _SPIRV_OP(Ordered) 949 _SPIRV_OP(Unordered) 950 #undef _SPIRV_OP 951 952 class SPIRVSelect:public SPIRVInstruction { 953 public: 954 // Complete constructor 955 SPIRVSelect(SPIRVId TheId, SPIRVId TheCondition, SPIRVId TheOp1, SPIRVId TheOp2, 956 SPIRVBasicBlock *TheBB) 957 :SPIRVInstruction(6, OpSelect, TheBB->getValueType(TheOp1), TheId, 958 TheBB), Condition(TheCondition), Op1(TheOp1), Op2(TheOp2){ 959 validate(); 960 assert(TheBB && "Invalid BB"); 961 } 962 // Incomplete constructor 963 SPIRVSelect():SPIRVInstruction(OpSelect), Condition(SPIRVID_INVALID), 964 Op1(SPIRVID_INVALID), Op2(SPIRVID_INVALID){} 965 SPIRVValue *getCondition() { return getValue(Condition);} 966 SPIRVValue *getTrueValue() { return getValue(Op1);} 967 SPIRVValue *getFalseValue() { return getValue(Op2);} 968 protected: 969 _SPIRV_DEF_ENCDEC5(Type, Id, Condition, Op1, Op2) 970 void validate()const { 971 SPIRVInstruction::validate(); 972 if (getValue(Condition)->isForward() || 973 getValue(Op1)->isForward() || 974 getValue(Op2)->isForward()) 975 return; 976 977 SPIRVType *conTy = getValueType(Condition)->isTypeVector() ? 978 getValueType(Condition)->getVectorComponentType() : 979 getValueType(Condition); 980 (void) conTy; 981 assert(conTy->isTypeBool() && "Invalid type"); 982 assert(getType() == getValueType(Op1) && getType() == getValueType(Op2) && 983 "Inconsistent type"); 984 } 985 SPIRVId Condition; 986 SPIRVId Op1; 987 SPIRVId Op2; 988 }; 989 990 class SPIRVSwitch: public SPIRVInstruction { 991 public: 992 static const Op OC = OpSwitch; 993 static const SPIRVWord FixedWordCount = 3; 994 SPIRVSwitch(SPIRVValue *TheSelect, SPIRVBasicBlock *TheDefault, 995 const std::vector<std::pair<SPIRVWord, SPIRVBasicBlock *>> &ThePairs, 996 SPIRVBasicBlock *BB) 997 :SPIRVInstruction(ThePairs.size() * 2 + FixedWordCount, OC, BB), 998 Select(TheSelect->getId()), Default(TheDefault->getId()) { 999 for (auto &I:ThePairs) { 1000 Pairs.push_back(I.first); 1001 Pairs.push_back(I.second->getId()); 1002 } 1003 validate(); 1004 assert(BB && "Invalid BB"); 1005 } 1006 SPIRVSwitch():SPIRVInstruction(OC), Select(SPIRVWORD_MAX), 1007 Default(SPIRVWORD_MAX) { 1008 setHasNoId(); 1009 setHasNoType(); 1010 } 1011 std::vector<SPIRVValue *> getPairs() { 1012 return getValues(Pairs); 1013 } 1014 SPIRVValue *getSelect() const { return getValue(Select);} 1015 SPIRVBasicBlock *getDefault() const { 1016 return static_cast<SPIRVBasicBlock *>(getValue(Default)); 1017 } 1018 size_t getNumPairs() const { return Pairs.size()/2;} 1019 void foreachPair(std::function<void(SPIRVWord, SPIRVBasicBlock *, size_t)> Func) 1020 const { 1021 for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { 1022 SPIRVEntry *BB; 1023 if (!Module->exist(Pairs[2*I+1], &BB)) 1024 continue; 1025 Func(Pairs[2*I], static_cast<SPIRVBasicBlock *>(BB), I); 1026 } 1027 } 1028 void setWordCount(SPIRVWord TheWordCount) { 1029 SPIRVEntry::setWordCount(TheWordCount); 1030 Pairs.resize(TheWordCount - FixedWordCount); 1031 } 1032 _SPIRV_DEF_ENCDEC3(Select, Default, Pairs) 1033 void validate()const { 1034 assert(WordCount == Pairs.size() + FixedWordCount); 1035 assert(OpCode == OC); 1036 assert(Pairs.size() % 2 == 0); 1037 foreachPair([=](SPIRVWord Literal, SPIRVBasicBlock *BB, size_t Index){ 1038 assert(BB->isBasicBlock() || BB->isForward()); 1039 }); 1040 SPIRVInstruction::validate(); 1041 } 1042 protected: 1043 SPIRVId Select; 1044 SPIRVId Default; 1045 std::vector<SPIRVWord> Pairs; 1046 }; 1047 1048 class SPIRVUnary:public SPIRVInstTemplateBase { 1049 protected: 1050 void validate()const { 1051 auto Op = Ops[0]; 1052 SPIRVInstruction::validate(); 1053 if (getValue(Op)->isForward()) 1054 return; 1055 if (isGenericNegateOpCode(OpCode)) { 1056 SPIRVType *resTy = Type->isTypeVector() ? 1057 Type->getVectorComponentType() : Type; 1058 SPIRVType *opTy = Type->isTypeVector() ? 1059 getValueType(Op)->getVectorComponentType() : getValueType(Op); 1060 1061 assert(getType() == getValueType(Op) && 1062 "Inconsistent type"); 1063 (void) resTy; 1064 assert((resTy->isTypeInt() || resTy->isTypeFloat()) && 1065 "Invalid type for Generic Negate instruction"); 1066 (void) opTy; 1067 assert((resTy->getBitWidth() == opTy->getBitWidth()) && 1068 "Invalid bitwidth for Generic Negate instruction"); 1069 assert((Type->isTypeVector() ? (Type->getVectorComponentCount() == 1070 getValueType(Op)->getVectorComponentCount()): 1) && 1071 "Invalid vector component Width for Generic Negate instruction"); 1072 } 1073 } 1074 }; 1075 1076 template<Op OC> 1077 class SPIRVUnaryInst:public SPIRVInstTemplate<SPIRVUnary, OC, true, 4, false> { 1078 }; 1079 1080 #define _SPIRV_OP(x) typedef SPIRVUnaryInst<Op##x> SPIRV##x; 1081 _SPIRV_OP(ConvertFToU) 1082 _SPIRV_OP(ConvertFToS) 1083 _SPIRV_OP(ConvertSToF) 1084 _SPIRV_OP(ConvertUToF) 1085 _SPIRV_OP(UConvert) 1086 _SPIRV_OP(SConvert) 1087 _SPIRV_OP(FConvert) 1088 _SPIRV_OP(SatConvertSToU) 1089 _SPIRV_OP(SatConvertUToS) 1090 _SPIRV_OP(ConvertPtrToU) 1091 _SPIRV_OP(ConvertUToPtr) 1092 _SPIRV_OP(PtrCastToGeneric) 1093 _SPIRV_OP(GenericCastToPtr) 1094 _SPIRV_OP(Bitcast) 1095 _SPIRV_OP(SNegate) 1096 _SPIRV_OP(FNegate) 1097 _SPIRV_OP(Not) 1098 _SPIRV_OP(LogicalNot) 1099 _SPIRV_OP(IsNan) 1100 _SPIRV_OP(IsInf) 1101 _SPIRV_OP(IsFinite) 1102 _SPIRV_OP(IsNormal) 1103 _SPIRV_OP(SignBitSet) 1104 _SPIRV_OP(Any) 1105 _SPIRV_OP(All) 1106 #undef _SPIRV_OP 1107 1108 class SPIRVAccessChainBase :public SPIRVInstTemplateBase { 1109 public: 1110 SPIRVValue *getBase() { return this->getValue(this->Ops[0]);} 1111 std::vector<SPIRVValue *> getIndices()const { 1112 std::vector<SPIRVWord> IndexWords(this->Ops.begin() + 1, this->Ops.end()); 1113 return this->getValues(IndexWords); 1114 } 1115 bool isInBounds() { 1116 return OpCode == OpInBoundsAccessChain || 1117 OpCode == OpInBoundsPtrAccessChain; 1118 } 1119 bool hasPtrIndex() { 1120 return OpCode == OpPtrAccessChain || 1121 OpCode == OpInBoundsPtrAccessChain; 1122 } 1123 }; 1124 1125 template<Op OC, unsigned FixedWC> 1126 class SPIRVAccessChainGeneric 1127 :public SPIRVInstTemplate<SPIRVAccessChainBase, OC, true, FixedWC, true> { 1128 }; 1129 1130 typedef SPIRVAccessChainGeneric<OpAccessChain, 4> SPIRVAccessChain; 1131 typedef SPIRVAccessChainGeneric<OpInBoundsAccessChain, 4> 1132 SPIRVInBoundsAccessChain; 1133 typedef SPIRVAccessChainGeneric<OpPtrAccessChain, 5> SPIRVPtrAccessChain; 1134 typedef SPIRVAccessChainGeneric<OpInBoundsPtrAccessChain, 5> 1135 SPIRVInBoundsPtrAccessChain; 1136 1137 template<Op OC, SPIRVWord FixedWordCount> 1138 class SPIRVFunctionCallGeneric: public SPIRVInstruction { 1139 public: 1140 SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, 1141 const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) 1142 :SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB), 1143 Args(TheArgs){ 1144 validate(); 1145 assert(BB && "Invalid BB"); 1146 } 1147 SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, 1148 const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB) 1149 :SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB) { 1150 Args = getIds(TheArgs); 1151 validate(); 1152 assert(BB && "Invalid BB"); 1153 } 1154 SPIRVFunctionCallGeneric():SPIRVInstruction(OC) {} 1155 const std::vector<SPIRVWord> &getArguments() { 1156 return Args; 1157 } 1158 std::vector<SPIRVValue *> getArgumentValues() { 1159 return getValues(Args); 1160 } 1161 std::vector<SPIRVType *> getArgumentValueTypes()const { 1162 std::vector<SPIRVType *> ArgTypes; 1163 for (auto &I:Args) 1164 ArgTypes.push_back(getValue(I)->getType()); 1165 return ArgTypes; 1166 } 1167 void setWordCount(SPIRVWord TheWordCount) { 1168 SPIRVEntry::setWordCount(TheWordCount); 1169 Args.resize(TheWordCount - FixedWordCount); 1170 } 1171 void validate()const { 1172 SPIRVInstruction::validate(); 1173 } 1174 protected: 1175 std::vector<SPIRVWord> Args; 1176 }; 1177 1178 class SPIRVFunctionCall: 1179 public SPIRVFunctionCallGeneric<OpFunctionCall, 4> { 1180 public: 1181 SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction, 1182 const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB); 1183 SPIRVFunctionCall():FunctionId(SPIRVID_INVALID) {} 1184 SPIRVFunction *getFunction()const { 1185 return get<SPIRVFunction>(FunctionId); 1186 } 1187 _SPIRV_DEF_ENCDEC4(Type, Id, FunctionId, Args) 1188 void validate()const; 1189 bool isOperandLiteral(unsigned Index) const { return false;} 1190 protected: 1191 SPIRVId FunctionId; 1192 }; 1193 1194 class SPIRVExtInst: public SPIRVFunctionCallGeneric<OpExtInst, 5> { 1195 public: 1196 SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, 1197 SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint, 1198 const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) 1199 :SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB), 1200 ExtSetId(TheBuiltinSet), 1201 ExtOp(TheEntryPoint) { 1202 setExtSetKindById(); 1203 validate(); 1204 } 1205 SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, 1206 SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint, 1207 const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB) 1208 :SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB), 1209 ExtSetId(TheBuiltinSet), 1210 ExtOp(TheEntryPoint) { 1211 setExtSetKindById(); 1212 validate(); 1213 } 1214 SPIRVExtInst(SPIRVExtInstSetKind SetKind = SPIRVEIS_Count, 1215 unsigned ExtOC = SPIRVWORD_MAX) 1216 :ExtSetId(SPIRVWORD_MAX), ExtOp(ExtOC), ExtSetKind(SetKind) {} 1217 void setExtSetId(unsigned Set) { ExtSetId = Set;} 1218 void setExtOp(unsigned ExtOC) { ExtOp = ExtOC;} 1219 SPIRVId getExtSetId()const { 1220 return ExtSetId; 1221 } 1222 SPIRVWord getExtOp()const { 1223 return ExtOp; 1224 } 1225 void setExtSetKindById() { 1226 assert(Module && "Invalid module"); 1227 ExtSetKind = Module->getBuiltinSet(ExtSetId); 1228 assert(ExtSetKind == SPIRVEIS_OpenCL && "not supported"); 1229 } 1230 void encode(spv_ostream &O) const { 1231 getEncoder(O) << Type << Id << ExtSetId; 1232 switch(ExtSetKind) { 1233 case SPIRVEIS_OpenCL: 1234 getEncoder(O) << ExtOpOCL; 1235 break; 1236 default: 1237 assert(0 && "not supported"); 1238 getEncoder(O) << ExtOp; 1239 } 1240 getEncoder(O) << Args; 1241 } 1242 void decode(std::istream &I) { 1243 getDecoder(I) >> Type >> Id >> ExtSetId; 1244 setExtSetKindById(); 1245 switch(ExtSetKind) { 1246 case SPIRVEIS_OpenCL: 1247 getDecoder(I) >> ExtOpOCL; 1248 break; 1249 default: 1250 assert(0 && "not supported"); 1251 getDecoder(I) >> ExtOp; 1252 } 1253 getDecoder(I) >> Args; 1254 } 1255 void validate()const { 1256 SPIRVFunctionCallGeneric::validate(); 1257 validateBuiltin(ExtSetId, ExtOp); 1258 } 1259 bool isOperandLiteral(unsigned Index) const { 1260 assert(ExtSetKind == SPIRVEIS_OpenCL && 1261 "Unsupported extended instruction set"); 1262 auto EOC = static_cast<OCLExtOpKind>(ExtOp); 1263 switch(EOC) { 1264 default: 1265 return false; 1266 case OpenCLLIB::Vloadn: 1267 case OpenCLLIB::Vload_halfn: 1268 case OpenCLLIB::Vloada_halfn: 1269 return Index == 2; 1270 case OpenCLLIB::Vstore_half_r: 1271 case OpenCLLIB::Vstore_halfn_r: 1272 case OpenCLLIB::Vstorea_halfn_r: 1273 return Index == 3; 1274 } 1275 } 1276 protected: 1277 SPIRVId ExtSetId; 1278 union { 1279 SPIRVWord ExtOp; 1280 OCLExtOpKind ExtOpOCL; 1281 }; 1282 SPIRVExtInstSetKind ExtSetKind; 1283 }; 1284 1285 class SPIRVCompositeExtract:public SPIRVInstruction { 1286 public: 1287 const static Op OC = OpCompositeExtract; 1288 // Complete constructor 1289 SPIRVCompositeExtract(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheComposite, 1290 const std::vector<SPIRVWord>& TheIndices, SPIRVBasicBlock *TheBB): 1291 SPIRVInstruction(TheIndices.size() + 4, OC, TheType, TheId, TheBB), 1292 Composite(TheComposite->getId()), Indices(TheIndices){ 1293 validate(); 1294 assert(TheBB && "Invalid BB"); 1295 } 1296 // Incomplete constructor 1297 SPIRVCompositeExtract():SPIRVInstruction(OC), Composite(SPIRVID_INVALID){} 1298 1299 SPIRVValue *getComposite() { return getValue(Composite);} 1300 const std::vector<SPIRVWord>& getIndices()const { return Indices;} 1301 protected: 1302 void setWordCount(SPIRVWord TheWordCount) { 1303 SPIRVEntry::setWordCount(TheWordCount); 1304 Indices.resize(TheWordCount - 4); 1305 } 1306 _SPIRV_DEF_ENCDEC4(Type, Id, Composite, Indices) 1307 // ToDo: validate the result type is consistent with the base type and indices 1308 // need to trace through the base type for struct types 1309 void validate()const { 1310 SPIRVInstruction::validate(); 1311 assert(getValueType(Composite)->isTypeArray() || 1312 getValueType(Composite)->isTypeStruct() || 1313 getValueType(Composite)->isTypeVector()); 1314 } 1315 SPIRVId Composite; 1316 std::vector<SPIRVWord> Indices; 1317 }; 1318 1319 class SPIRVCompositeInsert:public SPIRVInstruction { 1320 public: 1321 const static Op OC = OpCompositeInsert; 1322 const static SPIRVWord FixedWordCount = 5; 1323 // Complete constructor 1324 SPIRVCompositeInsert(SPIRVId TheId, SPIRVValue *TheObject, 1325 SPIRVValue *TheComposite, const std::vector<SPIRVWord>& TheIndices, 1326 SPIRVBasicBlock *TheBB): 1327 SPIRVInstruction(TheIndices.size() + FixedWordCount, OC, 1328 TheComposite->getType(), TheId, TheBB), 1329 Object(TheObject->getId()), Composite(TheComposite->getId()), 1330 Indices(TheIndices){ 1331 validate(); 1332 assert(TheBB && "Invalid BB"); 1333 } 1334 // Incomplete constructor 1335 SPIRVCompositeInsert():SPIRVInstruction(OC), Object(SPIRVID_INVALID), 1336 Composite(SPIRVID_INVALID){} 1337 1338 SPIRVValue *getObject() { return getValue(Object);} 1339 SPIRVValue *getComposite() { return getValue(Composite);} 1340 const std::vector<SPIRVWord>& getIndices()const { return Indices;} 1341 protected: 1342 void setWordCount(SPIRVWord TheWordCount) { 1343 SPIRVEntry::setWordCount(TheWordCount); 1344 Indices.resize(TheWordCount - FixedWordCount); 1345 } 1346 _SPIRV_DEF_ENCDEC5(Type, Id, Object, Composite, Indices) 1347 // ToDo: validate the object type is consistent with the base type and indices 1348 // need to trace through the base type for struct types 1349 void validate()const { 1350 SPIRVInstruction::validate(); 1351 assert(OpCode == OC); 1352 assert(WordCount == Indices.size() + FixedWordCount); 1353 assert(getValueType(Composite)->isTypeArray() || 1354 getValueType(Composite)->isTypeStruct() || 1355 getValueType(Composite)->isTypeVector()); 1356 assert(Type == getValueType(Composite)); 1357 } 1358 SPIRVId Object; 1359 SPIRVId Composite; 1360 std::vector<SPIRVWord> Indices; 1361 }; 1362 1363 class SPIRVCopyObject :public SPIRVInstruction { 1364 public: 1365 const static Op OC = OpCopyObject; 1366 1367 // Complete constructor 1368 SPIRVCopyObject(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheOperand, 1369 SPIRVBasicBlock *TheBB) : 1370 SPIRVInstruction(4, OC, TheType, TheId, TheBB), 1371 Operand(TheOperand->getId()) { 1372 validate(); 1373 assert(TheBB && "Invalid BB"); 1374 } 1375 // Incomplete constructor 1376 SPIRVCopyObject() :SPIRVInstruction(OC), Operand(SPIRVID_INVALID) {} 1377 1378 SPIRVValue *getOperand() { return getValue(Operand); } 1379 1380 protected: 1381 _SPIRV_DEF_ENCDEC3(Type, Id, Operand) 1382 1383 void validate()const { 1384 SPIRVInstruction::validate(); 1385 } 1386 SPIRVId Operand; 1387 }; 1388 1389 1390 class SPIRVCopyMemory :public SPIRVInstruction, public SPIRVMemoryAccess { 1391 public: 1392 const static Op OC = OpCopyMemory; 1393 const static SPIRVWord FixedWords = 3; 1394 // Complete constructor 1395 SPIRVCopyMemory(SPIRVValue *TheTarget, SPIRVValue *TheSource, 1396 const std::vector<SPIRVWord> &TheMemoryAccess, 1397 SPIRVBasicBlock *TheBB) : 1398 SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB), 1399 SPIRVMemoryAccess(TheMemoryAccess), 1400 MemoryAccess(TheMemoryAccess), 1401 Target(TheTarget->getId()), 1402 Source(TheSource->getId()) { 1403 validate(); 1404 assert(TheBB && "Invalid BB"); 1405 } 1406 1407 // Incomplete constructor 1408 SPIRVCopyMemory() :SPIRVInstruction(OC), SPIRVMemoryAccess(), 1409 Target(SPIRVID_INVALID), 1410 Source(SPIRVID_INVALID) { 1411 setHasNoId(); 1412 setHasNoType(); 1413 } 1414 1415 SPIRVValue *getSource() { return getValue(Source); } 1416 SPIRVValue *getTarget() { return getValue(Target); } 1417 1418 protected: 1419 void setWordCount(SPIRVWord TheWordCount) { 1420 SPIRVEntry::setWordCount(TheWordCount); 1421 MemoryAccess.resize(TheWordCount - FixedWords); 1422 } 1423 1424 void encode(spv_ostream &O) const { 1425 getEncoder(O) << Target << Source << MemoryAccess; 1426 } 1427 1428 void decode(std::istream &I) { 1429 getDecoder(I) >> Target >> Source >> MemoryAccess; 1430 MemoryAccessUpdate(MemoryAccess); 1431 } 1432 1433 void validate()const { 1434 assert((getValueType(Id) == getValueType(Source)) && "Inconsistent type"); 1435 assert(getValueType(Id)->isTypePointer() && "Invalid type"); 1436 assert(!(getValueType(Id)->getPointerElementType()->isTypeVoid()) && 1437 "Invalid type"); 1438 SPIRVInstruction::validate(); 1439 } 1440 1441 std::vector<SPIRVWord> MemoryAccess; 1442 SPIRVId Target; 1443 SPIRVId Source; 1444 }; 1445 1446 class SPIRVCopyMemorySized :public SPIRVInstruction, public SPIRVMemoryAccess { 1447 public: 1448 const static Op OC = OpCopyMemorySized; 1449 const static SPIRVWord FixedWords = 4; 1450 // Complete constructor 1451 SPIRVCopyMemorySized(SPIRVValue *TheTarget, SPIRVValue *TheSource, 1452 SPIRVValue *TheSize, const std::vector<SPIRVWord> &TheMemoryAccess, 1453 SPIRVBasicBlock *TheBB) : 1454 SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB), 1455 SPIRVMemoryAccess(TheMemoryAccess), 1456 MemoryAccess(TheMemoryAccess), 1457 Target(TheTarget->getId()), 1458 Source(TheSource->getId()), 1459 Size(TheSize->getId()) { 1460 validate(); 1461 assert(TheBB && "Invalid BB"); 1462 } 1463 // Incomplete constructor 1464 SPIRVCopyMemorySized() :SPIRVInstruction(OC), SPIRVMemoryAccess(), 1465 Target(SPIRVID_INVALID), Source(SPIRVID_INVALID), Size(0) { 1466 setHasNoId(); 1467 setHasNoType(); 1468 } 1469 1470 SPIRVValue *getSource() { return getValue(Source); } 1471 SPIRVValue *getTarget() { return getValue(Target); } 1472 SPIRVValue *getSize() { return getValue(Size); } 1473 1474 protected: 1475 void setWordCount(SPIRVWord TheWordCount) { 1476 SPIRVEntry::setWordCount(TheWordCount); 1477 MemoryAccess.resize(TheWordCount - FixedWords); 1478 } 1479 1480 void encode(spv_ostream &O) const { 1481 getEncoder(O) << Target << Source << Size << MemoryAccess; 1482 } 1483 1484 void decode(std::istream &I) { 1485 getDecoder(I) >> Target >> Source >> Size >> MemoryAccess; 1486 MemoryAccessUpdate(MemoryAccess); 1487 } 1488 1489 void validate()const { 1490 SPIRVInstruction::validate(); 1491 } 1492 1493 std::vector<SPIRVWord> MemoryAccess; 1494 SPIRVId Target; 1495 SPIRVId Source; 1496 SPIRVId Size; 1497 }; 1498 1499 class SPIRVVectorExtractDynamic:public SPIRVInstruction { 1500 public: 1501 const static Op OC = OpVectorExtractDynamic; 1502 // Complete constructor 1503 SPIRVVectorExtractDynamic(SPIRVId TheId, SPIRVValue *TheVector, 1504 SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB) 1505 :SPIRVInstruction(5, OC, TheVector->getType()->getVectorComponentType(), 1506 TheId, TheBB), VectorId(TheVector->getId()), 1507 IndexId(TheIndex->getId()){ 1508 validate(); 1509 assert(TheBB && "Invalid BB"); 1510 } 1511 // Incomplete constructor 1512 SPIRVVectorExtractDynamic():SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), 1513 IndexId(SPIRVID_INVALID){} 1514 1515 SPIRVValue *getVector() { return getValue(VectorId);} 1516 SPIRVValue *getIndex()const { return getValue(IndexId);} 1517 protected: 1518 _SPIRV_DEF_ENCDEC4(Type, Id, VectorId, IndexId) 1519 void validate()const { 1520 SPIRVInstruction::validate(); 1521 if (getValue(VectorId)->isForward()) 1522 return; 1523 assert(getValueType(VectorId)->isTypeVector()); 1524 } 1525 SPIRVId VectorId; 1526 SPIRVId IndexId; 1527 }; 1528 1529 class SPIRVVectorInsertDynamic :public SPIRVInstruction { 1530 public: 1531 const static Op OC = OpVectorInsertDynamic; 1532 // Complete constructor 1533 SPIRVVectorInsertDynamic(SPIRVId TheId, SPIRVValue *TheVector, 1534 SPIRVValue* TheComponent, SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB) 1535 :SPIRVInstruction(6, OC, TheVector->getType()->getVectorComponentType(), 1536 TheId, TheBB), VectorId(TheVector->getId()), 1537 IndexId(TheIndex->getId()), ComponentId(TheComponent->getId()){ 1538 validate(); 1539 assert(TheBB && "Invalid BB"); 1540 } 1541 // Incomplete constructor 1542 SPIRVVectorInsertDynamic() :SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), 1543 IndexId(SPIRVID_INVALID), ComponentId(SPIRVID_INVALID){} 1544 1545 SPIRVValue *getVector() { return getValue(VectorId); } 1546 SPIRVValue *getIndex()const { return getValue(IndexId); } 1547 SPIRVValue *getComponent() { return getValue(ComponentId); } 1548 protected: 1549 _SPIRV_DEF_ENCDEC5(Type, Id, VectorId, ComponentId, IndexId) 1550 void validate()const { 1551 SPIRVInstruction::validate(); 1552 if (getValue(VectorId)->isForward()) 1553 return; 1554 assert(getValueType(VectorId)->isTypeVector()); 1555 } 1556 SPIRVId VectorId; 1557 SPIRVId IndexId; 1558 SPIRVId ComponentId; 1559 }; 1560 1561 class SPIRVVectorShuffle:public SPIRVInstruction { 1562 public: 1563 const static Op OC = OpVectorShuffle; 1564 const static SPIRVWord FixedWordCount = 5; 1565 // Complete constructor 1566 SPIRVVectorShuffle(SPIRVId TheId, SPIRVType *TheType, SPIRVValue *TheVector1, 1567 SPIRVValue *TheVector2, const std::vector<SPIRVWord>& TheComponents, 1568 SPIRVBasicBlock *TheBB): 1569 SPIRVInstruction(TheComponents.size() + FixedWordCount, OC, TheType, 1570 TheId, TheBB), 1571 Vector1(TheVector1->getId()), Vector2(TheVector2->getId()), 1572 Components(TheComponents){ 1573 validate(); 1574 assert(TheBB && "Invalid BB"); 1575 } 1576 // Incomplete constructor 1577 SPIRVVectorShuffle():SPIRVInstruction(OC), Vector1(SPIRVID_INVALID), 1578 Vector2(SPIRVID_INVALID){} 1579 1580 SPIRVValue *getVector1() { return getValue(Vector1);} 1581 SPIRVValue *getVector2() { return getValue(Vector2);} 1582 const std::vector<SPIRVWord>& getComponents()const { return Components;} 1583 protected: 1584 void setWordCount(SPIRVWord TheWordCount) { 1585 SPIRVEntry::setWordCount(TheWordCount); 1586 Components.resize(TheWordCount - FixedWordCount); 1587 } 1588 _SPIRV_DEF_ENCDEC5(Type, Id, Vector1, Vector2, Components) 1589 void validate()const { 1590 SPIRVInstruction::validate(); 1591 assert(OpCode == OC); 1592 assert(WordCount == Components.size() + FixedWordCount); 1593 assert(Type->isTypeVector()); 1594 assert(Type->getVectorComponentType() == 1595 getValueType(Vector1)->getVectorComponentType()); 1596 if (getValue(Vector1)->isForward() || 1597 getValue(Vector2)->isForward()) 1598 return; 1599 assert(getValueType(Vector1) == getValueType(Vector2)); 1600 size_t CompCount = Type->getVectorComponentCount(); 1601 (void) CompCount; 1602 assert(Components.size() == CompCount); 1603 assert(Components.size() > 1); 1604 } 1605 SPIRVId Vector1; 1606 SPIRVId Vector2; 1607 std::vector<SPIRVWord> Components; 1608 }; 1609 1610 class SPIRVControlBarrier:public SPIRVInstruction { 1611 public: 1612 static const Op OC = OpControlBarrier; 1613 // Complete constructor 1614 SPIRVControlBarrier(SPIRVValue *TheScope, 1615 SPIRVValue *TheMemScope, SPIRVValue *TheMemSema, 1616 SPIRVBasicBlock *TheBB) 1617 :SPIRVInstruction(4, OC, TheBB), ExecScope(TheScope->getId()), 1618 MemScope(TheMemScope->getId()), MemSema(TheMemSema->getId()){ 1619 validate(); 1620 assert(TheBB && "Invalid BB"); 1621 } 1622 // Incomplete constructor 1623 SPIRVControlBarrier():SPIRVInstruction(OC), ExecScope(ScopeInvocation) { 1624 setHasNoId(); 1625 setHasNoType(); 1626 } 1627 void setWordCount(SPIRVWord TheWordCount) { 1628 SPIRVEntry::setWordCount(TheWordCount); 1629 } 1630 SPIRVValue *getExecScope() const { return getValue(ExecScope); } 1631 SPIRVValue *getMemScope() const { return getValue(MemScope); } 1632 SPIRVValue *getMemSemantic() const { return getValue(MemSema); } 1633 std::vector<SPIRVValue *> getOperands() { 1634 std::vector<SPIRVId> Operands; 1635 Operands.push_back(ExecScope); 1636 Operands.push_back(MemScope); 1637 Operands.push_back(MemSema); 1638 return getValues(Operands); 1639 } 1640 protected: 1641 _SPIRV_DEF_ENCDEC3(ExecScope, MemScope, MemSema) 1642 void validate()const { 1643 assert(OpCode == OC); 1644 assert(WordCount == 4); 1645 SPIRVInstruction::validate(); 1646 } 1647 SPIRVId ExecScope; 1648 SPIRVId MemScope; 1649 SPIRVId MemSema; 1650 }; 1651 1652 class SPIRVGroupAsyncCopy:public SPIRVInstruction { 1653 public: 1654 static const Op OC = OpGroupAsyncCopy; 1655 static const SPIRVWord WC = 9; 1656 // Complete constructor 1657 SPIRVGroupAsyncCopy(SPIRVValue *TheScope, SPIRVId TheId, 1658 SPIRVValue *TheDest, SPIRVValue *TheSrc, SPIRVValue *TheNumElems, 1659 SPIRVValue *TheStride, SPIRVValue *TheEvent, SPIRVBasicBlock *TheBB) 1660 :SPIRVInstruction(WC, OC, TheEvent->getType(), TheId, TheBB), 1661 ExecScope(TheScope->getId()), Destination(TheDest->getId()), 1662 Source(TheSrc->getId()), NumElements(TheNumElems->getId()), 1663 Stride(TheStride->getId()), Event(TheEvent->getId()){ 1664 validate(); 1665 assert(TheBB && "Invalid BB"); 1666 } 1667 // Incomplete constructor 1668 SPIRVGroupAsyncCopy():SPIRVInstruction(OC), ExecScope(SPIRVID_INVALID), 1669 Destination(SPIRVID_INVALID), Source(SPIRVID_INVALID), 1670 NumElements(SPIRVID_INVALID), Stride(SPIRVID_INVALID), 1671 Event(SPIRVID_INVALID){ 1672 } 1673 SPIRVValue *getExecScope() const { return getValue(ExecScope); } 1674 SPIRVValue *getDestination()const { return getValue(Destination);} 1675 SPIRVValue *getSource()const { return getValue(Source);} 1676 SPIRVValue *getNumElements()const { return getValue(NumElements);} 1677 SPIRVValue *getStride()const { return getValue(Stride);} 1678 SPIRVValue *getEvent()const { return getValue(Event);} 1679 std::vector<SPIRVValue *> getOperands() { 1680 std::vector<SPIRVId> Operands; 1681 Operands.push_back(Destination); 1682 Operands.push_back(Source); 1683 Operands.push_back(NumElements); 1684 Operands.push_back(Stride); 1685 Operands.push_back(Event); 1686 return getValues(Operands); 1687 } 1688 1689 protected: 1690 _SPIRV_DEF_ENCDEC8(Type, Id, ExecScope, Destination, Source, NumElements, 1691 Stride, Event) 1692 void validate()const { 1693 assert(OpCode == OC); 1694 assert(WordCount == WC); 1695 SPIRVInstruction::validate(); 1696 } 1697 SPIRVId ExecScope; 1698 SPIRVId Destination; 1699 SPIRVId Source; 1700 SPIRVId NumElements; 1701 SPIRVId Stride; 1702 SPIRVId Event; 1703 }; 1704 1705 enum SPIRVOpKind { 1706 SPIRVOPK_Id, 1707 SPIRVOPK_Literal, 1708 SPIRVOPK_Count 1709 }; 1710 1711 class SPIRVDevEnqInstBase:public SPIRVInstTemplateBase { 1712 public: 1713 SPIRVCapVec getRequiriedCapability() const { 1714 return getVec(CapabilityDeviceEnqueue); 1715 } 1716 }; 1717 1718 #define _SPIRV_OP(x, ...) \ 1719 typedef SPIRVInstTemplate<SPIRVDevEnqInstBase, Op##x, __VA_ARGS__> \ 1720 SPIRV##x; 1721 // CL 2.0 enqueue kernel builtins 1722 _SPIRV_OP(EnqueueMarker, true, 7) 1723 _SPIRV_OP(EnqueueKernel, true, 13, true) 1724 _SPIRV_OP(GetKernelNDrangeSubGroupCount, true, 8) 1725 _SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, true, 8) 1726 _SPIRV_OP(GetKernelWorkGroupSize, true, 7) 1727 _SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, true, 7) 1728 _SPIRV_OP(RetainEvent, false, 2) 1729 _SPIRV_OP(ReleaseEvent, false, 2) 1730 _SPIRV_OP(CreateUserEvent, true, 3) 1731 _SPIRV_OP(IsValidEvent, true, 4) 1732 _SPIRV_OP(SetUserEventStatus, false, 3) 1733 _SPIRV_OP(CaptureEventProfilingInfo, false, 4) 1734 _SPIRV_OP(GetDefaultQueue, true, 3) 1735 _SPIRV_OP(BuildNDRange, true, 6) 1736 #undef _SPIRV_OP 1737 1738 class SPIRVPipeInstBase:public SPIRVInstTemplateBase { 1739 public: 1740 SPIRVCapVec getRequiriedCapability() const { 1741 return getVec(CapabilityPipes); 1742 } 1743 }; 1744 1745 #define _SPIRV_OP(x, ...) \ 1746 typedef SPIRVInstTemplate<SPIRVPipeInstBase, Op##x, __VA_ARGS__> \ 1747 SPIRV##x; 1748 // CL 2.0 pipe builtins 1749 _SPIRV_OP(ReadPipe, true, 7) 1750 _SPIRV_OP(WritePipe, true, 7) 1751 _SPIRV_OP(ReservedReadPipe, true, 9) 1752 _SPIRV_OP(ReservedWritePipe, true, 9) 1753 _SPIRV_OP(ReserveReadPipePackets, true, 7) 1754 _SPIRV_OP(ReserveWritePipePackets, true, 7) 1755 _SPIRV_OP(CommitReadPipe, false, 5) 1756 _SPIRV_OP(CommitWritePipe, false, 5) 1757 _SPIRV_OP(IsValidReserveId, true, 4) 1758 _SPIRV_OP(GetNumPipePackets, true, 6) 1759 _SPIRV_OP(GetMaxPipePackets, true, 6) 1760 #undef _SPIRV_OP 1761 1762 class SPIRVPipeStorageInstBase :public SPIRVInstTemplateBase { 1763 public: 1764 SPIRVCapVec getRequiriedCapability() const { 1765 return getVec(CapabilityPipeStorage, CapabilityPipes); 1766 } 1767 }; 1768 1769 #define _SPIRV_OP(x, ...) \ 1770 typedef SPIRVInstTemplate<SPIRVPipeStorageInstBase, Op##x, __VA_ARGS__> \ 1771 SPIRV##x; 1772 1773 _SPIRV_OP(CreatePipeFromPipeStorage, true, 4) 1774 #undef _SPIRV_OP 1775 1776 class SPIRVGroupInstBase:public SPIRVInstTemplateBase { 1777 public: 1778 SPIRVCapVec getRequiriedCapability() const { 1779 return getVec(CapabilityGroups); 1780 } 1781 }; 1782 1783 #define _SPIRV_OP(x, ...) \ 1784 typedef SPIRVInstTemplate<SPIRVGroupInstBase, Op##x, __VA_ARGS__> \ 1785 SPIRV##x; 1786 // Group instructions 1787 _SPIRV_OP(GroupWaitEvents, false, 4) 1788 _SPIRV_OP(GroupAll, true, 5) 1789 _SPIRV_OP(GroupAny, true, 5) 1790 _SPIRV_OP(GroupBroadcast, true, 6) 1791 _SPIRV_OP(GroupIAdd, true, 6, false, 1) 1792 _SPIRV_OP(GroupFAdd, true, 6, false, 1) 1793 _SPIRV_OP(GroupFMin, true, 6, false, 1) 1794 _SPIRV_OP(GroupUMin, true, 6, false, 1) 1795 _SPIRV_OP(GroupSMin, true, 6, false, 1) 1796 _SPIRV_OP(GroupFMax, true, 6, false, 1) 1797 _SPIRV_OP(GroupUMax, true, 6, false, 1) 1798 _SPIRV_OP(GroupSMax, true, 6, false, 1) 1799 _SPIRV_OP(GroupReserveReadPipePackets, true, 8) 1800 _SPIRV_OP(GroupReserveWritePipePackets, true, 8) 1801 _SPIRV_OP(GroupCommitReadPipe, false, 6) 1802 _SPIRV_OP(GroupCommitWritePipe, false, 6) 1803 #undef _SPIRV_OP 1804 1805 class SPIRVAtomicInstBase:public SPIRVInstTemplateBase { 1806 public: 1807 SPIRVCapVec getRequiriedCapability() const { 1808 return getVec(CapabilityInt64Atomics); 1809 } 1810 }; 1811 1812 #define _SPIRV_OP(x, ...) \ 1813 typedef SPIRVInstTemplate<SPIRVAtomicInstBase, Op##x, __VA_ARGS__> \ 1814 SPIRV##x; 1815 // Atomic builtins 1816 _SPIRV_OP(AtomicFlagTestAndSet, true, 6) 1817 _SPIRV_OP(AtomicFlagClear, false, 4) 1818 _SPIRV_OP(AtomicLoad, true, 6) 1819 _SPIRV_OP(AtomicStore, false, 5) 1820 _SPIRV_OP(AtomicExchange, true, 7) 1821 _SPIRV_OP(AtomicCompareExchange, true, 9) 1822 _SPIRV_OP(AtomicCompareExchangeWeak, true, 9) 1823 _SPIRV_OP(AtomicIIncrement, true, 6) 1824 _SPIRV_OP(AtomicIDecrement, true, 6) 1825 _SPIRV_OP(AtomicIAdd, true, 7) 1826 _SPIRV_OP(AtomicISub, true, 7) 1827 _SPIRV_OP(AtomicUMin, true, 7) 1828 _SPIRV_OP(AtomicUMax, true, 7) 1829 _SPIRV_OP(AtomicSMin, true, 7) 1830 _SPIRV_OP(AtomicSMax, true, 7) 1831 _SPIRV_OP(AtomicAnd, true, 7) 1832 _SPIRV_OP(AtomicOr, true, 7) 1833 _SPIRV_OP(AtomicXor, true, 7) 1834 _SPIRV_OP(MemoryBarrier, false, 3) 1835 #undef _SPIRV_OP 1836 1837 class SPIRVImageInstBase:public SPIRVInstTemplateBase { 1838 public: 1839 SPIRVCapVec getRequiriedCapability() const { 1840 return getVec(CapabilityImageBasic); 1841 } 1842 }; 1843 1844 #define _SPIRV_OP(x, ...) \ 1845 typedef SPIRVInstTemplate<SPIRVImageInstBase, Op##x, __VA_ARGS__> \ 1846 SPIRV##x; 1847 // Image instructions 1848 _SPIRV_OP(SampledImage, true, 5) 1849 _SPIRV_OP(ImageSampleImplicitLod, true, 5, true) 1850 _SPIRV_OP(ImageSampleExplicitLod, true, 7, true, 2) 1851 _SPIRV_OP(ImageRead, true, 5, true, 2) 1852 _SPIRV_OP(ImageWrite, false, 4, true, 3) 1853 _SPIRV_OP(ImageQueryFormat, true, 4) 1854 _SPIRV_OP(ImageQueryOrder, true, 4) 1855 _SPIRV_OP(ImageQuerySizeLod, true, 5) 1856 _SPIRV_OP(ImageQuerySize, true, 4) 1857 _SPIRV_OP(ImageQueryLod, true, 5) 1858 _SPIRV_OP(ImageQueryLevels, true, 4) 1859 _SPIRV_OP(ImageQuerySamples, true, 4) 1860 #undef _SPIRV_OP 1861 1862 #define _SPIRV_OP(x, ...) \ 1863 typedef SPIRVInstTemplate<SPIRVInstTemplateBase, Op##x, __VA_ARGS__> \ 1864 SPIRV##x; 1865 // Other instructions 1866 _SPIRV_OP(SpecConstantOp, true, 4, true, 0) 1867 _SPIRV_OP(GenericPtrMemSemantics, true, 4, false) 1868 _SPIRV_OP(GenericCastToPtrExplicit, true, 5, false, 1) 1869 #undef _SPIRV_OP 1870 1871 SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst); 1872 SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *C); 1873 } 1874 1875 #endif // SPIRVINSTRUCTION_HPP_ 1876