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