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