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