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