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