• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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