1 // 2 // Copyright (C) 2014-2015 LunarG, Inc. 3 // Copyright (C) 2015-2020 Google, Inc. 4 // Copyright (C) 2017 ARM Limited. 5 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. 6 // 7 // All rights reserved. 8 // 9 // Redistribution and use in source and binary forms, with or without 10 // modification, are permitted provided that the following conditions 11 // are met: 12 // 13 // Redistributions of source code must retain the above copyright 14 // notice, this list of conditions and the following disclaimer. 15 // 16 // Redistributions in binary form must reproduce the above 17 // copyright notice, this list of conditions and the following 18 // disclaimer in the documentation and/or other materials provided 19 // with the distribution. 20 // 21 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 22 // contributors may be used to endorse or promote products derived 23 // from this software without specific prior written permission. 24 // 25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 35 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 // POSSIBILITY OF SUCH DAMAGE. 37 38 // 39 // "Builder" is an interface to fully build SPIR-V IR. Allocate one of 40 // these to build (a thread safe) internal SPIR-V representation (IR), 41 // and then dump it as a binary stream according to the SPIR-V specification. 42 // 43 // A Builder has a 1:1 relationship with a SPIR-V module. 44 // 45 46 #pragma once 47 #ifndef SpvBuilder_H 48 #define SpvBuilder_H 49 50 #include "Logger.h" 51 #define SPV_ENABLE_UTILITY_CODE 52 #include "spirv.hpp" 53 #include "spvIR.h" 54 namespace spv { 55 #include "GLSL.ext.KHR.h" 56 #include "NonSemanticShaderDebugInfo100.h" 57 } 58 59 #include <algorithm> 60 #include <cstdint> 61 #include <map> 62 #include <memory> 63 #include <set> 64 #include <sstream> 65 #include <stack> 66 #include <unordered_map> 67 #include <map> 68 69 namespace spv { 70 71 typedef enum { 72 Spv_1_0 = (1 << 16), 73 Spv_1_1 = (1 << 16) | (1 << 8), 74 Spv_1_2 = (1 << 16) | (2 << 8), 75 Spv_1_3 = (1 << 16) | (3 << 8), 76 Spv_1_4 = (1 << 16) | (4 << 8), 77 Spv_1_5 = (1 << 16) | (5 << 8), 78 } SpvVersion; 79 80 class Builder { 81 public: 82 Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger); 83 virtual ~Builder(); 84 85 static const int maxMatrixSize = 4; 86 getSpvVersion()87 unsigned int getSpvVersion() const { return spvVersion; } 88 setSource(spv::SourceLanguage lang,int version)89 void setSource(spv::SourceLanguage lang, int version) 90 { 91 sourceLang = lang; 92 sourceVersion = version; 93 } getStringId(const std::string & str)94 spv::Id getStringId(const std::string& str) 95 { 96 auto sItr = stringIds.find(str); 97 if (sItr != stringIds.end()) 98 return sItr->second; 99 spv::Id strId = getUniqueId(); 100 Instruction* fileString = new Instruction(strId, NoType, OpString); 101 const char* file_c_str = str.c_str(); 102 fileString->addStringOperand(file_c_str); 103 strings.push_back(std::unique_ptr<Instruction>(fileString)); 104 module.mapInstruction(fileString); 105 stringIds[file_c_str] = strId; 106 return strId; 107 } 108 getMainFileId()109 spv::Id getMainFileId() const { return mainFileId; } 110 111 // Initialize the main source file name setDebugMainSourceFile(const std::string & file)112 void setDebugMainSourceFile(const std::string& file) 113 { 114 if (trackDebugInfo) { 115 dirtyLineTracker = true; 116 mainFileId = getStringId(file); 117 currentFileId = mainFileId; 118 } 119 } 120 121 // Set the debug source location tracker in the builder. 122 // The upcoming instructions in basic blocks will be associated to this location. setDebugSourceLocation(int line,const char * filename)123 void setDebugSourceLocation(int line, const char* filename) 124 { 125 if (trackDebugInfo) { 126 dirtyLineTracker = true; 127 if (line != 0) { 128 // TODO: This is special handling of some AST nodes having (untracked) line 0. 129 // But they should have a valid line number. 130 currentLine = line; 131 if (filename) { 132 currentFileId = getStringId(filename); 133 } 134 } 135 } 136 } 137 setSourceText(const std::string & text)138 void setSourceText(const std::string& text) { sourceText = text; } addSourceExtension(const char * ext)139 void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); } addModuleProcessed(const std::string & p)140 void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); } setEmitSpirvDebugInfo()141 void setEmitSpirvDebugInfo() 142 { 143 trackDebugInfo = true; 144 emitSpirvDebugInfo = true; 145 } setEmitNonSemanticShaderDebugInfo(bool emitSourceText)146 void setEmitNonSemanticShaderDebugInfo(bool emitSourceText) 147 { 148 trackDebugInfo = true; 149 emitNonSemanticShaderDebugInfo = true; 150 importNonSemanticShaderDebugInfoInstructions(); 151 152 if (emitSourceText) { 153 emitNonSemanticShaderDebugSource = emitSourceText; 154 } 155 } addExtension(const char * ext)156 void addExtension(const char* ext) { extensions.insert(ext); } removeExtension(const char * ext)157 void removeExtension(const char* ext) 158 { 159 extensions.erase(ext); 160 } addIncorporatedExtension(const char * ext,SpvVersion incorporatedVersion)161 void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion) 162 { 163 if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion)) 164 addExtension(ext); 165 } promoteIncorporatedExtension(const char * baseExt,const char * promoExt,SpvVersion incorporatedVersion)166 void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion) 167 { 168 removeExtension(baseExt); 169 addIncorporatedExtension(promoExt, incorporatedVersion); 170 } addInclude(const std::string & name,const std::string & text)171 void addInclude(const std::string& name, const std::string& text) 172 { 173 spv::Id incId = getStringId(name); 174 includeFiles[incId] = &text; 175 } 176 Id import(const char*); setMemoryModel(spv::AddressingModel addr,spv::MemoryModel mem)177 void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem) 178 { 179 addressModel = addr; 180 memoryModel = mem; 181 } 182 addCapability(spv::Capability cap)183 void addCapability(spv::Capability cap) { capabilities.insert(cap); } 184 185 // To get a new <id> for anything needing a new one. getUniqueId()186 Id getUniqueId() { return ++uniqueId; } 187 188 // To get a set of new <id>s, e.g., for a set of function parameters getUniqueIds(int numIds)189 Id getUniqueIds(int numIds) 190 { 191 Id id = uniqueId + 1; 192 uniqueId += numIds; 193 return id; 194 } 195 196 // For creating new types (will return old type if the requested one was already made). 197 Id makeVoidType(); 198 Id makeBoolType(); 199 Id makePointer(StorageClass, Id pointee); 200 Id makeForwardPointer(StorageClass); 201 Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee); 202 Id makeIntegerType(int width, bool hasSign); // generic makeIntType(int width)203 Id makeIntType(int width) { return makeIntegerType(width, true); } makeUintType(int width)204 Id makeUintType(int width) { return makeIntegerType(width, false); } 205 Id makeFloatType(int width); 206 Id makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated = true); 207 Id makeStructResultType(Id type0, Id type1); 208 Id makeVectorType(Id component, int size); 209 Id makeMatrixType(Id component, int cols, int rows); 210 Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration 211 Id makeRuntimeArray(Id element); 212 Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes); 213 Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format); 214 Id makeSamplerType(); 215 Id makeSampledImageType(Id imageType); 216 Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use); 217 Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols); 218 Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType); 219 Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands); 220 221 // SPIR-V NonSemantic Shader DebugInfo Instructions 222 struct DebugTypeLoc { 223 std::string name {}; 224 int line {0}; 225 int column {0}; 226 }; 227 std::unordered_map<Id, DebugTypeLoc> debugTypeLocs; 228 Id makeDebugInfoNone(); 229 Id makeBoolDebugType(int const size); 230 Id makeIntegerDebugType(int const width, bool const hasSign); 231 Id makeFloatDebugType(int const width); 232 Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType); 233 Id makeArrayDebugType(Id const baseType, Id const componentCount); 234 Id makeVectorDebugType(Id const baseType, int const componentCount); 235 Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true); 236 Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc); 237 Id makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name, 238 NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false); 239 Id makePointerDebugType(StorageClass storageClass, Id const baseType); 240 Id makeForwardPointerDebugType(StorageClass storageClass); 241 Id makeDebugSource(const Id fileName); 242 Id makeDebugCompilationUnit(); 243 Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable); 244 Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0); 245 Id makeDebugExpression(); 246 Id makeDebugDeclare(Id const debugLocalVariable, Id const pointer); 247 Id makeDebugValue(Id const debugLocalVariable, Id const value); 248 Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes); 249 Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId); 250 Id makeDebugLexicalBlock(uint32_t line, uint32_t column); 251 std::string unmangleFunctionName(std::string const& name) const; 252 253 // Initialize non-semantic debug information for a function, including those of: 254 // - The function definition 255 // - The function parameters 256 void setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes, 257 const std::vector<char const*>& paramNames); 258 259 // accelerationStructureNV type 260 Id makeAccelerationStructureType(); 261 // rayQueryEXT type 262 Id makeRayQueryType(); 263 // hitObjectNV type 264 Id makeHitObjectNVType(); 265 266 // For querying about types. getTypeId(Id resultId)267 Id getTypeId(Id resultId) const { return module.getTypeId(resultId); } 268 Id getDerefTypeId(Id resultId) const; getOpCode(Id id)269 Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); } getTypeClass(Id typeId)270 Op getTypeClass(Id typeId) const { return getOpCode(typeId); } 271 Op getMostBasicTypeClass(Id typeId) const; getNumComponents(Id resultId)272 unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); } 273 unsigned int getNumTypeConstituents(Id typeId) const; getNumTypeComponents(Id typeId)274 unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); } 275 Id getScalarTypeId(Id typeId) const; 276 Id getContainedTypeId(Id typeId) const; 277 Id getContainedTypeId(Id typeId, int) const; getTypeStorageClass(Id typeId)278 StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); } getImageTypeFormat(Id typeId)279 ImageFormat getImageTypeFormat(Id typeId) const 280 { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } 281 Id getResultingAccessChainType() const; getIdOperand(Id resultId,int idx)282 Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); } 283 isPointer(Id resultId)284 bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); } isScalar(Id resultId)285 bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); } isVector(Id resultId)286 bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); } isMatrix(Id resultId)287 bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); } isCooperativeMatrix(Id resultId)288 bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); } isAggregate(Id resultId)289 bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); } isSampledImage(Id resultId)290 bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); } isTensorView(Id resultId)291 bool isTensorView(Id resultId)const { return isTensorViewType(getTypeId(resultId)); } 292 isBoolType(Id typeId)293 bool isBoolType(Id typeId) 294 { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } isIntType(Id typeId)295 bool isIntType(Id typeId) const 296 { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; } isUintType(Id typeId)297 bool isUintType(Id typeId) const 298 { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; } isFloatType(Id typeId)299 bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; } isPointerType(Id typeId)300 bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; } isScalarType(Id typeId)301 bool isScalarType(Id typeId) const 302 { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || 303 getTypeClass(typeId) == OpTypeBool; } isVectorType(Id typeId)304 bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; } isMatrixType(Id typeId)305 bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; } isStructType(Id typeId)306 bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; } isArrayType(Id typeId)307 bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; } isCooperativeMatrixType(Id typeId)308 bool isCooperativeMatrixType(Id typeId)const 309 { 310 return getTypeClass(typeId) == OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == OpTypeCooperativeMatrixNV; 311 } isTensorViewType(Id typeId)312 bool isTensorViewType(Id typeId) const { return getTypeClass(typeId) == OpTypeTensorViewNV; } isAggregateType(Id typeId)313 bool isAggregateType(Id typeId) const 314 { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); } isImageType(Id typeId)315 bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; } isSamplerType(Id typeId)316 bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; } isSampledImageType(Id typeId)317 bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; } 318 bool containsType(Id typeId, Op typeOp, unsigned int width) const; 319 bool containsPhysicalStorageBufferOrArray(Id typeId) const; 320 321 bool isConstantOpCode(Op opcode) const; 322 bool isSpecConstantOpCode(Op opcode) const; isConstant(Id resultId)323 bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); } isConstantScalar(Id resultId)324 bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; } isSpecConstant(Id resultId)325 bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); } getConstantScalar(Id resultId)326 unsigned int getConstantScalar(Id resultId) const 327 { return module.getInstruction(resultId)->getImmediateOperand(0); } getStorageClass(Id resultId)328 StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); } 329 isVariableOpCode(Op opcode)330 bool isVariableOpCode(Op opcode) const { return opcode == OpVariable; } isVariable(Id resultId)331 bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); } isGlobalStorage(Id resultId)332 bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClassFunction; } isGlobalVariable(Id resultId)333 bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); } 334 // See if a resultId is valid for use as an initializer. isValidInitializer(Id resultId)335 bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); } 336 getScalarTypeWidth(Id typeId)337 int getScalarTypeWidth(Id typeId) const 338 { 339 Id scalarTypeId = getScalarTypeId(typeId); 340 assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat); 341 return module.getInstruction(scalarTypeId)->getImmediateOperand(0); 342 } 343 getTypeNumColumns(Id typeId)344 unsigned int getTypeNumColumns(Id typeId) const 345 { 346 assert(isMatrixType(typeId)); 347 return getNumTypeConstituents(typeId); 348 } getNumColumns(Id resultId)349 unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); } getTypeNumRows(Id typeId)350 unsigned int getTypeNumRows(Id typeId) const 351 { 352 assert(isMatrixType(typeId)); 353 return getNumTypeComponents(getContainedTypeId(typeId)); 354 } getNumRows(Id resultId)355 unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); } 356 getTypeDimensionality(Id typeId)357 Dim getTypeDimensionality(Id typeId) const 358 { 359 assert(isImageType(typeId)); 360 return (Dim)module.getInstruction(typeId)->getImmediateOperand(1); 361 } getImageType(Id resultId)362 Id getImageType(Id resultId) const 363 { 364 Id typeId = getTypeId(resultId); 365 assert(isImageType(typeId) || isSampledImageType(typeId)); 366 return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId; 367 } isArrayedImageType(Id typeId)368 bool isArrayedImageType(Id typeId) const 369 { 370 assert(isImageType(typeId)); 371 return module.getInstruction(typeId)->getImmediateOperand(3) != 0; 372 } 373 374 // For making new constants (will return old constant if the requested one was already made). 375 Id makeNullConstant(Id typeId); 376 Id makeBoolConstant(bool b, bool specConstant = false); 377 Id makeIntConstant(Id typeId, unsigned value, bool specConstant); 378 Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant); 379 Id makeInt8Constant(int i, bool specConstant = false) 380 { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); } 381 Id makeUint8Constant(unsigned u, bool specConstant = false) 382 { return makeIntConstant(makeUintType(8), u, specConstant); } 383 Id makeInt16Constant(int i, bool specConstant = false) 384 { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); } 385 Id makeUint16Constant(unsigned u, bool specConstant = false) 386 { return makeIntConstant(makeUintType(16), u, specConstant); } 387 Id makeIntConstant(int i, bool specConstant = false) 388 { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); } 389 Id makeUintConstant(unsigned u, bool specConstant = false) 390 { return makeIntConstant(makeUintType(32), u, specConstant); } 391 Id makeInt64Constant(long long i, bool specConstant = false) 392 { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); } 393 Id makeUint64Constant(unsigned long long u, bool specConstant = false) 394 { return makeInt64Constant(makeUintType(64), u, specConstant); } 395 Id makeFloatConstant(float f, bool specConstant = false); 396 Id makeDoubleConstant(double d, bool specConstant = false); 397 Id makeFloat16Constant(float f16, bool specConstant = false); 398 Id makeFpConstant(Id type, double d, bool specConstant = false); 399 400 Id importNonSemanticShaderDebugInfoInstructions(); 401 402 // Turn the array of constants into a proper spv constant of the requested type. 403 Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false); 404 405 // Methods for adding information outside the CFG. 406 Instruction* addEntryPoint(ExecutionModel, Function*, const char* name); 407 void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1); 408 void addExecutionMode(Function*, ExecutionMode mode, const std::vector<unsigned>& literals); 409 void addExecutionModeId(Function*, ExecutionMode mode, const std::vector<Id>& operandIds); 410 void addName(Id, const char* name); 411 void addMemberName(Id, int member, const char* name); 412 void addDecoration(Id, Decoration, int num = -1); 413 void addDecoration(Id, Decoration, const char*); 414 void addDecoration(Id, Decoration, const std::vector<unsigned>& literals); 415 void addDecoration(Id, Decoration, const std::vector<const char*>& strings); 416 void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType); 417 void addDecorationId(Id id, Decoration, Id idDecoration); 418 void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds); 419 void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1); 420 void addMemberDecoration(Id, unsigned int member, Decoration, const char*); 421 void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<unsigned>& literals); 422 void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings); 423 424 // At the end of what block do the next create*() instructions go? 425 // Also reset current last DebugScope and current source line to unknown setBuildPoint(Block * bp)426 void setBuildPoint(Block* bp) { 427 buildPoint = bp; 428 dirtyLineTracker = true; 429 dirtyScopeTracker = true; 430 } getBuildPoint()431 Block* getBuildPoint() const { return buildPoint; } 432 433 // Append an instruction to the end of the current build point. 434 // Optionally, additional debug info instructions may also be prepended. 435 void addInstruction(std::unique_ptr<Instruction> inst); 436 437 // Append an instruction to the end of the current build point without prepending any debug instructions. 438 // This is useful for insertion of some debug info instructions themselves or some control flow instructions 439 // that are attached to its predecessor instruction. 440 void addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst); 441 442 // Make the entry-point function. The returned pointer is only valid 443 // for the lifetime of this builder. 444 Function* makeEntryPoint(const char*); 445 446 // Make a shader-style function, and create its entry block if entry is non-zero. 447 // Return the function, pass back the entry. 448 // The returned pointer is only valid for the lifetime of this builder. 449 Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType, 450 const std::vector<Id>& paramTypes, 451 const std::vector<std::vector<Decoration>>& precisions, Block** entry = nullptr); 452 453 // Create a return. An 'implicit' return is one not appearing in the source 454 // code. In the case of an implicit return, no post-return block is inserted. 455 void makeReturn(bool implicit, Id retVal = 0); 456 457 // Initialize state and generate instructions for new lexical scope 458 void enterLexicalBlock(uint32_t line, uint32_t column); 459 460 // Set state and generate instructions to exit current lexical scope 461 void leaveLexicalBlock(); 462 463 // Prepare builder for generation of instructions for a function. 464 void enterFunction(Function const* function); 465 466 // Generate all the code needed to finish up a function. 467 void leaveFunction(); 468 469 // Create block terminator instruction for certain statements like 470 // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT 471 void makeStatementTerminator(spv::Op opcode, const char *name); 472 473 // Create block terminator instruction for statements that have input operands 474 // such as OpEmitMeshTasksEXT 475 void makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name); 476 477 // Create a global or function local or IO variable. 478 Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr, 479 Id initializer = NoResult, bool const compilerGenerated = true); 480 481 // Create an intermediate with an undefined value. 482 Id createUndefined(Id type); 483 484 // Store into an Id and return the l-value 485 void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, 486 spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); 487 488 // Load from an Id and return it 489 Id createLoad(Id lValue, spv::Decoration precision, 490 spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, 491 spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); 492 493 // Create an OpAccessChain instruction 494 Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets); 495 496 // Create an OpArrayLength instruction 497 Id createArrayLength(Id base, unsigned int member); 498 499 // Create an OpCooperativeMatrixLengthKHR instruction 500 Id createCooperativeMatrixLengthKHR(Id type); 501 // Create an OpCooperativeMatrixLengthNV instruction 502 Id createCooperativeMatrixLengthNV(Id type); 503 504 // Create an OpCompositeExtract instruction 505 Id createCompositeExtract(Id composite, Id typeId, unsigned index); 506 Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes); 507 Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index); 508 Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes); 509 510 Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex); 511 Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex); 512 513 void createNoResultOp(Op); 514 void createNoResultOp(Op, Id operand); 515 void createNoResultOp(Op, const std::vector<Id>& operands); 516 void createNoResultOp(Op, const std::vector<IdImmediate>& operands); 517 void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask); 518 void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics); 519 Id createUnaryOp(Op, Id typeId, Id operand); 520 Id createBinOp(Op, Id typeId, Id operand1, Id operand2); 521 Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3); 522 Id createOp(Op, Id typeId, const std::vector<Id>& operands); 523 Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands); 524 Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&); 525 Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals); 526 527 // Take an rvalue (source) and a set of channels to extract from it to 528 // make a new rvalue, which is returned. 529 Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels); 530 531 // Take a copy of an lvalue (target) and a source of components, and set the 532 // source components into the lvalue where the 'channels' say to put them. 533 // An updated version of the target is returned. 534 // (No true lvalue or stores are used.) 535 Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels); 536 537 // If both the id and precision are valid, the id 538 // gets tagged with the requested precision. 539 // The passed in id is always the returned id, to simplify use patterns. setPrecision(Id id,Decoration precision)540 Id setPrecision(Id id, Decoration precision) 541 { 542 if (precision != NoPrecision && id != NoResult) 543 addDecoration(id, precision); 544 545 return id; 546 } 547 548 // Can smear a scalar to a vector for the following forms: 549 // - promoteScalar(scalar, vector) // smear scalar to width of vector 550 // - promoteScalar(vector, scalar) // smear scalar to width of vector 551 // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to 552 // - promoteScalar(scalar, scalar) // do nothing 553 // Other forms are not allowed. 554 // 555 // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'. 556 // The type of the created vector is a vector of components of the same type as the scalar. 557 // 558 // Note: One of the arguments will change, with the result coming back that way rather than 559 // through the return value. 560 void promoteScalar(Decoration precision, Id& left, Id& right); 561 562 // Make a value by smearing the scalar to fill the type. 563 // vectorType should be the correct type for making a vector of scalarVal. 564 // (No conversions are done.) 565 Id smearScalar(Decoration precision, Id scalarVal, Id vectorType); 566 567 // Create a call to a built-in function. 568 Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args); 569 570 // List of parameters used to create a texture operation 571 struct TextureParameters { 572 Id sampler; 573 Id coords; 574 Id bias; 575 Id lod; 576 Id Dref; 577 Id offset; 578 Id offsets; 579 Id gradX; 580 Id gradY; 581 Id sample; 582 Id component; 583 Id texelOut; 584 Id lodClamp; 585 Id granularity; 586 Id coarse; 587 bool nonprivate; 588 bool volatil; 589 }; 590 591 // Select the correct texture operation based on all inputs, and emit the correct instruction 592 Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, 593 bool noImplicit, const TextureParameters&, ImageOperandsMask); 594 595 // Emit the OpTextureQuery* instruction that was passed in. 596 // Figure out the right return value and type, and return it. 597 Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult); 598 599 Id createSamplePositionCall(Decoration precision, Id, Id); 600 601 Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned); 602 Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id); 603 604 // Reduction comparison for composites: For equal and not-equal resulting in a scalar. 605 Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */); 606 607 // OpCompositeConstruct 608 Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents); 609 610 // vector or scalar constructor 611 Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId); 612 613 // matrix constructor 614 Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee); 615 616 // coopmat conversion 617 Id createCooperativeMatrixConversion(Id typeId, Id source); 618 Id createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func); 619 Id createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands); 620 621 // Helper to use for building nested control flow with if-then-else. 622 class If { 623 public: 624 If(Id condition, unsigned int ctrl, Builder& builder); ~If()625 ~If() {} 626 627 void makeBeginElse(); 628 void makeEndIf(); 629 630 private: 631 If(const If&); 632 If& operator=(If&); 633 634 Builder& builder; 635 Id condition; 636 unsigned int control; 637 Function* function; 638 Block* headerBlock; 639 Block* thenBlock; 640 Block* elseBlock; 641 Block* mergeBlock; 642 }; 643 644 // Make a switch statement. A switch has 'numSegments' of pieces of code, not containing 645 // any case/default labels, all separated by one or more case/default labels. Each possible 646 // case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this 647 // number space. How to compute the value is given by 'condition', as in switch(condition). 648 // 649 // The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches. 650 // 651 // Use a defaultSegment < 0 if there is no default segment (to branch to post switch). 652 // 653 // Returns the right set of basic blocks to start each code segment with, so that the caller's 654 // recursion stack can hold the memory for it. 655 // 656 void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues, 657 const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); 658 659 // Add a branch to the innermost switch's merge block. 660 void addSwitchBreak(bool implicit); 661 662 // Move to the next code segment, passing in the return argument in makeSwitch() 663 void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment); 664 665 // Finish off the innermost switch. 666 void endSwitch(std::vector<Block*>& segmentBB); 667 668 struct LoopBlocks { LoopBlocksLoopBlocks669 LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) : 670 head(head), body(body), merge(merge), continue_target(continue_target) { } 671 Block &head, &body, &merge, &continue_target; 672 private: 673 LoopBlocks(); 674 LoopBlocks& operator=(const LoopBlocks&) = delete; 675 }; 676 677 // Start a new loop and prepare the builder to generate code for it. Until 678 // closeLoop() is called for this loop, createLoopContinue() and 679 // createLoopExit() will target its corresponding blocks. 680 LoopBlocks& makeNewLoop(); 681 682 // Create a new block in the function containing the build point. Memory is 683 // owned by the function object. 684 Block& makeNewBlock(); 685 686 // Add a branch to the continue_target of the current (innermost) loop. 687 void createLoopContinue(); 688 689 // Add an exit (e.g. "break") from the innermost loop that we're currently 690 // in. 691 void createLoopExit(); 692 693 // Close the innermost loop that you're in 694 void closeLoop(); 695 696 // 697 // Access chain design for an R-Value vs. L-Value: 698 // 699 // There is a single access chain the builder is building at 700 // any particular time. Such a chain can be used to either to a load or 701 // a store, when desired. 702 // 703 // Expressions can be r-values, l-values, or both, or only r-values: 704 // a[b.c].d = .... // l-value 705 // ... = a[b.c].d; // r-value, that also looks like an l-value 706 // ++a[b.c].d; // r-value and l-value 707 // (x + y)[2]; // r-value only, can't possibly be l-value 708 // 709 // Computing an r-value means generating code. Hence, 710 // r-values should only be computed when they are needed, not speculatively. 711 // 712 // Computing an l-value means saving away information for later use in the compiler, 713 // no code is generated until the l-value is later dereferenced. It is okay 714 // to speculatively generate an l-value, just not okay to speculatively dereference it. 715 // 716 // The base of the access chain (the left-most variable or expression 717 // from which everything is based) can be set either as an l-value 718 // or as an r-value. Most efficient would be to set an l-value if one 719 // is available. If an expression was evaluated, the resulting r-value 720 // can be set as the chain base. 721 // 722 // The users of this single access chain can save and restore if they 723 // want to nest or manage multiple chains. 724 // 725 726 struct AccessChain { 727 Id base; // for l-values, pointer to the base object, for r-values, the base object 728 std::vector<Id> indexChain; 729 Id instr; // cache the instruction that generates this access chain 730 std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number 731 Id component; // a dynamic component index, can coexist with a swizzle, 732 // done after the swizzle, NoResult if not present 733 Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; 734 // NoType unless a swizzle or component is present 735 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value 736 unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment. 737 // Only tracks base and (optional) component selection alignment. 738 739 // Accumulate whether anything in the chain of structures has coherent decorations. 740 struct CoherentFlags { CoherentFlagsAccessChain::CoherentFlags741 CoherentFlags() { clear(); } isVolatileAccessChain::CoherentFlags742 bool isVolatile() const { return volatil; } isNonUniformAccessChain::CoherentFlags743 bool isNonUniform() const { return nonUniform; } anyCoherentAccessChain::CoherentFlags744 bool anyCoherent() const { 745 return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent || 746 subgroupcoherent || shadercallcoherent; 747 } 748 749 unsigned coherent : 1; 750 unsigned devicecoherent : 1; 751 unsigned queuefamilycoherent : 1; 752 unsigned workgroupcoherent : 1; 753 unsigned subgroupcoherent : 1; 754 unsigned shadercallcoherent : 1; 755 unsigned nonprivate : 1; 756 unsigned volatil : 1; 757 unsigned isImage : 1; 758 unsigned nonUniform : 1; 759 clearAccessChain::CoherentFlags760 void clear() { 761 coherent = 0; 762 devicecoherent = 0; 763 queuefamilycoherent = 0; 764 workgroupcoherent = 0; 765 subgroupcoherent = 0; 766 shadercallcoherent = 0; 767 nonprivate = 0; 768 volatil = 0; 769 isImage = 0; 770 nonUniform = 0; 771 } 772 773 CoherentFlags operator |=(const CoherentFlags &other) { 774 coherent |= other.coherent; 775 devicecoherent |= other.devicecoherent; 776 queuefamilycoherent |= other.queuefamilycoherent; 777 workgroupcoherent |= other.workgroupcoherent; 778 subgroupcoherent |= other.subgroupcoherent; 779 shadercallcoherent |= other.shadercallcoherent; 780 nonprivate |= other.nonprivate; 781 volatil |= other.volatil; 782 isImage |= other.isImage; 783 nonUniform |= other.nonUniform; 784 return *this; 785 } 786 }; 787 CoherentFlags coherentFlags; 788 }; 789 790 // 791 // the SPIR-V builder maintains a single active chain that 792 // the following methods operate on 793 // 794 795 // for external save and restore getAccessChain()796 AccessChain getAccessChain() { return accessChain; } setAccessChain(AccessChain newChain)797 void setAccessChain(AccessChain newChain) { accessChain = newChain; } 798 799 // clear accessChain 800 void clearAccessChain(); 801 802 // set new base as an l-value base setAccessChainLValue(Id lValue)803 void setAccessChainLValue(Id lValue) 804 { 805 assert(isPointer(lValue)); 806 accessChain.base = lValue; 807 } 808 809 // set new base value as an r-value setAccessChainRValue(Id rValue)810 void setAccessChainRValue(Id rValue) 811 { 812 accessChain.isRValue = true; 813 accessChain.base = rValue; 814 } 815 816 // push offset onto the end of the chain accessChainPush(Id offset,AccessChain::CoherentFlags coherentFlags,unsigned int alignment)817 void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment) 818 { 819 accessChain.indexChain.push_back(offset); 820 accessChain.coherentFlags |= coherentFlags; 821 accessChain.alignment |= alignment; 822 } 823 824 // push new swizzle onto the end of any existing swizzle, merging into a single swizzle 825 void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, 826 AccessChain::CoherentFlags coherentFlags, unsigned int alignment); 827 828 // push a dynamic component selection onto the access chain, only applicable with a 829 // non-trivial swizzle or no swizzle accessChainPushComponent(Id component,Id preSwizzleBaseType,AccessChain::CoherentFlags coherentFlags,unsigned int alignment)830 void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, 831 unsigned int alignment) 832 { 833 if (accessChain.swizzle.size() != 1) { 834 accessChain.component = component; 835 if (accessChain.preSwizzleBaseType == NoType) 836 accessChain.preSwizzleBaseType = preSwizzleBaseType; 837 } 838 accessChain.coherentFlags |= coherentFlags; 839 accessChain.alignment |= alignment; 840 } 841 842 // use accessChain and swizzle to store value 843 void accessChainStore(Id rvalue, Decoration nonUniform, 844 spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, 845 spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); 846 847 // use accessChain and swizzle to load an r-value 848 Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType, 849 spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, 850 unsigned int alignment = 0); 851 852 // Return whether or not the access chain can be represented in SPIR-V 853 // as an l-value. 854 // E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be. isSpvLvalue()855 bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; } 856 857 // get the direct pointer for an l-value 858 Id accessChainGetLValue(); 859 860 // Get the inferred SPIR-V type of the result of the current access chain, 861 // based on the type of the base and the chain of dereferences. 862 Id accessChainGetInferredType(); 863 864 // Add capabilities, extensions, remove unneeded decorations, etc., 865 // based on the resulting SPIR-V. 866 void postProcess(bool compileOnly); 867 868 // Prune unreachable blocks in the CFG and remove unneeded decorations. 869 void postProcessCFG(); 870 871 // Add capabilities, extensions based on instructions in the module. 872 void postProcessFeatures(); 873 // Hook to visit each instruction in a block in a function 874 void postProcess(Instruction&); 875 // Hook to visit each non-32-bit sized float/int operation in a block. 876 void postProcessType(const Instruction&, spv::Id typeId); 877 // move OpSampledImage instructions to be next to their users. 878 void postProcessSamplers(); 879 880 void dump(std::vector<unsigned int>&) const; 881 882 // Add a branch to the target block. 883 // If set implicit, the branch instruction shouldn't have debug source location. 884 void createBranch(bool implicit, Block* block); 885 void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock); 886 void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, 887 const std::vector<unsigned int>& operands); 888 889 // Sets to generate opcode for specialization constants. setToSpecConstCodeGenMode()890 void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; } 891 // Sets to generate opcode for non-specialization constants (normal mode). setToNormalCodeGenMode()892 void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; } 893 // Check if the builder is generating code for spec constants. isInSpecConstCodeGenMode()894 bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; } 895 setUseReplicatedComposites(bool use)896 void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; } 897 898 protected: 899 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value); 900 Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2); 901 Id findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps); 902 Id findStructConstant(Id typeId, const std::vector<Id>& comps); 903 Id collapseAccessChain(); 904 void remapDynamicSwizzle(); 905 void transferAccessChainSwizzle(bool dynamic); 906 void simplifyAccessChainSwizzle(); 907 void createAndSetNoPredecessorBlock(const char*); 908 void createSelectionMerge(Block* mergeBlock, unsigned int control); 909 void dumpSourceInstructions(std::vector<unsigned int>&) const; 910 void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const; 911 template <class Range> void dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const; 912 void dumpModuleProcesses(std::vector<unsigned int>&) const; 913 spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) 914 const; 915 struct DecorationInstructionLessThan { 916 bool operator()(const std::unique_ptr<Instruction>& lhs, const std::unique_ptr<Instruction>& rhs) const; 917 }; 918 919 unsigned int spvVersion; // the version of SPIR-V to emit in the header 920 SourceLanguage sourceLang; 921 int sourceVersion; 922 spv::Id nonSemanticShaderCompilationUnitId {0}; 923 spv::Id nonSemanticShaderDebugInfo {0}; 924 spv::Id debugInfoNone {0}; 925 spv::Id debugExpression {0}; // Debug expression with zero operations. 926 std::string sourceText; 927 928 // True if an new OpLine/OpDebugLine may need to be inserted. Either: 929 // 1. The current debug location changed 930 // 2. The current build point changed 931 bool dirtyLineTracker; 932 int currentLine = 0; 933 // OpString id of the current file name. Always 0 if debug info is off. 934 spv::Id currentFileId = 0; 935 // OpString id of the main file name. Always 0 if debug info is off. 936 spv::Id mainFileId = 0; 937 938 // True if an new OpDebugScope may need to be inserted. Either: 939 // 1. A new lexical block is pushed 940 // 2. The current build point changed 941 bool dirtyScopeTracker; 942 std::stack<spv::Id> currentDebugScopeId; 943 944 // This flag toggles tracking of debug info while building the SPIR-V. 945 bool trackDebugInfo = false; 946 // This flag toggles emission of SPIR-V debug instructions, like OpLine and OpSource. 947 bool emitSpirvDebugInfo = false; 948 // This flag toggles emission of Non-Semantic Debug extension debug instructions. 949 bool emitNonSemanticShaderDebugInfo = false; 950 bool restoreNonSemanticShaderDebugInfo = false; 951 bool emitNonSemanticShaderDebugSource = false; 952 953 std::set<std::string> extensions; 954 std::vector<const char*> sourceExtensions; 955 std::vector<const char*> moduleProcesses; 956 AddressingModel addressModel; 957 MemoryModel memoryModel; 958 std::set<spv::Capability> capabilities; 959 int builderNumber; 960 Module module; 961 Block* buildPoint; 962 Id uniqueId; 963 Function* entryPointFunction; 964 bool generatingOpCodeForSpecConst; 965 bool useReplicatedComposites { false }; 966 AccessChain accessChain; 967 968 // special blocks of instructions for output 969 std::vector<std::unique_ptr<Instruction> > strings; 970 std::vector<std::unique_ptr<Instruction> > imports; 971 std::vector<std::unique_ptr<Instruction> > entryPoints; 972 std::vector<std::unique_ptr<Instruction> > executionModes; 973 std::vector<std::unique_ptr<Instruction> > names; 974 std::set<std::unique_ptr<Instruction>, DecorationInstructionLessThan> decorations; 975 std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals; 976 std::vector<std::unique_ptr<Instruction> > externals; 977 std::vector<std::unique_ptr<Function> > functions; 978 979 // not output, internally used for quick & dirty canonical (unique) creation 980 981 // map type opcodes to constant inst. 982 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants; 983 // map struct-id to constant instructions 984 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants; 985 // map type opcodes to type instructions 986 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes; 987 // map type opcodes to debug type instructions 988 std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes; 989 // list of OpConstantNull instructions 990 std::vector<Instruction*> nullConstants; 991 992 // stack of switches 993 std::stack<Block*> switchMerges; 994 995 // Our loop stack. 996 std::stack<LoopBlocks> loops; 997 998 // map from strings to their string ids 999 std::unordered_map<std::string, spv::Id> stringIds; 1000 1001 // map from include file name ids to their contents 1002 std::map<spv::Id, const std::string*> includeFiles; 1003 1004 // map from core id to debug id 1005 std::map <spv::Id, spv::Id> debugId; 1006 1007 // map from file name string id to DebugSource id 1008 std::unordered_map<spv::Id, spv::Id> debugSourceId; 1009 1010 // The stream for outputting warnings and errors. 1011 SpvBuildLogger* logger; 1012 }; // end Builder class 1013 1014 } // end spv namespace 1015 1016 #endif // SpvBuilder_H 1017