• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // BuildSPIRV: Helper for OutputSPIRV to build SPIR-V.
7 //
8 
9 #ifndef COMPILER_TRANSLATOR_BUILDSPIRV_H_
10 #define COMPILER_TRANSLATOR_BUILDSPIRV_H_
11 
12 #include "common/FixedVector.h"
13 #include "common/hash_utils.h"
14 #include "common/spirv/spirv_instruction_builder_autogen.h"
15 #include "compiler/translator/Compiler.h"
16 
17 namespace spirv = angle::spirv;
18 
19 namespace sh
20 {
21 // Helper classes to map types to ids
22 
23 // The same GLSL type may map to multiple SPIR-V types when said GLSL type is used differently in
24 // the shader source, for example used with |invariant| and without, used in an interface block etc.
25 // This type contains the pieces of information that differentiate SPIR-V types derived from the
26 // same GLSL type.  This is referred to as "SPIR-V type specialization" henceforth.
27 struct SpirvType;
28 class SpirvTypeSpec
29 {
30   public:
31     // Some of the properties that specialize SPIR-V types apply to structs or arrays, but not to
32     // their fields or basic types.  When extracting fields, array elements, columns or basic types
33     // from a type, the following helpers are used to remove any ineffective (and thus incorrect)
34     // specialization.
35     void inferDefaults(const TType &type, TCompiler *compiler);
36     void onArrayElementSelection(bool isElementTypeBlock, bool isElementTypeArray);
37     void onBlockFieldSelection(const TType &fieldType);
38     void onMatrixColumnSelection();
39     void onVectorComponentSelection();
40 
41     // If a structure is used in two interface blocks with different layouts, it would have
42     // to generate two SPIR-V types, as its fields' Offset decorations could be different.
43     // For non-block types, when used in an interface block as an array, they could generate
44     // different ArrayStride decorations.  As such, the block storage is part of the SPIR-V type
45     // except for non-block non-array types.
46     TLayoutBlockStorage blockStorage = EbsUnspecified;
47 
48     // If a structure is used in two I/O blocks or output varyings with and without the invariant
49     // qualifier, it would also have to generate two SPIR-V types, as its fields' Invariant
50     // decorations would be different.
51     bool isInvariantBlock = false;
52 
53     // Similarly, a structure containing matrices may be used both with the column_major and
54     // row_major layout qualifier, generating two SPIR-V types with different decorations on its
55     // fields.
56     bool isRowMajorQualifiedBlock = false;
57 
58     // Arrays when used in an interface block produce a different type which is decorated with an
59     // ArrayStride.  Row-major qualified arrays of matrices can potentially produce a different
60     // stride from column-major ones.
61     bool isRowMajorQualifiedArray = false;
62 
63     // Bool is disallowed in interface blocks in SPIR-V.  This type is emulated with uint.  This
64     // property applies to both blocks with bools in them and the bool type inside the block itself.
65     bool isOrHasBoolInInterfaceBlock = false;
66 };
67 
68 struct SpirvType
69 {
70     // If struct or interface block, the type is identified by the pointer.  Note that both
71     // TStructure and TInterfaceBlock inherit from TFieldListCollection, and their difference is
72     // irrelevant as far as SPIR-V type is concerned.
73     const TFieldListCollection *block = nullptr;
74 
75     // Otherwise, it's a basic type + column, row and array dimensions, or it's an image
76     // declaration.
77     //
78     // Notes:
79     //
80     // - `precision` turns into a RelaxedPrecision decoration on the variable and instructions.
81     // - `precise` turns into a NoContraction decoration on the instructions.
82     // - `readonly`, `writeonly`, `coherent`, `volatile` and `restrict` only apply to memory object
83     //    declarations
84     // - `invariant` only applies to variable or members of a block
85     // - `matrixPacking` only applies to members of a struct
86     TBasicType type = EbtFloat;
87 
88     uint8_t primarySize   = 1;
89     uint8_t secondarySize = 1;
90 
91     TSpan<const unsigned int> arraySizes;
92 
93     // Only useful for image types.
94     TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified;
95 
96     // For sampled images (i.e. GLSL samplers), there are two type ids; one is the OpTypeImage that
97     // declares the image itself, and one OpTypeSampledImage.  `isSamplerBaseImage` distinguishes
98     // between these two types.  Note that for the former, the basic type is still Ebt*Sampler* to
99     // distinguish it from storage images (which have a basic type of Ebt*Image*).
100     bool isSamplerBaseImage = false;
101 
102     // Anything that can cause the same GLSL type to produce different SPIR-V types.
103     SpirvTypeSpec typeSpec;
104 };
105 
106 struct SpirvIdAndIdList
107 {
108     spirv::IdRef id;
109     spirv::IdRefList idList;
110 
111     bool operator==(const SpirvIdAndIdList &other) const
112     {
113         return id == other.id && idList == other.idList;
114     }
115 };
116 
117 struct SpirvIdAndStorageClass
118 {
119     spirv::IdRef id;
120     spv::StorageClass storageClass;
121 
122     bool operator==(const SpirvIdAndStorageClass &other) const
123     {
124         return id == other.id && storageClass == other.storageClass;
125     }
126 };
127 
128 struct SpirvTypeHash
129 {
operatorSpirvTypeHash130     size_t operator()(const sh::SpirvType &type) const
131     {
132         // Block storage must only affect the type if it's a block type or array type (in a block).
133         ASSERT(type.typeSpec.blockStorage == sh::EbsUnspecified || type.block != nullptr ||
134                !type.arraySizes.empty());
135 
136         // Invariant must only affect the type if it's a block type.
137         ASSERT(!type.typeSpec.isInvariantBlock || type.block != nullptr);
138 
139         // Row-major block must only affect the type if it's a block type.
140         ASSERT(!type.typeSpec.isRowMajorQualifiedBlock || type.block != nullptr);
141 
142         // Row-major array must only affect the type if it's an array of non-square matrices in
143         // an std140 or std430 block.
144         ASSERT(!type.typeSpec.isRowMajorQualifiedArray ||
145                (type.block == nullptr && !type.arraySizes.empty() && type.secondarySize > 1 &&
146                 type.primarySize != type.secondarySize &&
147                 type.typeSpec.blockStorage != sh::EbsUnspecified));
148 
149         size_t result = 0;
150 
151         if (!type.arraySizes.empty())
152         {
153             result = angle::ComputeGenericHash(type.arraySizes.data(),
154                                                type.arraySizes.size() * sizeof(type.arraySizes[0]));
155         }
156 
157         if (type.block != nullptr)
158         {
159             return result ^ angle::ComputeGenericHash(&type.block, sizeof(type.block)) ^
160                    static_cast<size_t>(type.typeSpec.isInvariantBlock) ^
161                    (static_cast<size_t>(type.typeSpec.isRowMajorQualifiedBlock) << 1) ^
162                    (static_cast<size_t>(type.typeSpec.isRowMajorQualifiedArray) << 2) ^
163                    (type.typeSpec.blockStorage << 3);
164         }
165 
166         static_assert(sh::EbtLast < 256, "Basic type doesn't fit in uint8_t");
167         static_assert(sh::EbsLast < 8, "Block storage doesn't fit in 3 bits");
168         static_assert(sh::EiifLast < 32, "Image format doesn't fit in 5 bits");
169         ASSERT(type.primarySize > 0 && type.primarySize <= 4);
170         ASSERT(type.secondarySize > 0 && type.secondarySize <= 4);
171 
172         const uint8_t properties[4] = {
173             static_cast<uint8_t>(type.type),
174             static_cast<uint8_t>((type.primarySize - 1) | (type.secondarySize - 1) << 2 |
175                                  type.isSamplerBaseImage << 4),
176             static_cast<uint8_t>(type.typeSpec.blockStorage | type.imageInternalFormat << 3),
177             // Padding because ComputeGenericHash expects a key size divisible by 4
178         };
179 
180         return result ^ angle::ComputeGenericHash(properties, sizeof(properties));
181     }
182 };
183 
184 struct SpirvIdAndIdListHash
185 {
operatorSpirvIdAndIdListHash186     size_t operator()(const SpirvIdAndIdList &key) const
187     {
188         return angle::ComputeGenericHash(key.idList.data(),
189                                          key.idList.size() * sizeof(key.idList[0])) ^
190                key.id;
191     }
192 };
193 
194 struct SpirvIdAndStorageClassHash
195 {
operatorSpirvIdAndStorageClassHash196     size_t operator()(const SpirvIdAndStorageClass &key) const
197     {
198         ASSERT(key.storageClass < 16);
199         return key.storageClass | key.id << 4;
200     }
201 };
202 
203 // Data tracked per SPIR-V type (keyed by SpirvType).
204 struct SpirvTypeData
205 {
206     // The SPIR-V id corresponding to the type.
207     spirv::IdRef id;
208 };
209 
210 // Decorations to be applied to variable or intermediate ids which are not part of the SPIR-V type
211 // and are not specific enough (like DescriptorSet) to be handled automatically.  Currently, these
212 // are:
213 //
214 //     RelaxedPrecision: used to implement |lowp| and |mediump|
215 //     NoContraction: used to implement |precise|.  TODO: support this.  It requires the precise
216 //                    property to be promoted through the nodes in the AST, which currently isn't.
217 //                    http://anglebug.com/4889
218 //     Invariant: used to implement |invariant|, which is applied to output variables.
219 //
220 // Note that Invariant applies to variables and NoContraction to arithmetic instructions, so they
221 // are mutually exclusive and a maximum of 2 decorations are possible.  FixedVector::push_back will
222 // ASSERT if the given size is ever not enough.
223 using SpirvDecorations = angle::FixedVector<spv::Decoration, 2>;
224 
225 // A block of code.  SPIR-V produces forward references to blocks, such as OpBranchConditional
226 // specifying the id of the if and else blocks, each of those referencing the id of the block after
227 // the else.  Additionally, local variable declarations are accumulated at the top of the first
228 // block in a function.  For these reasons, each block of SPIR-V is generated separately and
229 // assembled at the end of the function, allowing prior blocks to be modified when necessary.
230 struct SpirvBlock
231 {
232     // Id of the block
233     spirv::IdRef labelId;
234 
235     // Local variable declarations.  Only the first block of a function is allowed to contain any
236     // instructions here.
237     spirv::Blob localVariables;
238 
239     // Everything *after* OpLabel (which itself is not generated until blocks are assembled) and
240     // local variables.
241     spirv::Blob body;
242 
243     // Whether the block is terminated.  Useful for functions without return, asserting that code is
244     // not added after return/break/continue etc (i.e. dead code, which should really be removed
245     // earlier by a transformation, but could also be hacked by returning a bogus block to contain
246     // all the "garbage" to throw away), last switch case without a break, etc.
247     bool isTerminated = false;
248 };
249 
250 // Conditional code, constituting ifs, switches and loops.
251 struct SpirvConditional
252 {
253     // The id of blocks that make up the conditional.
254     //
255     // - For if, there are three blocks: the then, else and merge blocks
256     // - For loops, there are four blocks: the condition, body, continue and merge blocks
257     // - For switch, there are a number of blocks based on the cases.
258     //
259     // In all cases, the merge block is the last block in this list.  When the conditional is done
260     // with, that's the block that will be made "current" and future instructions written to.  The
261     // merge block is also the branch target of "break" instructions.
262     //
263     // For loops, the continue target block is the one before last block in this list.
264     std::vector<spirv::IdRef> blockIds;
265 
266     // Up to which block is already generated.  Used by nextConditionalBlock() to generate a block
267     // and give it an id pre-determined in blockIds.
268     size_t nextBlockToWrite = 0;
269 
270     // Used to determine if continue will affect this (i.e. it's a loop).
271     bool isContinuable = false;
272     // Used to determine if break will affect this (i.e. it's a loop or switch).
273     bool isBreakable = false;
274 };
275 
276 // Helper class to construct SPIR-V
277 class SPIRVBuilder : angle::NonCopyable
278 {
279   public:
SPIRVBuilder(TCompiler * compiler,ShCompileOptions compileOptions,bool forceHighp,ShHashFunction64 hashFunction,NameMap & nameMap)280     SPIRVBuilder(TCompiler *compiler,
281                  ShCompileOptions compileOptions,
282                  bool forceHighp,
283                  ShHashFunction64 hashFunction,
284                  NameMap &nameMap)
285         : mCompiler(compiler),
286           mCompileOptions(compileOptions),
287           mShaderType(gl::FromGLenum<gl::ShaderType>(compiler->getShaderType())),
288           mDisableRelaxedPrecision(forceHighp),
289           mNextAvailableId(1),
290           mHashFunction(hashFunction),
291           mNameMap(nameMap),
292           mNextUnusedBinding(0),
293           mNextUnusedInputLocation(0),
294           mNextUnusedOutputLocation(0)
295     {}
296 
297     spirv::IdRef getNewId(const SpirvDecorations &decorations);
298     SpirvType getSpirvType(const TType &type, const SpirvTypeSpec &typeSpec) const;
299     const SpirvTypeData &getTypeData(const TType &type, const SpirvTypeSpec &typeSpec);
300     const SpirvTypeData &getSpirvTypeData(const SpirvType &type, const TSymbol *block);
301     spirv::IdRef getBasicTypeId(TBasicType basicType, size_t size);
302     spirv::IdRef getTypePointerId(spirv::IdRef typeId, spv::StorageClass storageClass);
303     spirv::IdRef getFunctionTypeId(spirv::IdRef returnTypeId, const spirv::IdRefList &paramTypeIds);
304 
305     // Decorations that may apply to intermediate instructions (in addition to variables).
306     SpirvDecorations getDecorations(const TType &type);
307 
308     // Extended instructions
309     spirv::IdRef getExtInstImportIdStd();
310 
getSpirvDebug()311     spirv::Blob *getSpirvDebug() { return &mSpirvDebug; }
getSpirvDecorations()312     spirv::Blob *getSpirvDecorations() { return &mSpirvDecorations; }
getSpirvTypeAndConstantDecls()313     spirv::Blob *getSpirvTypeAndConstantDecls() { return &mSpirvTypeAndConstantDecls; }
getSpirvTypePointerDecls()314     spirv::Blob *getSpirvTypePointerDecls() { return &mSpirvTypePointerDecls; }
getSpirvFunctionTypeDecls()315     spirv::Blob *getSpirvFunctionTypeDecls() { return &mSpirvFunctionTypeDecls; }
getSpirvVariableDecls()316     spirv::Blob *getSpirvVariableDecls() { return &mSpirvVariableDecls; }
getSpirvFunctions()317     spirv::Blob *getSpirvFunctions() { return &mSpirvFunctions; }
getSpirvCurrentFunctionBlock()318     spirv::Blob *getSpirvCurrentFunctionBlock()
319     {
320         ASSERT(!mSpirvCurrentFunctionBlocks.empty() &&
321                !mSpirvCurrentFunctionBlocks.back().isTerminated);
322         return &mSpirvCurrentFunctionBlocks.back().body;
323     }
getSpirvCurrentFunctionBlockId()324     spirv::IdRef getSpirvCurrentFunctionBlockId()
325     {
326         ASSERT(!mSpirvCurrentFunctionBlocks.empty() &&
327                !mSpirvCurrentFunctionBlocks.back().isTerminated);
328         return mSpirvCurrentFunctionBlocks.back().labelId;
329     }
isCurrentFunctionBlockTerminated()330     bool isCurrentFunctionBlockTerminated() const
331     {
332         ASSERT(!mSpirvCurrentFunctionBlocks.empty());
333         return mSpirvCurrentFunctionBlocks.back().isTerminated;
334     }
terminateCurrentFunctionBlock()335     void terminateCurrentFunctionBlock()
336     {
337         ASSERT(!mSpirvCurrentFunctionBlocks.empty());
338         mSpirvCurrentFunctionBlocks.back().isTerminated = true;
339     }
getCurrentConditional()340     const SpirvConditional *getCurrentConditional() { return &mConditionalStack.back(); }
341 
342     bool isInvariantOutput(const TType &type) const;
343 
344     void addCapability(spv::Capability capability);
345     void setEntryPointId(spirv::IdRef id);
346     void addEntryPointInterfaceVariableId(spirv::IdRef id);
347     void writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId);
348     void writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId);
349     void writeBranchConditional(spirv::IdRef conditionValue,
350                                 spirv::IdRef trueBlock,
351                                 spirv::IdRef falseBlock,
352                                 spirv::IdRef mergeBlock);
353     void writeBranchConditionalBlockEnd();
354     void writeLoopHeader(spirv::IdRef branchToBlock,
355                          spirv::IdRef continueBlock,
356                          spirv::IdRef mergeBlock);
357     void writeLoopConditionEnd(spirv::IdRef conditionValue,
358                                spirv::IdRef branchToBlock,
359                                spirv::IdRef mergeBlock);
360     void writeLoopContinueEnd(spirv::IdRef headerBlock);
361     void writeLoopBodyEnd(spirv::IdRef continueBlock);
362     void writeSwitch(spirv::IdRef conditionValue,
363                      spirv::IdRef defaultBlock,
364                      const spirv::PairLiteralIntegerIdRefList &targetPairList,
365                      spirv::IdRef mergeBlock);
366     void writeSwitchCaseBlockEnd();
367 
368     spirv::IdRef getBoolConstant(bool value);
369     spirv::IdRef getUintConstant(uint32_t value);
370     spirv::IdRef getIntConstant(int32_t value);
371     spirv::IdRef getFloatConstant(float value);
372     spirv::IdRef getUvecConstant(uint32_t value, int size);
373     spirv::IdRef getIvecConstant(int32_t value, int size);
374     spirv::IdRef getVecConstant(float value, int size);
375     spirv::IdRef getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values);
376     spirv::IdRef getNullConstant(spirv::IdRef typeId);
377 
378     // Helpers to start and end a function.
379     void startNewFunction(spirv::IdRef functionId, const TFunction *func);
380     void assembleSpirvFunctionBlocks();
381 
382     // Helper to declare a variable.  Function-local variables must be placed in the first block of
383     // the current function.
384     spirv::IdRef declareVariable(spirv::IdRef typeId,
385                                  spv::StorageClass storageClass,
386                                  const SpirvDecorations &decorations,
387                                  spirv::IdRef *initializerId,
388                                  const char *name);
389     // Helper to declare specialization constants.
390     spirv::IdRef declareSpecConst(TBasicType type, int id, const char *name);
391 
392     // Helpers for conditionals.
393     void startConditional(size_t blockCount, bool isContinuable, bool isBreakable);
394     void nextConditionalBlock();
395     void endConditional();
396     bool isInLoop() const;
397     spirv::IdRef getBreakTargetId() const;
398     spirv::IdRef getContinueTargetId() const;
399 
400     // TODO: remove name hashing once translation through glslang is removed.  That is necessary to
401     // avoid name collision between ANGLE's internal symbols and user-defined ones when compiling
402     // the generated GLSL, but is irrelevant when generating SPIR-V directly.  Currently, the SPIR-V
403     // transformer relies on the "mapped" names, which should also be changed when this hashing is
404     // removed.
405     ImmutableString hashName(const TSymbol *symbol);
406     ImmutableString hashTypeName(const TType &type);
407     ImmutableString hashFieldName(const TField *field);
408     ImmutableString hashFunctionName(const TFunction *func);
409 
410     spirv::Blob getSpirv();
411 
412   private:
413     SpirvTypeData declareType(const SpirvType &type, const TSymbol *block);
414 
415     uint32_t calculateBaseAlignmentAndSize(const SpirvType &type, uint32_t *sizeInStorageBlockOut);
416     uint32_t calculateSizeAndWriteOffsetDecorations(const SpirvType &type,
417                                                     spirv::IdRef typeId,
418                                                     uint32_t blockBaseAlignment);
419     void writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId);
420     void writeInterpolationDecoration(TQualifier qualifier, spirv::IdRef id, uint32_t fieldIndex);
421 
422     // Helpers for type declaration.
423     void getImageTypeParameters(TBasicType type,
424                                 spirv::IdRef *sampledTypeOut,
425                                 spv::Dim *dimOut,
426                                 spirv::LiteralInteger *depthOut,
427                                 spirv::LiteralInteger *arrayedOut,
428                                 spirv::LiteralInteger *multisampledOut,
429                                 spirv::LiteralInteger *sampledOut);
430     spv::ImageFormat getImageFormat(TLayoutImageInternalFormat imageInternalFormat);
431 
432     spirv::IdRef getBasicConstantHelper(uint32_t value,
433                                         TBasicType type,
434                                         angle::HashMap<uint32_t, spirv::IdRef> *constants);
435     spirv::IdRef getNullVectorConstantHelper(TBasicType type, int size);
436     spirv::IdRef getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size);
437 
438     uint32_t nextUnusedBinding();
439     uint32_t nextUnusedInputLocation(uint32_t consumedCount);
440     uint32_t nextUnusedOutputLocation(uint32_t consumedCount);
441 
442     void generateExecutionModes(spirv::Blob *blob);
443 
444     ANGLE_MAYBE_UNUSED TCompiler *mCompiler;
445     ShCompileOptions mCompileOptions;
446     gl::ShaderType mShaderType;
447     const bool mDisableRelaxedPrecision;
448 
449     // Capabilities the shader is using.  Accumulated as the instructions are generated.  The Shader
450     // capability is unconditionally generated, so it's not tracked.
451     std::set<spv::Capability> mCapabilities;
452 
453     // The list of interface variables and the id of main() populated as the instructions are
454     // generated.  Used for the OpEntryPoint instruction.
455     spirv::IdRefList mEntryPointInterfaceList;
456     spirv::IdRef mEntryPointId;
457 
458     // Id of imported instructions, if used.
459     spirv::IdRef mExtInstImportIdStd;
460 
461     // Current ID bound, used to allocate new ids.
462     spirv::IdRef mNextAvailableId;
463 
464     // A map from the AST type to the corresponding SPIR-V ID and associated data.  Note that TType
465     // includes a lot of information that pertains to the variable that has the type, not the type
466     // itself.  SpirvType instead contains only information that can identify the type itself.
467     angle::HashMap<SpirvType, SpirvTypeData, SpirvTypeHash> mTypeMap;
468 
469     // Various sections of SPIR-V.  Each section grows as SPIR-V is generated, and the final result
470     // is obtained by stitching the sections together.  This puts the instructions in the order
471     // required by the spec.
472     spirv::Blob mSpirvDebug;
473     spirv::Blob mSpirvDecorations;
474     spirv::Blob mSpirvTypeAndConstantDecls;
475     spirv::Blob mSpirvTypePointerDecls;
476     spirv::Blob mSpirvFunctionTypeDecls;
477     spirv::Blob mSpirvVariableDecls;
478     spirv::Blob mSpirvFunctions;
479     // A list of blocks created for the current function.  These are assembled by
480     // assembleSpirvFunctionBlocks() when the function is entirely visited.  Local variables need to
481     // be inserted at the beginning of the first function block, so the entire SPIR-V of the
482     // function cannot be obtained until it's fully visited.
483     //
484     // The last block in this list is the one currently being written to.
485     std::vector<SpirvBlock> mSpirvCurrentFunctionBlocks;
486 
487     // List of constants that are already defined (for reuse).
488     spirv::IdRef mBoolConstants[2];
489     angle::HashMap<uint32_t, spirv::IdRef> mUintConstants;
490     angle::HashMap<uint32_t, spirv::IdRef> mIntConstants;
491     angle::HashMap<uint32_t, spirv::IdRef> mFloatConstants;
492     angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mCompositeConstants;
493     // Keyed by typeId, returns the null constant corresponding to that type.
494     std::vector<spirv::IdRef> mNullConstants;
495 
496     // List of type pointers that are already defined.
497     // TODO: if all users call getTypeData(), move to SpirvTypeData.  http://anglebug.com/4889
498     angle::HashMap<SpirvIdAndStorageClass, spirv::IdRef, SpirvIdAndStorageClassHash>
499         mTypePointerIdMap;
500 
501     // List of function types that are already defined.
502     angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mFunctionTypeIdMap;
503 
504     // Stack of conditionals.  When an if, loop or switch is visited, a new conditional scope is
505     // added.  When the conditional construct is entirely visited, it's popped.  As the blocks of
506     // the conditional constructs are visited, ids are consumed from the top of the stack.  When
507     // break or continue is visited, the stack is traversed backwards until a loop or switch is
508     // found.
509     std::vector<SpirvConditional> mConditionalStack;
510 
511     // name hashing.
512     ShHashFunction64 mHashFunction;
513     NameMap &mNameMap;
514 
515     // Every resource that requires set & binding layout qualifiers is assigned set 0 and an
516     // arbitrary binding.  Every input/output that requires a location layout qualifier is assigned
517     // an arbitrary location as well.
518     //
519     // The link-time SPIR-V transformer modifies set, binding and location decorations in SPIR-V
520     // directly.
521     uint32_t mNextUnusedBinding;
522     uint32_t mNextUnusedInputLocation;
523     uint32_t mNextUnusedOutputLocation;
524 };
525 }  // namespace sh
526 
527 #endif  // COMPILER_TRANSLATOR_BUILDSPIRV_H_
528