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