1 // 2 // Copyright (C) 2014-2015 LunarG, Inc. 3 // Copyright (C) 2015-2016 Google, Inc. 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions 9 // are met: 10 // 11 // Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // 14 // Redistributions in binary form must reproduce the above 15 // copyright notice, this list of conditions and the following 16 // disclaimer in the documentation and/or other materials provided 17 // with the distribution. 18 // 19 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20 // contributors may be used to endorse or promote products derived 21 // from this software without specific prior written permission. 22 // 23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 // POSSIBILITY OF SUCH DAMAGE. 35 36 // 37 // "Builder" is an interface to fully build SPIR-V IR. Allocate one of 38 // these to build (a thread safe) internal SPIR-V representation (IR), 39 // and then dump it as a binary stream according to the SPIR-V specification. 40 // 41 // A Builder has a 1:1 relationship with a SPIR-V module. 42 // 43 44 #pragma once 45 #ifndef SpvBuilder_H 46 #define SpvBuilder_H 47 48 #include "Logger.h" 49 #include "spirv.hpp" 50 #include "spvIR.h" 51 52 #include <algorithm> 53 #include <map> 54 #include <memory> 55 #include <set> 56 #include <sstream> 57 #include <stack> 58 59 namespace spv { 60 61 class Builder { 62 public: 63 Builder(unsigned int userNumber, SpvBuildLogger* logger); 64 virtual ~Builder(); 65 66 static const int maxMatrixSize = 4; 67 68 void setSource(spv::SourceLanguage lang, int version) 69 { 70 source = lang; 71 sourceVersion = version; 72 } 73 void setSourceFile(const std::string& file) 74 { 75 Instruction* fileString = new Instruction(getUniqueId(), NoType, OpString); 76 fileString->addStringOperand(file.c_str()); 77 sourceFileStringId = fileString->getResultId(); 78 strings.push_back(std::unique_ptr<Instruction>(fileString)); 79 } 80 void setSourceText(const std::string& text) { sourceText = text; } 81 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); } 82 void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); } 83 void setEmitOpLines() { emitOpLines = true; } 84 void addExtension(const char* ext) { extensions.insert(ext); } 85 Id import(const char*); 86 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem) 87 { 88 addressModel = addr; 89 memoryModel = mem; 90 } 91 92 void addCapability(spv::Capability cap) { capabilities.insert(cap); } 93 94 // To get a new <id> for anything needing a new one. 95 Id getUniqueId() { return ++uniqueId; } 96 97 // To get a set of new <id>s, e.g., for a set of function parameters 98 Id getUniqueIds(int numIds) 99 { 100 Id id = uniqueId + 1; 101 uniqueId += numIds; 102 return id; 103 } 104 105 // Log the current line, and if different than the last one, 106 // issue a new OpLine, using the current file name. 107 void setLine(int line); 108 // Low-level OpLine. See setLine() for a layered helper. 109 void addLine(Id fileName, int line, int column); 110 111 // For creating new types (will return old type if the requested one was already made). 112 Id makeVoidType(); 113 Id makeBoolType(); 114 Id makePointer(StorageClass, Id type); 115 Id makeIntegerType(int width, bool hasSign); // generic 116 Id makeIntType(int width) { return makeIntegerType(width, true); } 117 Id makeUintType(int width) { return makeIntegerType(width, false); } 118 Id makeFloatType(int width); 119 Id makeStructType(const std::vector<Id>& members, const char*); 120 Id makeStructResultType(Id type0, Id type1); 121 Id makeVectorType(Id component, int size); 122 Id makeMatrixType(Id component, int cols, int rows); 123 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration 124 Id makeRuntimeArray(Id element); 125 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes); 126 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format); 127 Id makeSamplerType(); 128 Id makeSampledImageType(Id imageType); 129 130 // For querying about types. 131 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); } 132 Id getDerefTypeId(Id resultId) const; 133 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); } 134 Op getTypeClass(Id typeId) const { return getOpCode(typeId); } 135 Op getMostBasicTypeClass(Id typeId) const; 136 int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); } 137 int getNumTypeConstituents(Id typeId) const; 138 int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); } 139 Id getScalarTypeId(Id typeId) const; 140 Id getContainedTypeId(Id typeId) const; 141 Id getContainedTypeId(Id typeId, int) const; 142 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); } 143 ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } 144 145 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); } 146 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); } 147 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); } 148 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); } 149 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); } 150 bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); } 151 152 bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } 153 bool isIntType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; } 154 bool isUintType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; } 155 bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; } 156 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; } 157 bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; } 158 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; } 159 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; } 160 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; } 161 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; } 162 bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); } 163 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; } 164 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; } 165 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; } 166 167 bool isConstantOpCode(Op opcode) const; 168 bool isSpecConstantOpCode(Op opcode) const; 169 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); } 170 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; } 171 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); } 172 unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); } 173 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); } 174 175 int getScalarTypeWidth(Id typeId) const 176 { 177 Id scalarTypeId = getScalarTypeId(typeId); 178 assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat); 179 return module.getInstruction(scalarTypeId)->getImmediateOperand(0); 180 } 181 182 int getTypeNumColumns(Id typeId) const 183 { 184 assert(isMatrixType(typeId)); 185 return getNumTypeConstituents(typeId); 186 } 187 int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); } 188 int getTypeNumRows(Id typeId) const 189 { 190 assert(isMatrixType(typeId)); 191 return getNumTypeComponents(getContainedTypeId(typeId)); 192 } 193 int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); } 194 195 Dim getTypeDimensionality(Id typeId) const 196 { 197 assert(isImageType(typeId)); 198 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1); 199 } 200 Id getImageType(Id resultId) const 201 { 202 Id typeId = getTypeId(resultId); 203 assert(isImageType(typeId) || isSampledImageType(typeId)); 204 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId; 205 } 206 bool isArrayedImageType(Id typeId) const 207 { 208 assert(isImageType(typeId)); 209 return module.getInstruction(typeId)->getImmediateOperand(3) != 0; 210 } 211 212 // For making new constants (will return old constant if the requested one was already made). 213 Id makeBoolConstant(bool b, bool specConstant = false); 214 Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); } 215 Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); } 216 Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); } 217 Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); } 218 #ifdef AMD_EXTENSIONS 219 Id makeInt16Constant(short i, bool specConstant = false) { return makeIntConstant(makeIntType(16), (unsigned)((unsigned short)i), specConstant); } 220 Id makeUint16Constant(unsigned short u, bool specConstant = false) { return makeIntConstant(makeUintType(16), (unsigned)u, specConstant); } 221 #endif 222 Id makeFloatConstant(float f, bool specConstant = false); 223 Id makeDoubleConstant(double d, bool specConstant = false); 224 #ifdef AMD_EXTENSIONS 225 Id makeFloat16Constant(float f16, bool specConstant = false); 226 #endif 227 228 // Turn the array of constants into a proper spv constant of the requested type. 229 Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false); 230 231 // Methods for adding information outside the CFG. 232 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name); 233 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1); 234 void addName(Id, const char* name); 235 void addMemberName(Id, int member, const char* name); 236 void addDecoration(Id, Decoration, int num = -1); 237 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1); 238 239 // At the end of what block do the next create*() instructions go? 240 void setBuildPoint(Block* bp) { buildPoint = bp; } 241 Block* getBuildPoint() const { return buildPoint; } 242 243 // Make the entry-point function. The returned pointer is only valid 244 // for the lifetime of this builder. 245 Function* makeEntryPoint(const char*); 246 247 // Make a shader-style function, and create its entry block if entry is non-zero. 248 // Return the function, pass back the entry. 249 // The returned pointer is only valid for the lifetime of this builder. 250 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes, 251 const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0); 252 253 // Create a return. An 'implicit' return is one not appearing in the source 254 // code. In the case of an implicit return, no post-return block is inserted. 255 void makeReturn(bool implicit, Id retVal = 0); 256 257 // Generate all the code needed to finish up a function. 258 void leaveFunction(); 259 260 // Create a discard. 261 void makeDiscard(); 262 263 // Create a global or function local or IO variable. 264 Id createVariable(StorageClass, Id type, const char* name = 0); 265 266 // Create an intermediate with an undefined value. 267 Id createUndefined(Id type); 268 269 // Store into an Id and return the l-value 270 void createStore(Id rValue, Id lValue); 271 272 // Load from an Id and return it 273 Id createLoad(Id lValue); 274 275 // Create an OpAccessChain instruction 276 Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets); 277 278 // Create an OpArrayLength instruction 279 Id createArrayLength(Id base, unsigned int member); 280 281 // Create an OpCompositeExtract instruction 282 Id createCompositeExtract(Id composite, Id typeId, unsigned index); 283 Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes); 284 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index); 285 Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes); 286 287 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex); 288 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex); 289 290 void createNoResultOp(Op); 291 void createNoResultOp(Op, Id operand); 292 void createNoResultOp(Op, const std::vector<Id>& operands); 293 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask); 294 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics); 295 Id createUnaryOp(Op, Id typeId, Id operand); 296 Id createBinOp(Op, Id typeId, Id operand1, Id operand2); 297 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3); 298 Id createOp(Op, Id typeId, const std::vector<Id>& operands); 299 Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&); 300 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals); 301 302 // Take an rvalue (source) and a set of channels to extract from it to 303 // make a new rvalue, which is returned. 304 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels); 305 306 // Take a copy of an lvalue (target) and a source of components, and set the 307 // source components into the lvalue where the 'channels' say to put them. 308 // An updated version of the target is returned. 309 // (No true lvalue or stores are used.) 310 Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels); 311 312 // If both the id and precision are valid, the id 313 // gets tagged with the requested precision. 314 // The passed in id is always the returned id, to simplify use patterns. 315 Id setPrecision(Id id, Decoration precision) 316 { 317 if (precision != NoPrecision && id != NoResult) 318 addDecoration(id, precision); 319 320 return id; 321 } 322 323 // Can smear a scalar to a vector for the following forms: 324 // - promoteScalar(scalar, vector) // smear scalar to width of vector 325 // - promoteScalar(vector, scalar) // smear scalar to width of vector 326 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to 327 // - promoteScalar(scalar, scalar) // do nothing 328 // Other forms are not allowed. 329 // 330 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'. 331 // The type of the created vector is a vector of components of the same type as the scalar. 332 // 333 // Note: One of the arguments will change, with the result coming back that way rather than 334 // through the return value. 335 void promoteScalar(Decoration precision, Id& left, Id& right); 336 337 // Make a value by smearing the scalar to fill the type. 338 // vectorType should be the correct type for making a vector of scalarVal. 339 // (No conversions are done.) 340 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType); 341 342 // Create a call to a built-in function. 343 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args); 344 345 // List of parameters used to create a texture operation 346 struct TextureParameters { 347 Id sampler; 348 Id coords; 349 Id bias; 350 Id lod; 351 Id Dref; 352 Id offset; 353 Id offsets; 354 Id gradX; 355 Id gradY; 356 Id sample; 357 Id component; 358 Id texelOut; 359 Id lodClamp; 360 }; 361 362 // Select the correct texture operation based on all inputs, and emit the correct instruction 363 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&); 364 365 // Emit the OpTextureQuery* instruction that was passed in. 366 // Figure out the right return value and type, and return it. 367 Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult); 368 369 Id createSamplePositionCall(Decoration precision, Id, Id); 370 371 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned); 372 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id); 373 374 // Reduction comparison for composites: For equal and not-equal resulting in a scalar. 375 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */); 376 377 // OpCompositeConstruct 378 Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents); 379 380 // vector or scalar constructor 381 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId); 382 383 // matrix constructor 384 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee); 385 386 // Helper to use for building nested control flow with if-then-else. 387 class If { 388 public: 389 If(Id condition, unsigned int ctrl, Builder& builder); 390 ~If() {} 391 392 void makeBeginElse(); 393 void makeEndIf(); 394 395 private: 396 If(const If&); 397 If& operator=(If&); 398 399 Builder& builder; 400 Id condition; 401 unsigned int control; 402 Function* function; 403 Block* headerBlock; 404 Block* thenBlock; 405 Block* elseBlock; 406 Block* mergeBlock; 407 }; 408 409 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing 410 // any case/default labels, all separated by one or more case/default labels. Each possible 411 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this 412 // number space. How to compute the value is given by 'condition', as in switch(condition). 413 // 414 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches. 415 // 416 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch). 417 // 418 // Returns the right set of basic blocks to start each code segment with, so that the caller's 419 // recursion stack can hold the memory for it. 420 // 421 void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues, 422 const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); // return argument 423 424 // Add a branch to the innermost switch's merge block. 425 void addSwitchBreak(); 426 427 // Move to the next code segment, passing in the return argument in makeSwitch() 428 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment); 429 430 // Finish off the innermost switch. 431 void endSwitch(std::vector<Block*>& segmentBB); 432 433 struct LoopBlocks { 434 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) : 435 head(head), body(body), merge(merge), continue_target(continue_target) { } 436 Block &head, &body, &merge, &continue_target; 437 private: 438 LoopBlocks(); 439 LoopBlocks& operator=(const LoopBlocks&); 440 }; 441 442 // Start a new loop and prepare the builder to generate code for it. Until 443 // closeLoop() is called for this loop, createLoopContinue() and 444 // createLoopExit() will target its corresponding blocks. 445 LoopBlocks& makeNewLoop(); 446 447 // Create a new block in the function containing the build point. Memory is 448 // owned by the function object. 449 Block& makeNewBlock(); 450 451 // Add a branch to the continue_target of the current (innermost) loop. 452 void createLoopContinue(); 453 454 // Add an exit (e.g. "break") from the innermost loop that we're currently 455 // in. 456 void createLoopExit(); 457 458 // Close the innermost loop that you're in 459 void closeLoop(); 460 461 // 462 // Access chain design for an R-Value vs. L-Value: 463 // 464 // There is a single access chain the builder is building at 465 // any particular time. Such a chain can be used to either to a load or 466 // a store, when desired. 467 // 468 // Expressions can be r-values, l-values, or both, or only r-values: 469 // a[b.c].d = .... // l-value 470 // ... = a[b.c].d; // r-value, that also looks like an l-value 471 // ++a[b.c].d; // r-value and l-value 472 // (x + y)[2]; // r-value only, can't possibly be l-value 473 // 474 // Computing an r-value means generating code. Hence, 475 // r-values should only be computed when they are needed, not speculatively. 476 // 477 // Computing an l-value means saving away information for later use in the compiler, 478 // no code is generated until the l-value is later dereferenced. It is okay 479 // to speculatively generate an l-value, just not okay to speculatively dereference it. 480 // 481 // The base of the access chain (the left-most variable or expression 482 // from which everything is based) can be set either as an l-value 483 // or as an r-value. Most efficient would be to set an l-value if one 484 // is available. If an expression was evaluated, the resulting r-value 485 // can be set as the chain base. 486 // 487 // The users of this single access chain can save and restore if they 488 // want to nest or manage multiple chains. 489 // 490 491 struct AccessChain { 492 Id base; // for l-values, pointer to the base object, for r-values, the base object 493 std::vector<Id> indexChain; 494 Id instr; // cache the instruction that generates this access chain 495 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number 496 Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present 497 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present 498 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value 499 }; 500 501 // 502 // the SPIR-V builder maintains a single active chain that 503 // the following methods operate on 504 // 505 506 // for external save and restore 507 AccessChain getAccessChain() { return accessChain; } 508 void setAccessChain(AccessChain newChain) { accessChain = newChain; } 509 510 // clear accessChain 511 void clearAccessChain(); 512 513 // set new base as an l-value base 514 void setAccessChainLValue(Id lValue) 515 { 516 assert(isPointer(lValue)); 517 accessChain.base = lValue; 518 } 519 520 // set new base value as an r-value 521 void setAccessChainRValue(Id rValue) 522 { 523 accessChain.isRValue = true; 524 accessChain.base = rValue; 525 } 526 527 // push offset onto the end of the chain 528 void accessChainPush(Id offset) 529 { 530 accessChain.indexChain.push_back(offset); 531 } 532 533 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle 534 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType); 535 536 // push a variable component selection onto the access chain; supporting only one, so unsided 537 void accessChainPushComponent(Id component, Id preSwizzleBaseType) 538 { 539 accessChain.component = component; 540 if (accessChain.preSwizzleBaseType == NoType) 541 accessChain.preSwizzleBaseType = preSwizzleBaseType; 542 } 543 544 // use accessChain and swizzle to store value 545 void accessChainStore(Id rvalue); 546 547 // use accessChain and swizzle to load an r-value 548 Id accessChainLoad(Decoration precision, Id ResultType); 549 550 // get the direct pointer for an l-value 551 Id accessChainGetLValue(); 552 553 // Get the inferred SPIR-V type of the result of the current access chain, 554 // based on the type of the base and the chain of dereferences. 555 Id accessChainGetInferredType(); 556 557 // Remove OpDecorate instructions whose operands are defined in unreachable 558 // blocks. 559 void eliminateDeadDecorations(); 560 void dump(std::vector<unsigned int>&) const; 561 562 void createBranch(Block* block); 563 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock); 564 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control); 565 566 // Sets to generate opcode for specialization constants. 567 void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; } 568 // Sets to generate opcode for non-specialization constants (normal mode). 569 void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; } 570 // Check if the builder is generating code for spec constants. 571 bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; } 572 573 protected: 574 Id makeIntConstant(Id typeId, unsigned value, bool specConstant); 575 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant); 576 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const; 577 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const; 578 Id findCompositeConstant(Op typeClass, const std::vector<Id>& comps) const; 579 Id collapseAccessChain(); 580 void transferAccessChainSwizzle(bool dynamic); 581 void simplifyAccessChainSwizzle(); 582 void createAndSetNoPredecessorBlock(const char*); 583 void createSelectionMerge(Block* mergeBlock, unsigned int control); 584 void dumpSourceInstructions(std::vector<unsigned int>&) const; 585 void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const; 586 void dumpModuleProcesses(std::vector<unsigned int>&) const; 587 588 SourceLanguage source; 589 int sourceVersion; 590 spv::Id sourceFileStringId; 591 std::string sourceText; 592 int currentLine; 593 bool emitOpLines; 594 std::set<std::string> extensions; 595 std::vector<const char*> sourceExtensions; 596 std::vector<const char*> moduleProcesses; 597 AddressingModel addressModel; 598 MemoryModel memoryModel; 599 std::set<spv::Capability> capabilities; 600 int builderNumber; 601 Module module; 602 Block* buildPoint; 603 Id uniqueId; 604 Function* entryPointFunction; 605 bool generatingOpCodeForSpecConst; 606 AccessChain accessChain; 607 608 // special blocks of instructions for output 609 std::vector<std::unique_ptr<Instruction> > strings; 610 std::vector<std::unique_ptr<Instruction> > imports; 611 std::vector<std::unique_ptr<Instruction> > entryPoints; 612 std::vector<std::unique_ptr<Instruction> > executionModes; 613 std::vector<std::unique_ptr<Instruction> > names; 614 std::vector<std::unique_ptr<Instruction> > lines; 615 std::vector<std::unique_ptr<Instruction> > decorations; 616 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals; 617 std::vector<std::unique_ptr<Instruction> > externals; 618 std::vector<std::unique_ptr<Function> > functions; 619 620 // not output, internally used for quick & dirty canonical (unique) creation 621 std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant 622 std::vector<Instruction*> groupedTypes[OpConstant]; 623 624 // stack of switches 625 std::stack<Block*> switchMerges; 626 627 // Our loop stack. 628 std::stack<LoopBlocks> loops; 629 630 // The stream for outputting warnings and errors. 631 SpvBuildLogger* logger; 632 }; // end Builder class 633 634 }; // end spv namespace 635 636 #endif // SpvBuilder_H 637