xref: /aosp_15_r20/external/angle/third_party/glslang/src/SPIRV/GlslangToSpv.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright (C) 2014-2016 LunarG, Inc.
3 // Copyright (C) 2015-2020 Google, Inc.
4 // Copyright (C) 2017, 2022-2024 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 // Visit the nodes in the glslang intermediate tree representation to
40 // translate them to SPIR-V.
41 //
42 
43 #include "spirv.hpp"
44 #include "GlslangToSpv.h"
45 #include "SpvBuilder.h"
46 #include "SpvTools.h"
47 namespace spv {
48     #include "GLSL.std.450.h"
49     #include "GLSL.ext.KHR.h"
50     #include "GLSL.ext.EXT.h"
51     #include "GLSL.ext.AMD.h"
52     #include "GLSL.ext.NV.h"
53     #include "GLSL.ext.ARM.h"
54     #include "GLSL.ext.QCOM.h"
55     #include "NonSemanticDebugPrintf.h"
56 }
57 
58 // Glslang includes
59 #include "../glslang/MachineIndependent/localintermediate.h"
60 #include "../glslang/MachineIndependent/SymbolTable.h"
61 #include "../glslang/Include/Common.h"
62 
63 // Build-time generated includes
64 #include "glslang/build_info.h"
65 
66 #include <fstream>
67 #include <iomanip>
68 #include <list>
69 #include <map>
70 #include <optional>
71 #include <stack>
72 #include <string>
73 #include <vector>
74 
75 namespace {
76 
77 namespace {
78 class SpecConstantOpModeGuard {
79 public:
SpecConstantOpModeGuard(spv::Builder * builder)80     SpecConstantOpModeGuard(spv::Builder* builder)
81         : builder_(builder) {
82         previous_flag_ = builder->isInSpecConstCodeGenMode();
83     }
~SpecConstantOpModeGuard()84     ~SpecConstantOpModeGuard() {
85         previous_flag_ ? builder_->setToSpecConstCodeGenMode()
86                        : builder_->setToNormalCodeGenMode();
87     }
turnOnSpecConstantOpMode()88     void turnOnSpecConstantOpMode() {
89         builder_->setToSpecConstCodeGenMode();
90     }
91 
92 private:
93     spv::Builder* builder_;
94     bool previous_flag_;
95 };
96 
97 struct OpDecorations {
98     public:
OpDecorations__anon1051589c0111::__anon1051589c0211::OpDecorations99         OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) :
100             precision(precision)
101             ,
102             noContraction(noContraction),
103             nonUniform(nonUniform)
104         { }
105 
106     spv::Decoration precision;
107 
addNoContraction__anon1051589c0111::__anon1051589c0211::OpDecorations108         void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); }
addNonUniform__anon1051589c0111::__anon1051589c0211::OpDecorations109         void addNonUniform(spv::Builder& builder, spv::Id t)  { builder.addDecoration(t, nonUniform); }
110     protected:
111         spv::Decoration noContraction;
112         spv::Decoration nonUniform;
113 };
114 
115 } // namespace
116 
117 //
118 // The main holder of information for translating glslang to SPIR-V.
119 //
120 // Derives from the AST walking base class.
121 //
122 class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
123 public:
124     TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger,
125         glslang::SpvOptions& options);
~TGlslangToSpvTraverser()126     virtual ~TGlslangToSpvTraverser() { }
127 
128     bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
129     bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
130     void visitConstantUnion(glslang::TIntermConstantUnion*);
131     bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
132     bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
133     void visitSymbol(glslang::TIntermSymbol* symbol);
134     bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
135     bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
136     bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
137 
138     void finishSpv(bool compileOnly);
139     void dumpSpv(std::vector<unsigned int>& out);
140 
141 protected:
142     TGlslangToSpvTraverser(TGlslangToSpvTraverser&);
143     TGlslangToSpvTraverser& operator=(TGlslangToSpvTraverser&);
144 
145     spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
146     spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
147     spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
148     spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags);
149     spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);
150     spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
151     spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
152     spv::Scope TranslateMemoryScope(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
153     spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
154     spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
155     spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
156     spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
157     spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;
158     spv::StorageClass TranslateStorageClass(const glslang::TType&);
159     void TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>&, std::vector<unsigned>&) const;
160     void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
161     spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType);
162     spv::Id getSampledType(const glslang::TSampler&);
163     spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
164     spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);
165     void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);
166     spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);
167     spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,
168         bool lastBufferBlockMember, bool forwardReferenceOnly = false);
169     void applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member);
170     bool filterMember(const glslang::TType& member);
171     spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
172                                           glslang::TLayoutPacking, const glslang::TQualifier&);
173     spv::LinkageType convertGlslangLinkageToSpv(glslang::TLinkType glslangLinkType);
174     void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,
175                             const glslang::TQualifier&, spv::Id, const std::vector<spv::Id>& spvMembers);
176     spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false, bool boolType = false);
177     spv::Id accessChainLoad(const glslang::TType& type);
178     void    accessChainStore(const glslang::TType& type, spv::Id rvalue);
179     void multiTypeStore(const glslang::TType&, spv::Id rValue);
180     spv::Id convertLoadedBoolInUniformToUint(const glslang::TType& type, spv::Id nominalTypeId, spv::Id loadedId);
181     glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
182     int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
183     int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
184     void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset,
185                             int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);
186     void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember);
187 
188     bool isShaderEntryPoint(const glslang::TIntermAggregate* node);
189     bool writableParam(glslang::TStorageQualifier) const;
190     bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam);
191     void makeFunctions(const glslang::TIntermSequence&);
192     void makeGlobalInitializers(const glslang::TIntermSequence&);
193     void collectRayTracingLinkerObjects();
194     void visitFunctions(const glslang::TIntermSequence&);
195     void handleFunctionEntry(const glslang::TIntermAggregate* node);
196     void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
197         spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
198     void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
199     spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
200     spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
201 
202     spv::Id createBinaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right,
203                                   glslang::TBasicType typeProxy, bool reduceComparison = true);
204     spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right);
205     spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand,
206                                  glslang::TBasicType typeProxy,
207                                  const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
208                                  const glslang::TType &opType);
209     spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand,
210                                        glslang::TBasicType typeProxy);
211     spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand,
212                              glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType);
213     spv::Id createIntWidthConversion(spv::Id operand, int vectorSize, spv::Id destType,
214                                      glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType);
215     spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
216     spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
217         std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
218         const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
219         const glslang::TType &opType);
220     spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
221         glslang::TBasicType typeProxy);
222     spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
223         spv::Id typeId, std::vector<spv::Id>& operands);
224     spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
225         glslang::TBasicType typeProxy);
226     spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
227         std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
228     spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);
229     spv::Id getSymbolId(const glslang::TIntermSymbol* node);
230     void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier);
231     bool hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor);
232     void addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor);
233     void addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather);
234     spv::Id createSpvConstant(const glslang::TIntermTyped&);
235     spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&,
236         int& nextConst, bool specConstant);
237     bool isTrivialLeaf(const glslang::TIntermTyped* node);
238     bool isTrivial(const glslang::TIntermTyped* node);
239     spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
240     spv::Id getExtBuiltins(const char* name);
241     std::pair<spv::Id, spv::Id> getForcedType(glslang::TBuiltInVariable builtIn, const glslang::TType&);
242     spv::Id translateForcedType(spv::Id object);
243     spv::Id createCompositeConstruct(spv::Id typeId, std::vector<spv::Id> constituents);
244 
245     glslang::SpvOptions& options;
246     spv::Function* shaderEntry;
247     spv::Function* currentFunction;
248     spv::Instruction* entryPoint;
249     int sequenceDepth;
250 
251     spv::SpvBuildLogger* logger;
252 
253     // There is a 1:1 mapping between a spv builder and a module; this is thread safe
254     spv::Builder builder;
255     bool inEntryPoint;
256     bool entryPointTerminated;
257     bool linkageOnly;                  // true when visiting the set of objects in the AST present only for
258                                        // establishing interface, whether or not they were statically used
259     std::set<spv::Id> iOSet;           // all input/output variables from either static use or declaration of interface
260     const glslang::TIntermediate* glslangIntermediate;
261     bool nanMinMaxClamp;               // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp
262     spv::Id stdBuiltins;
263     spv::Id nonSemanticDebugPrintf;
264     std::unordered_map<std::string, spv::Id> extBuiltinMap;
265 
266     std::unordered_map<long long, spv::Id> symbolValues;
267     std::unordered_map<uint32_t, spv::Id> builtInVariableIds;
268     std::unordered_set<long long> rValueParameters;  // set of formal function parameters passed as rValues,
269                                                // rather than a pointer
270     std::unordered_map<std::string, spv::Function*> functionMap;
271     std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
272     // for mapping glslang block indices to spv indices (e.g., due to hidden members):
273     std::unordered_map<long long, std::vector<int>> memberRemapper;
274     // for mapping glslang symbol struct to symbol Id
275     std::unordered_map<const glslang::TTypeList*, long long> glslangTypeToIdMap;
276     std::stack<bool> breakForLoop;  // false means break for switch
277     std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;
278     // Map pointee types for EbtReference to their forward pointers
279     std::map<const glslang::TType *, spv::Id> forwardPointers;
280     // Type forcing, for when SPIR-V wants a different type than the AST,
281     // requiring local translation to and from SPIR-V type on every access.
282     // Maps <builtin-variable-id -> AST-required-type-id>
283     std::unordered_map<spv::Id, spv::Id> forceType;
284     // Used by Task shader while generating opearnds for OpEmitMeshTasksEXT
285     spv::Id taskPayloadID;
286     // Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData
287     std::unordered_map<unsigned int, glslang::TIntermSymbol *> locationToSymbol[4];
288     std::unordered_map<spv::Id, std::vector<spv::Decoration> > idToQCOMDecorations;
289 };
290 
291 //
292 // Helper functions for translating glslang representations to SPIR-V enumerants.
293 //
294 
295 // Translate glslang profile to SPIR-V source language.
TranslateSourceLanguage(glslang::EShSource source,EProfile profile)296 spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile)
297 {
298     switch (source) {
299     case glslang::EShSourceGlsl:
300         switch (profile) {
301         case ENoProfile:
302         case ECoreProfile:
303         case ECompatibilityProfile:
304             return spv::SourceLanguageGLSL;
305         case EEsProfile:
306             return spv::SourceLanguageESSL;
307         default:
308             return spv::SourceLanguageUnknown;
309         }
310     case glslang::EShSourceHlsl:
311         return spv::SourceLanguageHLSL;
312     default:
313         return spv::SourceLanguageUnknown;
314     }
315 }
316 
317 // Translate glslang language (stage) to SPIR-V execution model.
TranslateExecutionModel(EShLanguage stage,bool isMeshShaderEXT=false)318 spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShaderEXT = false)
319 {
320     switch (stage) {
321     case EShLangVertex:           return spv::ExecutionModelVertex;
322     case EShLangFragment:         return spv::ExecutionModelFragment;
323     case EShLangCompute:          return spv::ExecutionModelGLCompute;
324     case EShLangTessControl:      return spv::ExecutionModelTessellationControl;
325     case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;
326     case EShLangGeometry:         return spv::ExecutionModelGeometry;
327     case EShLangRayGen:           return spv::ExecutionModelRayGenerationKHR;
328     case EShLangIntersect:        return spv::ExecutionModelIntersectionKHR;
329     case EShLangAnyHit:           return spv::ExecutionModelAnyHitKHR;
330     case EShLangClosestHit:       return spv::ExecutionModelClosestHitKHR;
331     case EShLangMiss:             return spv::ExecutionModelMissKHR;
332     case EShLangCallable:         return spv::ExecutionModelCallableKHR;
333     case EShLangTask:             return (isMeshShaderEXT)? spv::ExecutionModelTaskEXT : spv::ExecutionModelTaskNV;
334     case EShLangMesh:             return (isMeshShaderEXT)? spv::ExecutionModelMeshEXT: spv::ExecutionModelMeshNV;
335     default:
336         assert(0);
337         return spv::ExecutionModelFragment;
338     }
339 }
340 
341 // Translate glslang sampler type to SPIR-V dimensionality.
TranslateDimensionality(const glslang::TSampler & sampler)342 spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
343 {
344     switch (sampler.dim) {
345     case glslang::Esd1D:      return spv::Dim1D;
346     case glslang::Esd2D:      return spv::Dim2D;
347     case glslang::Esd3D:      return spv::Dim3D;
348     case glslang::EsdCube:    return spv::DimCube;
349     case glslang::EsdRect:    return spv::DimRect;
350     case glslang::EsdBuffer:  return spv::DimBuffer;
351     case glslang::EsdSubpass: return spv::DimSubpassData;
352     case glslang::EsdAttachmentEXT: return spv::DimTileImageDataEXT;
353     default:
354         assert(0);
355         return spv::Dim2D;
356     }
357 }
358 
359 // Translate glslang precision to SPIR-V precision decorations.
TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)360 spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
361 {
362     switch (glslangPrecision) {
363     case glslang::EpqLow:    return spv::DecorationRelaxedPrecision;
364     case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
365     default:
366         return spv::NoPrecision;
367     }
368 }
369 
370 // Translate glslang type to SPIR-V precision decorations.
TranslatePrecisionDecoration(const glslang::TType & type)371 spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
372 {
373     return TranslatePrecisionDecoration(type.getQualifier().precision);
374 }
375 
376 // Translate glslang type to SPIR-V block decorations.
TranslateBlockDecoration(const glslang::TStorageQualifier storage,bool useStorageBuffer)377 spv::Decoration TranslateBlockDecoration(const glslang::TStorageQualifier storage, bool useStorageBuffer)
378 {
379     switch (storage) {
380     case glslang::EvqUniform:      return spv::DecorationBlock;
381     case glslang::EvqBuffer:       return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock;
382     case glslang::EvqVaryingIn:    return spv::DecorationBlock;
383     case glslang::EvqVaryingOut:   return spv::DecorationBlock;
384     case glslang::EvqShared:       return spv::DecorationBlock;
385     case glslang::EvqPayload:      return spv::DecorationBlock;
386     case glslang::EvqPayloadIn:    return spv::DecorationBlock;
387     case glslang::EvqHitAttr:      return spv::DecorationBlock;
388     case glslang::EvqCallableData:   return spv::DecorationBlock;
389     case glslang::EvqCallableDataIn: return spv::DecorationBlock;
390     case glslang::EvqHitObjectAttrNV: return spv::DecorationBlock;
391     default:
392         assert(0);
393         break;
394     }
395 
396     return spv::DecorationMax;
397 }
398 
399 // Translate glslang type to SPIR-V memory decorations.
TranslateMemoryDecoration(const glslang::TQualifier & qualifier,std::vector<spv::Decoration> & memory,bool useVulkanMemoryModel)400 void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory,
401     bool useVulkanMemoryModel)
402 {
403     if (!useVulkanMemoryModel) {
404         if (qualifier.isVolatile()) {
405             memory.push_back(spv::DecorationVolatile);
406             memory.push_back(spv::DecorationCoherent);
407         } else if (qualifier.isCoherent()) {
408             memory.push_back(spv::DecorationCoherent);
409         }
410     }
411     if (qualifier.isRestrict())
412         memory.push_back(spv::DecorationRestrict);
413     if (qualifier.isReadOnly())
414         memory.push_back(spv::DecorationNonWritable);
415     if (qualifier.isWriteOnly())
416        memory.push_back(spv::DecorationNonReadable);
417 }
418 
419 // Translate glslang type to SPIR-V layout decorations.
TranslateLayoutDecoration(const glslang::TType & type,glslang::TLayoutMatrix matrixLayout)420 spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
421 {
422     if (type.isMatrix()) {
423         switch (matrixLayout) {
424         case glslang::ElmRowMajor:
425             return spv::DecorationRowMajor;
426         case glslang::ElmColumnMajor:
427             return spv::DecorationColMajor;
428         default:
429             // opaque layouts don't need a majorness
430             return spv::DecorationMax;
431         }
432     } else {
433         switch (type.getBasicType()) {
434         default:
435             return spv::DecorationMax;
436             break;
437         case glslang::EbtBlock:
438             switch (type.getQualifier().storage) {
439             case glslang::EvqShared:
440             case glslang::EvqUniform:
441             case glslang::EvqBuffer:
442                 switch (type.getQualifier().layoutPacking) {
443                 case glslang::ElpShared:  return spv::DecorationGLSLShared;
444                 case glslang::ElpPacked:  return spv::DecorationGLSLPacked;
445                 default:
446                     return spv::DecorationMax;
447                 }
448             case glslang::EvqVaryingIn:
449             case glslang::EvqVaryingOut:
450                 if (type.getQualifier().isTaskMemory()) {
451                     switch (type.getQualifier().layoutPacking) {
452                     case glslang::ElpShared:  return spv::DecorationGLSLShared;
453                     case glslang::ElpPacked:  return spv::DecorationGLSLPacked;
454                     default: break;
455                     }
456                 } else {
457                     assert(type.getQualifier().layoutPacking == glslang::ElpNone);
458                 }
459                 return spv::DecorationMax;
460             case glslang::EvqPayload:
461             case glslang::EvqPayloadIn:
462             case glslang::EvqHitAttr:
463             case glslang::EvqCallableData:
464             case glslang::EvqCallableDataIn:
465             case glslang::EvqHitObjectAttrNV:
466                 return spv::DecorationMax;
467             default:
468                 assert(0);
469                 return spv::DecorationMax;
470             }
471         }
472     }
473 }
474 
475 // Translate glslang type to SPIR-V interpolation decorations.
476 // Returns spv::DecorationMax when no decoration
477 // should be applied.
TranslateInterpolationDecoration(const glslang::TQualifier & qualifier)478 spv::Decoration TGlslangToSpvTraverser::TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
479 {
480     if (qualifier.smooth)
481         // Smooth decoration doesn't exist in SPIR-V 1.0
482         return spv::DecorationMax;
483     else if (qualifier.isNonPerspective())
484         return spv::DecorationNoPerspective;
485     else if (qualifier.flat)
486         return spv::DecorationFlat;
487     else if (qualifier.isExplicitInterpolation()) {
488         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
489         return spv::DecorationExplicitInterpAMD;
490     }
491     else
492         return spv::DecorationMax;
493 }
494 
495 // Translate glslang type to SPIR-V auxiliary storage decorations.
496 // Returns spv::DecorationMax when no decoration
497 // should be applied.
TranslateAuxiliaryStorageDecoration(const glslang::TQualifier & qualifier)498 spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier)
499 {
500     if (qualifier.centroid)
501         return spv::DecorationCentroid;
502     else if (qualifier.patch)
503         return spv::DecorationPatch;
504     else if (qualifier.sample) {
505         builder.addCapability(spv::CapabilitySampleRateShading);
506         return spv::DecorationSample;
507     }
508 
509     return spv::DecorationMax;
510 }
511 
512 // If glslang type is invariant, return SPIR-V invariant decoration.
TranslateInvariantDecoration(const glslang::TQualifier & qualifier)513 spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
514 {
515     if (qualifier.invariant)
516         return spv::DecorationInvariant;
517     else
518         return spv::DecorationMax;
519 }
520 
521 // If glslang type is noContraction, return SPIR-V NoContraction decoration.
TranslateNoContractionDecoration(const glslang::TQualifier & qualifier)522 spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
523 {
524     if (qualifier.isNoContraction())
525         return spv::DecorationNoContraction;
526     else
527         return spv::DecorationMax;
528 }
529 
530 // If glslang type is nonUniform, return SPIR-V NonUniform decoration.
TranslateNonUniformDecoration(const glslang::TQualifier & qualifier)531 spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier)
532 {
533     if (qualifier.isNonUniform()) {
534         builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
535         builder.addCapability(spv::CapabilityShaderNonUniformEXT);
536         return spv::DecorationNonUniformEXT;
537     } else
538         return spv::DecorationMax;
539 }
540 
541 // If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration.
TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags & coherentFlags)542 spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(
543     const spv::Builder::AccessChain::CoherentFlags& coherentFlags)
544 {
545     if (coherentFlags.isNonUniform()) {
546         builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
547         builder.addCapability(spv::CapabilityShaderNonUniformEXT);
548         return spv::DecorationNonUniformEXT;
549     } else
550         return spv::DecorationMax;
551 }
552 
TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags & coherentFlags)553 spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(
554     const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
555 {
556     spv::MemoryAccessMask mask = spv::MemoryAccessMaskNone;
557 
558     if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage)
559         return mask;
560 
561     if (coherentFlags.isVolatile() || coherentFlags.anyCoherent()) {
562         mask = mask | spv::MemoryAccessMakePointerAvailableKHRMask |
563                       spv::MemoryAccessMakePointerVisibleKHRMask;
564     }
565 
566     if (coherentFlags.nonprivate) {
567         mask = mask | spv::MemoryAccessNonPrivatePointerKHRMask;
568     }
569     if (coherentFlags.volatil) {
570         mask = mask | spv::MemoryAccessVolatileMask;
571     }
572     if (mask != spv::MemoryAccessMaskNone) {
573         builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
574     }
575 
576     return mask;
577 }
578 
TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags & coherentFlags)579 spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands(
580     const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
581 {
582     spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
583 
584     if (!glslangIntermediate->usingVulkanMemoryModel())
585         return mask;
586 
587     if (coherentFlags.volatil ||
588         coherentFlags.anyCoherent()) {
589         mask = mask | spv::ImageOperandsMakeTexelAvailableKHRMask |
590                       spv::ImageOperandsMakeTexelVisibleKHRMask;
591     }
592     if (coherentFlags.nonprivate) {
593         mask = mask | spv::ImageOperandsNonPrivateTexelKHRMask;
594     }
595     if (coherentFlags.volatil) {
596         mask = mask | spv::ImageOperandsVolatileTexelKHRMask;
597     }
598     if (mask != spv::ImageOperandsMaskNone) {
599         builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
600     }
601 
602     return mask;
603 }
604 
TranslateCoherent(const glslang::TType & type)605 spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type)
606 {
607     spv::Builder::AccessChain::CoherentFlags flags = {};
608     flags.coherent = type.getQualifier().coherent;
609     flags.devicecoherent = type.getQualifier().devicecoherent;
610     flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent;
611     // shared variables are implicitly workgroupcoherent in GLSL.
612     flags.workgroupcoherent = type.getQualifier().workgroupcoherent ||
613                               type.getQualifier().storage == glslang::EvqShared;
614     flags.subgroupcoherent = type.getQualifier().subgroupcoherent;
615     flags.shadercallcoherent = type.getQualifier().shadercallcoherent;
616     flags.volatil = type.getQualifier().volatil;
617     // *coherent variables are implicitly nonprivate in GLSL
618     flags.nonprivate = type.getQualifier().nonprivate ||
619                        flags.anyCoherent() ||
620                        flags.volatil;
621     flags.isImage = type.getBasicType() == glslang::EbtSampler;
622     flags.nonUniform = type.getQualifier().nonUniform;
623     return flags;
624 }
625 
TranslateMemoryScope(const spv::Builder::AccessChain::CoherentFlags & coherentFlags)626 spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope(
627     const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
628 {
629     spv::Scope scope = spv::ScopeMax;
630 
631     if (coherentFlags.volatil || coherentFlags.coherent) {
632         // coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model
633         scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
634     } else if (coherentFlags.devicecoherent) {
635         scope = spv::ScopeDevice;
636     } else if (coherentFlags.queuefamilycoherent) {
637         scope = spv::ScopeQueueFamilyKHR;
638     } else if (coherentFlags.workgroupcoherent) {
639         scope = spv::ScopeWorkgroup;
640     } else if (coherentFlags.subgroupcoherent) {
641         scope = spv::ScopeSubgroup;
642     } else if (coherentFlags.shadercallcoherent) {
643         scope = spv::ScopeShaderCallKHR;
644     }
645     if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) {
646         builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
647     }
648 
649     return scope;
650 }
651 
652 // Translate a glslang built-in variable to a SPIR-V built in decoration.  Also generate
653 // associated capabilities when required.  For some built-in variables, a capability
654 // is generated only when using the variable in an executable instruction, but not when
655 // just declaring a struct member variable with it.  This is true for PointSize,
656 // ClipDistance, and CullDistance.
TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn,bool memberDeclaration)657 spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn,
658     bool memberDeclaration)
659 {
660     switch (builtIn) {
661     case glslang::EbvPointSize:
662         // Defer adding the capability until the built-in is actually used.
663         if (! memberDeclaration) {
664             switch (glslangIntermediate->getStage()) {
665             case EShLangGeometry:
666                 builder.addCapability(spv::CapabilityGeometryPointSize);
667                 break;
668             case EShLangTessControl:
669             case EShLangTessEvaluation:
670                 builder.addCapability(spv::CapabilityTessellationPointSize);
671                 break;
672             default:
673                 break;
674             }
675         }
676         return spv::BuiltInPointSize;
677 
678     case glslang::EbvPosition:             return spv::BuiltInPosition;
679     case glslang::EbvVertexId:             return spv::BuiltInVertexId;
680     case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;
681     case glslang::EbvVertexIndex:          return spv::BuiltInVertexIndex;
682     case glslang::EbvInstanceIndex:        return spv::BuiltInInstanceIndex;
683 
684     case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;
685     case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;
686     case glslang::EbvFace:                 return spv::BuiltInFrontFacing;
687     case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;
688 
689     case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;
690     case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;
691     case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;
692     case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;
693     case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
694     case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;
695 
696     // These *Distance capabilities logically belong here, but if the member is declared and
697     // then never used, consumers of SPIR-V prefer the capability not be declared.
698     // They are now generated when used, rather than here when declared.
699     // Potentially, the specification should be more clear what the minimum
700     // use needed is to trigger the capability.
701     //
702     case glslang::EbvClipDistance:
703         if (!memberDeclaration)
704             builder.addCapability(spv::CapabilityClipDistance);
705         return spv::BuiltInClipDistance;
706 
707     case glslang::EbvCullDistance:
708         if (!memberDeclaration)
709             builder.addCapability(spv::CapabilityCullDistance);
710         return spv::BuiltInCullDistance;
711 
712     case glslang::EbvViewportIndex:
713         if (glslangIntermediate->getStage() == EShLangGeometry ||
714             glslangIntermediate->getStage() == EShLangFragment) {
715             builder.addCapability(spv::CapabilityMultiViewport);
716         }
717         if (glslangIntermediate->getStage() == EShLangVertex ||
718             glslangIntermediate->getStage() == EShLangTessControl ||
719             glslangIntermediate->getStage() == EShLangTessEvaluation) {
720 
721             if (builder.getSpvVersion() < spv::Spv_1_5) {
722                 builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);
723                 builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);
724             }
725             else
726                 builder.addCapability(spv::CapabilityShaderViewportIndex);
727         }
728         return spv::BuiltInViewportIndex;
729 
730     case glslang::EbvSampleId:
731         builder.addCapability(spv::CapabilitySampleRateShading);
732         return spv::BuiltInSampleId;
733 
734     case glslang::EbvSamplePosition:
735         builder.addCapability(spv::CapabilitySampleRateShading);
736         return spv::BuiltInSamplePosition;
737 
738     case glslang::EbvSampleMask:
739         return spv::BuiltInSampleMask;
740 
741     case glslang::EbvLayer:
742         if (glslangIntermediate->getStage() == EShLangMesh) {
743             return spv::BuiltInLayer;
744         }
745         if (glslangIntermediate->getStage() == EShLangGeometry ||
746             glslangIntermediate->getStage() == EShLangFragment) {
747             builder.addCapability(spv::CapabilityGeometry);
748         }
749         if (glslangIntermediate->getStage() == EShLangVertex ||
750             glslangIntermediate->getStage() == EShLangTessControl ||
751             glslangIntermediate->getStage() == EShLangTessEvaluation) {
752 
753             if (builder.getSpvVersion() < spv::Spv_1_5) {
754                 builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);
755                 builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);
756             } else
757                 builder.addCapability(spv::CapabilityShaderLayer);
758         }
759         return spv::BuiltInLayer;
760 
761     case glslang::EbvBaseVertex:
762         builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
763         builder.addCapability(spv::CapabilityDrawParameters);
764         return spv::BuiltInBaseVertex;
765 
766     case glslang::EbvBaseInstance:
767         builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
768         builder.addCapability(spv::CapabilityDrawParameters);
769         return spv::BuiltInBaseInstance;
770 
771     case glslang::EbvDrawId:
772         builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
773         builder.addCapability(spv::CapabilityDrawParameters);
774         return spv::BuiltInDrawIndex;
775 
776     case glslang::EbvPrimitiveId:
777         if (glslangIntermediate->getStage() == EShLangFragment)
778             builder.addCapability(spv::CapabilityGeometry);
779         return spv::BuiltInPrimitiveId;
780 
781     case glslang::EbvFragStencilRef:
782         builder.addExtension(spv::E_SPV_EXT_shader_stencil_export);
783         builder.addCapability(spv::CapabilityStencilExportEXT);
784         return spv::BuiltInFragStencilRefEXT;
785 
786     case glslang::EbvShadingRateKHR:
787         builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);
788         builder.addCapability(spv::CapabilityFragmentShadingRateKHR);
789         return spv::BuiltInShadingRateKHR;
790 
791     case glslang::EbvPrimitiveShadingRateKHR:
792         builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);
793         builder.addCapability(spv::CapabilityFragmentShadingRateKHR);
794         return spv::BuiltInPrimitiveShadingRateKHR;
795 
796     case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;
797     case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;
798     case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;
799     case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;
800     case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;
801     case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;
802 
803     case glslang::EbvSubGroupSize:
804         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
805         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
806         return spv::BuiltInSubgroupSize;
807 
808     case glslang::EbvSubGroupInvocation:
809         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
810         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
811         return spv::BuiltInSubgroupLocalInvocationId;
812 
813     case glslang::EbvSubGroupEqMask:
814         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
815         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
816         return spv::BuiltInSubgroupEqMask;
817 
818     case glslang::EbvSubGroupGeMask:
819         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
820         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
821         return spv::BuiltInSubgroupGeMask;
822 
823     case glslang::EbvSubGroupGtMask:
824         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
825         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
826         return spv::BuiltInSubgroupGtMask;
827 
828     case glslang::EbvSubGroupLeMask:
829         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
830         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
831         return spv::BuiltInSubgroupLeMask;
832 
833     case glslang::EbvSubGroupLtMask:
834         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
835         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
836         return spv::BuiltInSubgroupLtMask;
837 
838     case glslang::EbvNumSubgroups:
839         builder.addCapability(spv::CapabilityGroupNonUniform);
840         return spv::BuiltInNumSubgroups;
841 
842     case glslang::EbvSubgroupID:
843         builder.addCapability(spv::CapabilityGroupNonUniform);
844         return spv::BuiltInSubgroupId;
845 
846     case glslang::EbvSubgroupSize2:
847         builder.addCapability(spv::CapabilityGroupNonUniform);
848         return spv::BuiltInSubgroupSize;
849 
850     case glslang::EbvSubgroupInvocation2:
851         builder.addCapability(spv::CapabilityGroupNonUniform);
852         return spv::BuiltInSubgroupLocalInvocationId;
853 
854     case glslang::EbvSubgroupEqMask2:
855         builder.addCapability(spv::CapabilityGroupNonUniform);
856         builder.addCapability(spv::CapabilityGroupNonUniformBallot);
857         return spv::BuiltInSubgroupEqMask;
858 
859     case glslang::EbvSubgroupGeMask2:
860         builder.addCapability(spv::CapabilityGroupNonUniform);
861         builder.addCapability(spv::CapabilityGroupNonUniformBallot);
862         return spv::BuiltInSubgroupGeMask;
863 
864     case glslang::EbvSubgroupGtMask2:
865         builder.addCapability(spv::CapabilityGroupNonUniform);
866         builder.addCapability(spv::CapabilityGroupNonUniformBallot);
867         return spv::BuiltInSubgroupGtMask;
868 
869     case glslang::EbvSubgroupLeMask2:
870         builder.addCapability(spv::CapabilityGroupNonUniform);
871         builder.addCapability(spv::CapabilityGroupNonUniformBallot);
872         return spv::BuiltInSubgroupLeMask;
873 
874     case glslang::EbvSubgroupLtMask2:
875         builder.addCapability(spv::CapabilityGroupNonUniform);
876         builder.addCapability(spv::CapabilityGroupNonUniformBallot);
877         return spv::BuiltInSubgroupLtMask;
878 
879     case glslang::EbvBaryCoordNoPersp:
880         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
881         return spv::BuiltInBaryCoordNoPerspAMD;
882 
883     case glslang::EbvBaryCoordNoPerspCentroid:
884         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
885         return spv::BuiltInBaryCoordNoPerspCentroidAMD;
886 
887     case glslang::EbvBaryCoordNoPerspSample:
888         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
889         return spv::BuiltInBaryCoordNoPerspSampleAMD;
890 
891     case glslang::EbvBaryCoordSmooth:
892         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
893         return spv::BuiltInBaryCoordSmoothAMD;
894 
895     case glslang::EbvBaryCoordSmoothCentroid:
896         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
897         return spv::BuiltInBaryCoordSmoothCentroidAMD;
898 
899     case glslang::EbvBaryCoordSmoothSample:
900         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
901         return spv::BuiltInBaryCoordSmoothSampleAMD;
902 
903     case glslang::EbvBaryCoordPullModel:
904         builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
905         return spv::BuiltInBaryCoordPullModelAMD;
906 
907     case glslang::EbvDeviceIndex:
908         builder.addIncorporatedExtension(spv::E_SPV_KHR_device_group, spv::Spv_1_3);
909         builder.addCapability(spv::CapabilityDeviceGroup);
910         return spv::BuiltInDeviceIndex;
911 
912     case glslang::EbvViewIndex:
913         builder.addIncorporatedExtension(spv::E_SPV_KHR_multiview, spv::Spv_1_3);
914         builder.addCapability(spv::CapabilityMultiView);
915         return spv::BuiltInViewIndex;
916 
917     case glslang::EbvFragSizeEXT:
918         builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
919         builder.addCapability(spv::CapabilityFragmentDensityEXT);
920         return spv::BuiltInFragSizeEXT;
921 
922     case glslang::EbvFragInvocationCountEXT:
923         builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
924         builder.addCapability(spv::CapabilityFragmentDensityEXT);
925         return spv::BuiltInFragInvocationCountEXT;
926 
927     case glslang::EbvViewportMaskNV:
928         if (!memberDeclaration) {
929             builder.addExtension(spv::E_SPV_NV_viewport_array2);
930             builder.addCapability(spv::CapabilityShaderViewportMaskNV);
931         }
932         return spv::BuiltInViewportMaskNV;
933     case glslang::EbvSecondaryPositionNV:
934         if (!memberDeclaration) {
935             builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
936             builder.addCapability(spv::CapabilityShaderStereoViewNV);
937         }
938         return spv::BuiltInSecondaryPositionNV;
939     case glslang::EbvSecondaryViewportMaskNV:
940         if (!memberDeclaration) {
941             builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
942             builder.addCapability(spv::CapabilityShaderStereoViewNV);
943         }
944         return spv::BuiltInSecondaryViewportMaskNV;
945     case glslang::EbvPositionPerViewNV:
946         if (!memberDeclaration) {
947             builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
948             builder.addCapability(spv::CapabilityPerViewAttributesNV);
949         }
950         return spv::BuiltInPositionPerViewNV;
951     case glslang::EbvViewportMaskPerViewNV:
952         if (!memberDeclaration) {
953             builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
954             builder.addCapability(spv::CapabilityPerViewAttributesNV);
955         }
956         return spv::BuiltInViewportMaskPerViewNV;
957     case glslang::EbvFragFullyCoveredNV:
958         builder.addExtension(spv::E_SPV_EXT_fragment_fully_covered);
959         builder.addCapability(spv::CapabilityFragmentFullyCoveredEXT);
960         return spv::BuiltInFullyCoveredEXT;
961     case glslang::EbvFragmentSizeNV:
962         builder.addExtension(spv::E_SPV_NV_shading_rate);
963         builder.addCapability(spv::CapabilityShadingRateNV);
964         return spv::BuiltInFragmentSizeNV;
965     case glslang::EbvInvocationsPerPixelNV:
966         builder.addExtension(spv::E_SPV_NV_shading_rate);
967         builder.addCapability(spv::CapabilityShadingRateNV);
968         return spv::BuiltInInvocationsPerPixelNV;
969 
970     // ray tracing
971     case glslang::EbvLaunchId:
972         return spv::BuiltInLaunchIdKHR;
973     case glslang::EbvLaunchSize:
974         return spv::BuiltInLaunchSizeKHR;
975     case glslang::EbvWorldRayOrigin:
976         return spv::BuiltInWorldRayOriginKHR;
977     case glslang::EbvWorldRayDirection:
978         return spv::BuiltInWorldRayDirectionKHR;
979     case glslang::EbvObjectRayOrigin:
980         return spv::BuiltInObjectRayOriginKHR;
981     case glslang::EbvObjectRayDirection:
982         return spv::BuiltInObjectRayDirectionKHR;
983     case glslang::EbvRayTmin:
984         return spv::BuiltInRayTminKHR;
985     case glslang::EbvRayTmax:
986         return spv::BuiltInRayTmaxKHR;
987     case glslang::EbvCullMask:
988         return spv::BuiltInCullMaskKHR;
989     case glslang::EbvPositionFetch:
990         return spv::BuiltInHitTriangleVertexPositionsKHR;
991     case glslang::EbvInstanceCustomIndex:
992         return spv::BuiltInInstanceCustomIndexKHR;
993     case glslang::EbvHitKind:
994         return spv::BuiltInHitKindKHR;
995     case glslang::EbvObjectToWorld:
996     case glslang::EbvObjectToWorld3x4:
997         return spv::BuiltInObjectToWorldKHR;
998     case glslang::EbvWorldToObject:
999     case glslang::EbvWorldToObject3x4:
1000         return spv::BuiltInWorldToObjectKHR;
1001     case glslang::EbvIncomingRayFlags:
1002         return spv::BuiltInIncomingRayFlagsKHR;
1003     case glslang::EbvGeometryIndex:
1004         return spv::BuiltInRayGeometryIndexKHR;
1005     case glslang::EbvCurrentRayTimeNV:
1006         builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);
1007         builder.addCapability(spv::CapabilityRayTracingMotionBlurNV);
1008         return spv::BuiltInCurrentRayTimeNV;
1009     case glslang::EbvMicroTrianglePositionNV:
1010         builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1011         builder.addExtension("SPV_NV_displacement_micromap");
1012         return spv::BuiltInHitMicroTriangleVertexPositionsNV;
1013     case glslang::EbvMicroTriangleBaryNV:
1014         builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1015         builder.addExtension("SPV_NV_displacement_micromap");
1016         return spv::BuiltInHitMicroTriangleVertexBarycentricsNV;
1017     case glslang::EbvHitKindFrontFacingMicroTriangleNV:
1018         builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1019         builder.addExtension("SPV_NV_displacement_micromap");
1020         return spv::BuiltInHitKindFrontFacingMicroTriangleNV;
1021     case glslang::EbvHitKindBackFacingMicroTriangleNV:
1022         builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1023         builder.addExtension("SPV_NV_displacement_micromap");
1024         return spv::BuiltInHitKindBackFacingMicroTriangleNV;
1025 
1026     // barycentrics
1027     case glslang::EbvBaryCoordNV:
1028         builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
1029         builder.addCapability(spv::CapabilityFragmentBarycentricNV);
1030         return spv::BuiltInBaryCoordNV;
1031     case glslang::EbvBaryCoordNoPerspNV:
1032         builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
1033         builder.addCapability(spv::CapabilityFragmentBarycentricNV);
1034         return spv::BuiltInBaryCoordNoPerspNV;
1035 
1036     case glslang::EbvBaryCoordEXT:
1037         builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
1038         builder.addCapability(spv::CapabilityFragmentBarycentricKHR);
1039         return spv::BuiltInBaryCoordKHR;
1040     case glslang::EbvBaryCoordNoPerspEXT:
1041         builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
1042         builder.addCapability(spv::CapabilityFragmentBarycentricKHR);
1043         return spv::BuiltInBaryCoordNoPerspKHR;
1044 
1045     // mesh shaders
1046     case glslang::EbvTaskCountNV:
1047         return spv::BuiltInTaskCountNV;
1048     case glslang::EbvPrimitiveCountNV:
1049         return spv::BuiltInPrimitiveCountNV;
1050     case glslang::EbvPrimitiveIndicesNV:
1051         return spv::BuiltInPrimitiveIndicesNV;
1052     case glslang::EbvClipDistancePerViewNV:
1053         return spv::BuiltInClipDistancePerViewNV;
1054     case glslang::EbvCullDistancePerViewNV:
1055         return spv::BuiltInCullDistancePerViewNV;
1056     case glslang::EbvLayerPerViewNV:
1057         return spv::BuiltInLayerPerViewNV;
1058     case glslang::EbvMeshViewCountNV:
1059         return spv::BuiltInMeshViewCountNV;
1060     case glslang::EbvMeshViewIndicesNV:
1061         return spv::BuiltInMeshViewIndicesNV;
1062 
1063     // SPV_EXT_mesh_shader
1064     case glslang::EbvPrimitivePointIndicesEXT:
1065         return spv::BuiltInPrimitivePointIndicesEXT;
1066     case glslang::EbvPrimitiveLineIndicesEXT:
1067         return spv::BuiltInPrimitiveLineIndicesEXT;
1068     case glslang::EbvPrimitiveTriangleIndicesEXT:
1069         return spv::BuiltInPrimitiveTriangleIndicesEXT;
1070     case glslang::EbvCullPrimitiveEXT:
1071         return spv::BuiltInCullPrimitiveEXT;
1072 
1073     // sm builtins
1074     case glslang::EbvWarpsPerSM:
1075         builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1076         builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1077         return spv::BuiltInWarpsPerSMNV;
1078     case glslang::EbvSMCount:
1079         builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1080         builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1081         return spv::BuiltInSMCountNV;
1082     case glslang::EbvWarpID:
1083         builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1084         builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1085         return spv::BuiltInWarpIDNV;
1086     case glslang::EbvSMID:
1087         builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1088         builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1089         return spv::BuiltInSMIDNV;
1090 
1091    // ARM builtins
1092     case glslang::EbvCoreCountARM:
1093         builder.addExtension(spv::E_SPV_ARM_core_builtins);
1094         builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1095         return spv::BuiltInCoreCountARM;
1096     case glslang::EbvCoreIDARM:
1097         builder.addExtension(spv::E_SPV_ARM_core_builtins);
1098         builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1099         return spv::BuiltInCoreIDARM;
1100     case glslang::EbvCoreMaxIDARM:
1101         builder.addExtension(spv::E_SPV_ARM_core_builtins);
1102         builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1103         return spv::BuiltInCoreMaxIDARM;
1104     case glslang::EbvWarpIDARM:
1105         builder.addExtension(spv::E_SPV_ARM_core_builtins);
1106         builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1107         return spv::BuiltInWarpIDARM;
1108     case glslang::EbvWarpMaxIDARM:
1109         builder.addExtension(spv::E_SPV_ARM_core_builtins);
1110         builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1111         return spv::BuiltInWarpMaxIDARM;
1112 
1113     default:
1114         return spv::BuiltInMax;
1115     }
1116 }
1117 
1118 // Translate glslang image layout format to SPIR-V image format.
TranslateImageFormat(const glslang::TType & type)1119 spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type)
1120 {
1121     assert(type.getBasicType() == glslang::EbtSampler);
1122 
1123     // Check for capabilities
1124     switch (type.getQualifier().getFormat()) {
1125     case glslang::ElfRg32f:
1126     case glslang::ElfRg16f:
1127     case glslang::ElfR11fG11fB10f:
1128     case glslang::ElfR16f:
1129     case glslang::ElfRgba16:
1130     case glslang::ElfRgb10A2:
1131     case glslang::ElfRg16:
1132     case glslang::ElfRg8:
1133     case glslang::ElfR16:
1134     case glslang::ElfR8:
1135     case glslang::ElfRgba16Snorm:
1136     case glslang::ElfRg16Snorm:
1137     case glslang::ElfRg8Snorm:
1138     case glslang::ElfR16Snorm:
1139     case glslang::ElfR8Snorm:
1140 
1141     case glslang::ElfRg32i:
1142     case glslang::ElfRg16i:
1143     case glslang::ElfRg8i:
1144     case glslang::ElfR16i:
1145     case glslang::ElfR8i:
1146 
1147     case glslang::ElfRgb10a2ui:
1148     case glslang::ElfRg32ui:
1149     case glslang::ElfRg16ui:
1150     case glslang::ElfRg8ui:
1151     case glslang::ElfR16ui:
1152     case glslang::ElfR8ui:
1153         builder.addCapability(spv::CapabilityStorageImageExtendedFormats);
1154         break;
1155 
1156     case glslang::ElfR64ui:
1157     case glslang::ElfR64i:
1158         builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
1159         builder.addCapability(spv::CapabilityInt64ImageEXT);
1160         break;
1161     default:
1162         break;
1163     }
1164 
1165     // do the translation
1166     switch (type.getQualifier().getFormat()) {
1167     case glslang::ElfNone:          return spv::ImageFormatUnknown;
1168     case glslang::ElfRgba32f:       return spv::ImageFormatRgba32f;
1169     case glslang::ElfRgba16f:       return spv::ImageFormatRgba16f;
1170     case glslang::ElfR32f:          return spv::ImageFormatR32f;
1171     case glslang::ElfRgba8:         return spv::ImageFormatRgba8;
1172     case glslang::ElfRgba8Snorm:    return spv::ImageFormatRgba8Snorm;
1173     case glslang::ElfRg32f:         return spv::ImageFormatRg32f;
1174     case glslang::ElfRg16f:         return spv::ImageFormatRg16f;
1175     case glslang::ElfR11fG11fB10f:  return spv::ImageFormatR11fG11fB10f;
1176     case glslang::ElfR16f:          return spv::ImageFormatR16f;
1177     case glslang::ElfRgba16:        return spv::ImageFormatRgba16;
1178     case glslang::ElfRgb10A2:       return spv::ImageFormatRgb10A2;
1179     case glslang::ElfRg16:          return spv::ImageFormatRg16;
1180     case glslang::ElfRg8:           return spv::ImageFormatRg8;
1181     case glslang::ElfR16:           return spv::ImageFormatR16;
1182     case glslang::ElfR8:            return spv::ImageFormatR8;
1183     case glslang::ElfRgba16Snorm:   return spv::ImageFormatRgba16Snorm;
1184     case glslang::ElfRg16Snorm:     return spv::ImageFormatRg16Snorm;
1185     case glslang::ElfRg8Snorm:      return spv::ImageFormatRg8Snorm;
1186     case glslang::ElfR16Snorm:      return spv::ImageFormatR16Snorm;
1187     case glslang::ElfR8Snorm:       return spv::ImageFormatR8Snorm;
1188     case glslang::ElfRgba32i:       return spv::ImageFormatRgba32i;
1189     case glslang::ElfRgba16i:       return spv::ImageFormatRgba16i;
1190     case glslang::ElfRgba8i:        return spv::ImageFormatRgba8i;
1191     case glslang::ElfR32i:          return spv::ImageFormatR32i;
1192     case glslang::ElfRg32i:         return spv::ImageFormatRg32i;
1193     case glslang::ElfRg16i:         return spv::ImageFormatRg16i;
1194     case glslang::ElfRg8i:          return spv::ImageFormatRg8i;
1195     case glslang::ElfR16i:          return spv::ImageFormatR16i;
1196     case glslang::ElfR8i:           return spv::ImageFormatR8i;
1197     case glslang::ElfRgba32ui:      return spv::ImageFormatRgba32ui;
1198     case glslang::ElfRgba16ui:      return spv::ImageFormatRgba16ui;
1199     case glslang::ElfRgba8ui:       return spv::ImageFormatRgba8ui;
1200     case glslang::ElfR32ui:         return spv::ImageFormatR32ui;
1201     case glslang::ElfRg32ui:        return spv::ImageFormatRg32ui;
1202     case glslang::ElfRg16ui:        return spv::ImageFormatRg16ui;
1203     case glslang::ElfRgb10a2ui:     return spv::ImageFormatRgb10a2ui;
1204     case glslang::ElfRg8ui:         return spv::ImageFormatRg8ui;
1205     case glslang::ElfR16ui:         return spv::ImageFormatR16ui;
1206     case glslang::ElfR8ui:          return spv::ImageFormatR8ui;
1207     case glslang::ElfR64ui:         return spv::ImageFormatR64ui;
1208     case glslang::ElfR64i:          return spv::ImageFormatR64i;
1209     default:                        return spv::ImageFormatMax;
1210     }
1211 }
1212 
TranslateSelectionControl(const glslang::TIntermSelection & selectionNode) const1213 spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(
1214     const glslang::TIntermSelection& selectionNode) const
1215 {
1216     if (selectionNode.getFlatten())
1217         return spv::SelectionControlFlattenMask;
1218     if (selectionNode.getDontFlatten())
1219         return spv::SelectionControlDontFlattenMask;
1220     return spv::SelectionControlMaskNone;
1221 }
1222 
TranslateSwitchControl(const glslang::TIntermSwitch & switchNode) const1223 spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode)
1224     const
1225 {
1226     if (switchNode.getFlatten())
1227         return spv::SelectionControlFlattenMask;
1228     if (switchNode.getDontFlatten())
1229         return spv::SelectionControlDontFlattenMask;
1230     return spv::SelectionControlMaskNone;
1231 }
1232 
1233 // return a non-0 dependency if the dependency argument must be set
TranslateLoopControl(const glslang::TIntermLoop & loopNode,std::vector<unsigned int> & operands) const1234 spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
1235     std::vector<unsigned int>& operands) const
1236 {
1237     spv::LoopControlMask control = spv::LoopControlMaskNone;
1238 
1239     if (loopNode.getDontUnroll())
1240         control = control | spv::LoopControlDontUnrollMask;
1241     if (loopNode.getUnroll())
1242         control = control | spv::LoopControlUnrollMask;
1243     if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite)
1244         control = control | spv::LoopControlDependencyInfiniteMask;
1245     else if (loopNode.getLoopDependency() > 0) {
1246         control = control | spv::LoopControlDependencyLengthMask;
1247         operands.push_back((unsigned int)loopNode.getLoopDependency());
1248     }
1249     if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
1250         if (loopNode.getMinIterations() > 0) {
1251             control = control | spv::LoopControlMinIterationsMask;
1252             operands.push_back(loopNode.getMinIterations());
1253         }
1254         if (loopNode.getMaxIterations() < glslang::TIntermLoop::iterationsInfinite) {
1255             control = control | spv::LoopControlMaxIterationsMask;
1256             operands.push_back(loopNode.getMaxIterations());
1257         }
1258         if (loopNode.getIterationMultiple() > 1) {
1259             control = control | spv::LoopControlIterationMultipleMask;
1260             operands.push_back(loopNode.getIterationMultiple());
1261         }
1262         if (loopNode.getPeelCount() > 0) {
1263             control = control | spv::LoopControlPeelCountMask;
1264             operands.push_back(loopNode.getPeelCount());
1265         }
1266         if (loopNode.getPartialCount() > 0) {
1267             control = control | spv::LoopControlPartialCountMask;
1268             operands.push_back(loopNode.getPartialCount());
1269         }
1270     }
1271 
1272     return control;
1273 }
1274 
1275 // Translate glslang type to SPIR-V storage class.
TranslateStorageClass(const glslang::TType & type)1276 spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type)
1277 {
1278     if (type.getBasicType() == glslang::EbtRayQuery || type.getBasicType() == glslang::EbtHitObjectNV)
1279         return spv::StorageClassPrivate;
1280     if (type.getQualifier().isSpirvByReference()) {
1281         if (type.getQualifier().isParamInput() || type.getQualifier().isParamOutput())
1282             return spv::StorageClassFunction;
1283     }
1284     if (type.getQualifier().isPipeInput())
1285         return spv::StorageClassInput;
1286     if (type.getQualifier().isPipeOutput())
1287         return spv::StorageClassOutput;
1288     if (type.getQualifier().storage == glslang::EvqTileImageEXT || type.isAttachmentEXT()) {
1289         builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1290         builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT);
1291         return spv::StorageClassTileImageEXT;
1292     }
1293 
1294     if (glslangIntermediate->getSource() != glslang::EShSourceHlsl ||
1295             type.getQualifier().storage == glslang::EvqUniform) {
1296         if (type.isAtomic())
1297             return spv::StorageClassAtomicCounter;
1298         if (type.containsOpaque() && !glslangIntermediate->getBindlessMode())
1299             return spv::StorageClassUniformConstant;
1300     }
1301 
1302     if (type.getQualifier().isUniformOrBuffer() &&
1303         type.getQualifier().isShaderRecord()) {
1304         return spv::StorageClassShaderRecordBufferKHR;
1305     }
1306 
1307     if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) {
1308         builder.addIncorporatedExtension(spv::E_SPV_KHR_storage_buffer_storage_class, spv::Spv_1_3);
1309         return spv::StorageClassStorageBuffer;
1310     }
1311 
1312     if (type.getQualifier().isUniformOrBuffer()) {
1313         if (type.getQualifier().isPushConstant())
1314             return spv::StorageClassPushConstant;
1315         if (type.getBasicType() == glslang::EbtBlock)
1316             return spv::StorageClassUniform;
1317         return spv::StorageClassUniformConstant;
1318     }
1319 
1320     if (type.getQualifier().storage == glslang::EvqShared && type.getBasicType() == glslang::EbtBlock) {
1321         builder.addExtension(spv::E_SPV_KHR_workgroup_memory_explicit_layout);
1322         builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR);
1323         return spv::StorageClassWorkgroup;
1324     }
1325 
1326     switch (type.getQualifier().storage) {
1327     case glslang::EvqGlobal:        return spv::StorageClassPrivate;
1328     case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
1329     case glslang::EvqTemporary:     return spv::StorageClassFunction;
1330     case glslang::EvqShared:           return spv::StorageClassWorkgroup;
1331     case glslang::EvqPayload:        return spv::StorageClassRayPayloadKHR;
1332     case glslang::EvqPayloadIn:      return spv::StorageClassIncomingRayPayloadKHR;
1333     case glslang::EvqHitAttr:        return spv::StorageClassHitAttributeKHR;
1334     case glslang::EvqCallableData:   return spv::StorageClassCallableDataKHR;
1335     case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR;
1336     case glslang::EvqtaskPayloadSharedEXT : return spv::StorageClassTaskPayloadWorkgroupEXT;
1337     case glslang::EvqHitObjectAttrNV: return spv::StorageClassHitObjectAttributeNV;
1338     case glslang::EvqSpirvStorageClass: return static_cast<spv::StorageClass>(type.getQualifier().spirvStorageClass);
1339     default:
1340         assert(0);
1341         break;
1342     }
1343 
1344     return spv::StorageClassFunction;
1345 }
1346 
1347 // Translate glslang constants to SPIR-V literals
TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion * > & constants,std::vector<unsigned> & literals) const1348 void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>& constants,
1349                                                std::vector<unsigned>& literals) const
1350 {
1351     for (auto constant : constants) {
1352         if (constant->getBasicType() == glslang::EbtFloat) {
1353             float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());
1354             unsigned literal;
1355             static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");
1356             memcpy(&literal, &floatValue, sizeof(literal));
1357             literals.push_back(literal);
1358         } else if (constant->getBasicType() == glslang::EbtInt) {
1359             unsigned literal = constant->getConstArray()[0].getIConst();
1360             literals.push_back(literal);
1361         } else if (constant->getBasicType() == glslang::EbtUint) {
1362             unsigned literal = constant->getConstArray()[0].getUConst();
1363             literals.push_back(literal);
1364         } else if (constant->getBasicType() == glslang::EbtBool) {
1365             unsigned literal = constant->getConstArray()[0].getBConst();
1366             literals.push_back(literal);
1367         } else if (constant->getBasicType() == glslang::EbtString) {
1368             auto str = constant->getConstArray()[0].getSConst()->c_str();
1369             unsigned literal = 0;
1370             char* literalPtr = reinterpret_cast<char*>(&literal);
1371             unsigned charCount = 0;
1372             char ch = 0;
1373             do {
1374                 ch = *(str++);
1375                 *(literalPtr++) = ch;
1376                 ++charCount;
1377                 if (charCount == 4) {
1378                     literals.push_back(literal);
1379                     literalPtr = reinterpret_cast<char*>(&literal);
1380                     charCount = 0;
1381                 }
1382             } while (ch != 0);
1383 
1384             // Partial literal is padded with 0
1385             if (charCount > 0) {
1386                 for (; charCount < 4; ++charCount)
1387                     *(literalPtr++) = 0;
1388                 literals.push_back(literal);
1389             }
1390         } else
1391             assert(0); // Unexpected type
1392     }
1393 }
1394 
1395 // Add capabilities pertaining to how an array is indexed.
addIndirectionIndexCapabilities(const glslang::TType & baseType,const glslang::TType & indexType)1396 void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType,
1397                                                              const glslang::TType& indexType)
1398 {
1399     if (indexType.getQualifier().isNonUniform()) {
1400         // deal with an asserted non-uniform index
1401         // SPV_EXT_descriptor_indexing already added in TranslateNonUniformDecoration
1402         if (baseType.getBasicType() == glslang::EbtSampler) {
1403             if (baseType.getQualifier().hasAttachment())
1404                 builder.addCapability(spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT);
1405             else if (baseType.isImage() && baseType.getSampler().isBuffer())
1406                 builder.addCapability(spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT);
1407             else if (baseType.isTexture() && baseType.getSampler().isBuffer())
1408                 builder.addCapability(spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT);
1409             else if (baseType.isImage())
1410                 builder.addCapability(spv::CapabilityStorageImageArrayNonUniformIndexingEXT);
1411             else if (baseType.isTexture())
1412                 builder.addCapability(spv::CapabilitySampledImageArrayNonUniformIndexingEXT);
1413         } else if (baseType.getBasicType() == glslang::EbtBlock) {
1414             if (baseType.getQualifier().storage == glslang::EvqBuffer)
1415                 builder.addCapability(spv::CapabilityStorageBufferArrayNonUniformIndexingEXT);
1416             else if (baseType.getQualifier().storage == glslang::EvqUniform)
1417                 builder.addCapability(spv::CapabilityUniformBufferArrayNonUniformIndexingEXT);
1418         }
1419     } else {
1420         // assume a dynamically uniform index
1421         if (baseType.getBasicType() == glslang::EbtSampler) {
1422             if (baseType.getQualifier().hasAttachment()) {
1423                 builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1424                 builder.addCapability(spv::CapabilityInputAttachmentArrayDynamicIndexingEXT);
1425             } else if (baseType.isImage() && baseType.getSampler().isBuffer()) {
1426                 builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1427                 builder.addCapability(spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT);
1428             } else if (baseType.isTexture() && baseType.getSampler().isBuffer()) {
1429                 builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1430                 builder.addCapability(spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT);
1431             }
1432         }
1433     }
1434 }
1435 
1436 // Return whether or not the given type is something that should be tied to a
1437 // descriptor set.
IsDescriptorResource(const glslang::TType & type)1438 bool IsDescriptorResource(const glslang::TType& type)
1439 {
1440     // uniform and buffer blocks are included, unless it is a push_constant
1441     if (type.getBasicType() == glslang::EbtBlock)
1442         return type.getQualifier().isUniformOrBuffer() &&
1443         ! type.getQualifier().isShaderRecord() &&
1444         ! type.getQualifier().isPushConstant();
1445 
1446     // non block...
1447     // basically samplerXXX/subpass/sampler/texture are all included
1448     // if they are the global-scope-class, not the function parameter
1449     // (or local, if they ever exist) class.
1450     if (type.getBasicType() == glslang::EbtSampler ||
1451         type.getBasicType() == glslang::EbtAccStruct)
1452         return type.getQualifier().isUniformOrBuffer();
1453 
1454     // None of the above.
1455     return false;
1456 }
1457 
InheritQualifiers(glslang::TQualifier & child,const glslang::TQualifier & parent)1458 void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
1459 {
1460     if (child.layoutMatrix == glslang::ElmNone)
1461         child.layoutMatrix = parent.layoutMatrix;
1462 
1463     if (parent.invariant)
1464         child.invariant = true;
1465     if (parent.flat)
1466         child.flat = true;
1467     if (parent.centroid)
1468         child.centroid = true;
1469     if (parent.nopersp)
1470         child.nopersp = true;
1471     if (parent.explicitInterp)
1472         child.explicitInterp = true;
1473     if (parent.perPrimitiveNV)
1474         child.perPrimitiveNV = true;
1475     if (parent.perViewNV)
1476         child.perViewNV = true;
1477     if (parent.perTaskNV)
1478         child.perTaskNV = true;
1479     if (parent.storage == glslang::EvqtaskPayloadSharedEXT)
1480         child.storage = glslang::EvqtaskPayloadSharedEXT;
1481     if (parent.patch)
1482         child.patch = true;
1483     if (parent.sample)
1484         child.sample = true;
1485     if (parent.coherent)
1486         child.coherent = true;
1487     if (parent.devicecoherent)
1488         child.devicecoherent = true;
1489     if (parent.queuefamilycoherent)
1490         child.queuefamilycoherent = true;
1491     if (parent.workgroupcoherent)
1492         child.workgroupcoherent = true;
1493     if (parent.subgroupcoherent)
1494         child.subgroupcoherent = true;
1495     if (parent.shadercallcoherent)
1496         child.shadercallcoherent = true;
1497     if (parent.nonprivate)
1498         child.nonprivate = true;
1499     if (parent.volatil)
1500         child.volatil = true;
1501     if (parent.restrict)
1502         child.restrict = true;
1503     if (parent.readonly)
1504         child.readonly = true;
1505     if (parent.writeonly)
1506         child.writeonly = true;
1507     if (parent.nonUniform)
1508         child.nonUniform = true;
1509 }
1510 
HasNonLayoutQualifiers(const glslang::TType & type,const glslang::TQualifier & qualifier)1511 bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)
1512 {
1513     // This should list qualifiers that simultaneous satisfy:
1514     // - struct members might inherit from a struct declaration
1515     //     (note that non-block structs don't explicitly inherit,
1516     //      only implicitly, meaning no decoration involved)
1517     // - affect decorations on the struct members
1518     //     (note smooth does not, and expecting something like volatile
1519     //      to effect the whole object)
1520     // - are not part of the offset/st430/etc or row/column-major layout
1521     return qualifier.invariant || (qualifier.hasLocation() && type.getBasicType() == glslang::EbtBlock);
1522 }
1523 
1524 //
1525 // Implement the TGlslangToSpvTraverser class.
1526 //
1527 
TGlslangToSpvTraverser(unsigned int spvVersion,const glslang::TIntermediate * glslangIntermediate,spv::SpvBuildLogger * buildLogger,glslang::SpvOptions & options)1528 TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
1529     const glslang::TIntermediate* glslangIntermediate,
1530     spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) :
1531         TIntermTraverser(true, false, true),
1532         options(options),
1533         shaderEntry(nullptr), currentFunction(nullptr),
1534         sequenceDepth(0), logger(buildLogger),
1535         builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
1536         inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
1537         glslangIntermediate(glslangIntermediate),
1538         nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()),
1539         nonSemanticDebugPrintf(0),
1540         taskPayloadID(0)
1541 {
1542     bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=
1543                             glslangIntermediate->getRequestedExtensions().end());
1544     spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage(), isMeshShaderExt);
1545 
1546     builder.clearAccessChain();
1547     builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),
1548                       glslangIntermediate->getVersion());
1549 
1550     if (options.emitNonSemanticShaderDebugSource)
1551             this->options.emitNonSemanticShaderDebugInfo = true;
1552     if (options.emitNonSemanticShaderDebugInfo)
1553             this->options.generateDebugInfo = true;
1554 
1555     if (this->options.generateDebugInfo) {
1556         if (this->options.emitNonSemanticShaderDebugInfo) {
1557             builder.setEmitNonSemanticShaderDebugInfo(this->options.emitNonSemanticShaderDebugSource);
1558         }
1559         else {
1560             builder.setEmitSpirvDebugInfo();
1561         }
1562         builder.setDebugMainSourceFile(glslangIntermediate->getSourceFile());
1563 
1564         // Set the source shader's text. If for SPV version 1.0, include
1565         // a preamble in comments stating the OpModuleProcessed instructions.
1566         // Otherwise, emit those as actual instructions.
1567         std::string text;
1568         const std::vector<std::string>& processes = glslangIntermediate->getProcesses();
1569         for (int p = 0; p < (int)processes.size(); ++p) {
1570             if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1) {
1571                 text.append("// OpModuleProcessed ");
1572                 text.append(processes[p]);
1573                 text.append("\n");
1574             } else
1575                 builder.addModuleProcessed(processes[p]);
1576         }
1577         if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1 && (int)processes.size() > 0)
1578             text.append("#line 1\n");
1579         text.append(glslangIntermediate->getSourceText());
1580         builder.setSourceText(text);
1581         // Pass name and text for all included files
1582         const std::map<std::string, std::string>& include_txt = glslangIntermediate->getIncludeText();
1583         for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr)
1584             builder.addInclude(iItr->first, iItr->second);
1585     }
1586 
1587     builder.setUseReplicatedComposites(glslangIntermediate->usingReplicatedComposites());
1588 
1589     stdBuiltins = builder.import("GLSL.std.450");
1590 
1591     spv::AddressingModel addressingModel = spv::AddressingModelLogical;
1592     spv::MemoryModel memoryModel = spv::MemoryModelGLSL450;
1593 
1594     if (glslangIntermediate->usingPhysicalStorageBuffer()) {
1595         addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;
1596         builder.addIncorporatedExtension(spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5);
1597         builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);
1598     }
1599     if (glslangIntermediate->usingVulkanMemoryModel()) {
1600         memoryModel = spv::MemoryModelVulkanKHR;
1601         builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
1602         builder.addIncorporatedExtension(spv::E_SPV_KHR_vulkan_memory_model, spv::Spv_1_5);
1603     }
1604     builder.setMemoryModel(addressingModel, memoryModel);
1605 
1606     if (glslangIntermediate->usingVariablePointers()) {
1607         builder.addCapability(spv::CapabilityVariablePointers);
1608     }
1609 
1610     // If not linking, there is no entry point
1611     if (!options.compileOnly) {
1612         shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
1613         entryPoint =
1614             builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
1615     }
1616 
1617     // Add the source extensions
1618     const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
1619     for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
1620         builder.addSourceExtension(it->c_str());
1621 
1622     // Add the top-level modes for this shader.
1623 
1624     if (glslangIntermediate->getXfbMode()) {
1625         builder.addCapability(spv::CapabilityTransformFeedback);
1626         builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
1627     }
1628 
1629     if (glslangIntermediate->getLayoutPrimitiveCulling()) {
1630         builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR);
1631     }
1632 
1633     if (glslangIntermediate->getSubgroupUniformControlFlow()) {
1634         builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow);
1635         builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR);
1636     }
1637     if (glslangIntermediate->getMaximallyReconverges()) {
1638         builder.addExtension(spv::E_SPV_KHR_maximal_reconvergence);
1639         builder.addExecutionMode(shaderEntry, spv::ExecutionModeMaximallyReconvergesKHR);
1640     }
1641 
1642     if (glslangIntermediate->getQuadDerivMode())
1643     {
1644         builder.addCapability(spv::CapabilityQuadControlKHR);
1645         builder.addExtension(spv::E_SPV_KHR_quad_control);
1646         builder.addExecutionMode(shaderEntry, spv::ExecutionModeQuadDerivativesKHR);
1647     }
1648 
1649     if (glslangIntermediate->getReqFullQuadsMode())
1650     {
1651         builder.addCapability(spv::CapabilityQuadControlKHR);
1652         builder.addExtension(spv::E_SPV_KHR_quad_control);
1653         builder.addExecutionMode(shaderEntry, spv::ExecutionModeRequireFullQuadsKHR);
1654     }
1655 
1656     unsigned int mode;
1657     switch (glslangIntermediate->getStage()) {
1658     case EShLangVertex:
1659         builder.addCapability(spv::CapabilityShader);
1660         break;
1661 
1662     case EShLangFragment:
1663         builder.addCapability(spv::CapabilityShader);
1664         if (glslangIntermediate->getPixelCenterInteger())
1665             builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
1666 
1667         if (glslangIntermediate->getOriginUpperLeft())
1668             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
1669         else
1670             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);
1671 
1672         if (glslangIntermediate->getEarlyFragmentTests())
1673             builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
1674 
1675         if (glslangIntermediate->getEarlyAndLateFragmentTestsAMD())
1676         {
1677             builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyAndLateFragmentTestsAMD);
1678             builder.addExtension(spv::E_SPV_AMD_shader_early_and_late_fragment_tests);
1679         }
1680 
1681         if (glslangIntermediate->getPostDepthCoverage()) {
1682             builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage);
1683             builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage);
1684             builder.addExtension(spv::E_SPV_KHR_post_depth_coverage);
1685         }
1686 
1687         if (glslangIntermediate->getNonCoherentColorAttachmentReadEXT()) {
1688             builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT);
1689             builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentColorAttachmentReadEXT);
1690             builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1691         }
1692 
1693         if (glslangIntermediate->getNonCoherentDepthAttachmentReadEXT()) {
1694             builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);
1695             builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentDepthAttachmentReadEXT);
1696             builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1697         }
1698 
1699         if (glslangIntermediate->getNonCoherentStencilAttachmentReadEXT()) {
1700             builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);
1701             builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentStencilAttachmentReadEXT);
1702             builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1703         }
1704 
1705         if (glslangIntermediate->isDepthReplacing())
1706             builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);
1707 
1708         if (glslangIntermediate->isStencilReplacing())
1709             builder.addExecutionMode(shaderEntry, spv::ExecutionModeStencilRefReplacingEXT);
1710 
1711         switch(glslangIntermediate->getDepth()) {
1712         case glslang::EldGreater:   mode = spv::ExecutionModeDepthGreater;   break;
1713         case glslang::EldLess:      mode = spv::ExecutionModeDepthLess;      break;
1714         case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break;
1715         default:                    mode = spv::ExecutionModeMax;            break;
1716         }
1717 
1718         if (mode != spv::ExecutionModeMax)
1719             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1720 
1721         switch (glslangIntermediate->getStencil()) {
1722         case glslang::ElsRefUnchangedFrontAMD:  mode = spv::ExecutionModeStencilRefUnchangedFrontAMD; break;
1723         case glslang::ElsRefGreaterFrontAMD:    mode = spv::ExecutionModeStencilRefGreaterFrontAMD;   break;
1724         case glslang::ElsRefLessFrontAMD:       mode = spv::ExecutionModeStencilRefLessFrontAMD;      break;
1725         case glslang::ElsRefUnchangedBackAMD:   mode = spv::ExecutionModeStencilRefUnchangedBackAMD;  break;
1726         case glslang::ElsRefGreaterBackAMD:     mode = spv::ExecutionModeStencilRefGreaterBackAMD;    break;
1727         case glslang::ElsRefLessBackAMD:        mode = spv::ExecutionModeStencilRefLessBackAMD;       break;
1728         default:                       mode = spv::ExecutionModeMax;                         break;
1729         }
1730 
1731         if (mode != spv::ExecutionModeMax)
1732             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1733         switch (glslangIntermediate->getInterlockOrdering()) {
1734         case glslang::EioPixelInterlockOrdered:         mode = spv::ExecutionModePixelInterlockOrderedEXT;
1735             break;
1736         case glslang::EioPixelInterlockUnordered:       mode = spv::ExecutionModePixelInterlockUnorderedEXT;
1737             break;
1738         case glslang::EioSampleInterlockOrdered:        mode = spv::ExecutionModeSampleInterlockOrderedEXT;
1739             break;
1740         case glslang::EioSampleInterlockUnordered:      mode = spv::ExecutionModeSampleInterlockUnorderedEXT;
1741             break;
1742         case glslang::EioShadingRateInterlockOrdered:   mode = spv::ExecutionModeShadingRateInterlockOrderedEXT;
1743             break;
1744         case glslang::EioShadingRateInterlockUnordered: mode = spv::ExecutionModeShadingRateInterlockUnorderedEXT;
1745             break;
1746         default:                                        mode = spv::ExecutionModeMax;
1747             break;
1748         }
1749         if (mode != spv::ExecutionModeMax) {
1750             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1751             if (mode == spv::ExecutionModeShadingRateInterlockOrderedEXT ||
1752                 mode == spv::ExecutionModeShadingRateInterlockUnorderedEXT) {
1753                 builder.addCapability(spv::CapabilityFragmentShaderShadingRateInterlockEXT);
1754             } else if (mode == spv::ExecutionModePixelInterlockOrderedEXT ||
1755                        mode == spv::ExecutionModePixelInterlockUnorderedEXT) {
1756                 builder.addCapability(spv::CapabilityFragmentShaderPixelInterlockEXT);
1757             } else {
1758                 builder.addCapability(spv::CapabilityFragmentShaderSampleInterlockEXT);
1759             }
1760             builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
1761         }
1762     break;
1763 
1764     case EShLangCompute: {
1765         builder.addCapability(spv::CapabilityShader);
1766         bool needSizeId = false;
1767         for (int dim = 0; dim < 3; ++dim) {
1768             if ((glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet)) {
1769                 needSizeId = true;
1770                 break;
1771             }
1772         }
1773         if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 && needSizeId) {
1774             std::vector<spv::Id> dimConstId;
1775             for (int dim = 0; dim < 3; ++dim) {
1776                 bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
1777                 dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
1778                 if (specConst) {
1779                     builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
1780                                           glslangIntermediate->getLocalSizeSpecId(dim));
1781                     needSizeId = true;
1782                 }
1783             }
1784             builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId);
1785         } else {
1786             builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
1787                                                                                glslangIntermediate->getLocalSize(1),
1788                                                                                glslangIntermediate->getLocalSize(2));
1789         }
1790         if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupQuads) {
1791             builder.addCapability(spv::CapabilityComputeDerivativeGroupQuadsNV);
1792             builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupQuadsNV);
1793             builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
1794         } else if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupLinear) {
1795             builder.addCapability(spv::CapabilityComputeDerivativeGroupLinearNV);
1796             builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupLinearNV);
1797             builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
1798         }
1799         break;
1800     }
1801     case EShLangTessEvaluation:
1802     case EShLangTessControl:
1803         builder.addCapability(spv::CapabilityTessellation);
1804 
1805         glslang::TLayoutGeometry primitive;
1806 
1807         if (glslangIntermediate->getStage() == EShLangTessControl) {
1808             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,
1809                 glslangIntermediate->getVertices());
1810             primitive = glslangIntermediate->getOutputPrimitive();
1811         } else {
1812             primitive = glslangIntermediate->getInputPrimitive();
1813         }
1814 
1815         switch (primitive) {
1816         case glslang::ElgTriangles:           mode = spv::ExecutionModeTriangles;     break;
1817         case glslang::ElgQuads:               mode = spv::ExecutionModeQuads;         break;
1818         case glslang::ElgIsolines:            mode = spv::ExecutionModeIsolines;      break;
1819         default:                              mode = spv::ExecutionModeMax;           break;
1820         }
1821         if (mode != spv::ExecutionModeMax)
1822             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1823 
1824         switch (glslangIntermediate->getVertexSpacing()) {
1825         case glslang::EvsEqual:            mode = spv::ExecutionModeSpacingEqual;          break;
1826         case glslang::EvsFractionalEven:   mode = spv::ExecutionModeSpacingFractionalEven; break;
1827         case glslang::EvsFractionalOdd:    mode = spv::ExecutionModeSpacingFractionalOdd;  break;
1828         default:                           mode = spv::ExecutionModeMax;                   break;
1829         }
1830         if (mode != spv::ExecutionModeMax)
1831             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1832 
1833         switch (glslangIntermediate->getVertexOrder()) {
1834         case glslang::EvoCw:     mode = spv::ExecutionModeVertexOrderCw;  break;
1835         case glslang::EvoCcw:    mode = spv::ExecutionModeVertexOrderCcw; break;
1836         default:                 mode = spv::ExecutionModeMax;            break;
1837         }
1838         if (mode != spv::ExecutionModeMax)
1839             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1840 
1841         if (glslangIntermediate->getPointMode())
1842             builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode);
1843         break;
1844 
1845     case EShLangGeometry:
1846         builder.addCapability(spv::CapabilityGeometry);
1847         switch (glslangIntermediate->getInputPrimitive()) {
1848         case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;
1849         case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;
1850         case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;
1851         case glslang::ElgTriangles:          mode = spv::ExecutionModeTriangles;               break;
1852         case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
1853         default:                             mode = spv::ExecutionModeMax;                     break;
1854         }
1855         if (mode != spv::ExecutionModeMax)
1856             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1857 
1858         builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
1859 
1860         switch (glslangIntermediate->getOutputPrimitive()) {
1861         case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;
1862         case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;
1863         case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;
1864         default:                        mode = spv::ExecutionModeMax;                          break;
1865         }
1866         if (mode != spv::ExecutionModeMax)
1867             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1868         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
1869         break;
1870 
1871     case EShLangRayGen:
1872     case EShLangIntersect:
1873     case EShLangAnyHit:
1874     case EShLangClosestHit:
1875     case EShLangMiss:
1876     case EShLangCallable:
1877     {
1878         auto& extensions = glslangIntermediate->getRequestedExtensions();
1879         if (extensions.find("GL_NV_ray_tracing") == extensions.end()) {
1880             builder.addCapability(spv::CapabilityRayTracingKHR);
1881             builder.addExtension("SPV_KHR_ray_tracing");
1882         }
1883         else {
1884             builder.addCapability(spv::CapabilityRayTracingNV);
1885             builder.addExtension("SPV_NV_ray_tracing");
1886         }
1887         if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) {
1888             if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) {
1889                 builder.addCapability(spv::CapabilityRayCullMaskKHR);
1890                 builder.addExtension("SPV_KHR_ray_cull_mask");
1891             }
1892             if (extensions.find("GL_EXT_ray_tracing_position_fetch") != extensions.end()) {
1893                 builder.addCapability(spv::CapabilityRayTracingPositionFetchKHR);
1894                 builder.addExtension("SPV_KHR_ray_tracing_position_fetch");
1895             }
1896         }
1897         break;
1898     }
1899     case EShLangTask:
1900     case EShLangMesh:
1901         if(isMeshShaderExt) {
1902             builder.addCapability(spv::CapabilityMeshShadingEXT);
1903             builder.addExtension(spv::E_SPV_EXT_mesh_shader);
1904         } else {
1905             builder.addCapability(spv::CapabilityMeshShadingNV);
1906             builder.addExtension(spv::E_SPV_NV_mesh_shader);
1907         }
1908         if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
1909             std::vector<spv::Id> dimConstId;
1910             for (int dim = 0; dim < 3; ++dim) {
1911                 bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
1912                 dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
1913                 if (specConst) {
1914                     builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
1915                                           glslangIntermediate->getLocalSizeSpecId(dim));
1916                 }
1917             }
1918             builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId);
1919         } else {
1920             builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
1921                                                                                glslangIntermediate->getLocalSize(1),
1922                                                                                glslangIntermediate->getLocalSize(2));
1923         }
1924         if (glslangIntermediate->getStage() == EShLangMesh) {
1925             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,
1926                 glslangIntermediate->getVertices());
1927             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV,
1928                 glslangIntermediate->getPrimitives());
1929 
1930             switch (glslangIntermediate->getOutputPrimitive()) {
1931             case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;      break;
1932             case glslang::ElgLines:         mode = spv::ExecutionModeOutputLinesNV;     break;
1933             case glslang::ElgTriangles:     mode = spv::ExecutionModeOutputTrianglesNV; break;
1934             default:                        mode = spv::ExecutionModeMax;               break;
1935             }
1936             if (mode != spv::ExecutionModeMax)
1937                 builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1938         }
1939         break;
1940 
1941     default:
1942         break;
1943     }
1944 
1945     //
1946     // Add SPIR-V requirements (GL_EXT_spirv_intrinsics)
1947     //
1948     if (glslangIntermediate->hasSpirvRequirement()) {
1949         const glslang::TSpirvRequirement& spirvRequirement = glslangIntermediate->getSpirvRequirement();
1950 
1951         // Add SPIR-V extension requirement
1952         for (auto& extension : spirvRequirement.extensions)
1953             builder.addExtension(extension.c_str());
1954 
1955         // Add SPIR-V capability requirement
1956         for (auto capability : spirvRequirement.capabilities)
1957             builder.addCapability(static_cast<spv::Capability>(capability));
1958     }
1959 
1960     //
1961     // Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics)
1962     //
1963     if (glslangIntermediate->hasSpirvExecutionMode()) {
1964         const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate->getSpirvExecutionMode();
1965 
1966         // Add spirv_execution_mode
1967         for (auto& mode : spirvExecutionMode.modes) {
1968             if (!mode.second.empty()) {
1969                 std::vector<unsigned> literals;
1970                 TranslateLiterals(mode.second, literals);
1971                 builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first), literals);
1972             } else
1973                 builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first));
1974         }
1975 
1976         // Add spirv_execution_mode_id
1977         for (auto& modeId : spirvExecutionMode.modeIds) {
1978             std::vector<spv::Id> operandIds;
1979             assert(!modeId.second.empty());
1980             for (auto extraOperand : modeId.second) {
1981                 if (extraOperand->getType().getQualifier().isSpecConstant())
1982                     operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));
1983                 else
1984                     operandIds.push_back(createSpvConstant(*extraOperand));
1985             }
1986             builder.addExecutionModeId(shaderEntry, static_cast<spv::ExecutionMode>(modeId.first), operandIds);
1987         }
1988     }
1989 }
1990 
1991 // Finish creating SPV, after the traversal is complete.
finishSpv(bool compileOnly)1992 void TGlslangToSpvTraverser::finishSpv(bool compileOnly)
1993 {
1994     // If not linking, an entry point is not expected
1995     if (!compileOnly) {
1996         // Finish the entry point function
1997         if (!entryPointTerminated) {
1998             builder.setBuildPoint(shaderEntry->getLastBlock());
1999             builder.leaveFunction();
2000         }
2001 
2002         // finish off the entry-point SPV instruction by adding the Input/Output <id>
2003         entryPoint->reserveOperands(iOSet.size());
2004         for (auto id : iOSet)
2005             entryPoint->addIdOperand(id);
2006     }
2007 
2008     // Add capabilities, extensions, remove unneeded decorations, etc.,
2009     // based on the resulting SPIR-V.
2010     // Note: WebGPU code generation must have the opportunity to aggressively
2011     // prune unreachable merge blocks and continue targets.
2012     builder.postProcess(compileOnly);
2013 }
2014 
2015 // Write the SPV into 'out'.
dumpSpv(std::vector<unsigned int> & out)2016 void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
2017 {
2018     builder.dump(out);
2019 }
2020 
2021 //
2022 // Implement the traversal functions.
2023 //
2024 // Return true from interior nodes to have the external traversal
2025 // continue on to children.  Return false if children were
2026 // already processed.
2027 //
2028 
2029 //
2030 // Symbols can turn into
2031 //  - uniform/input reads
2032 //  - output writes
2033 //  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain
2034 //  - something simple that degenerates into the last bullet
2035 //
visitSymbol(glslang::TIntermSymbol * symbol)2036 void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
2037 {
2038     // We update the line information even though no code might be generated here
2039     // This is helpful to yield correct lines for control flow instructions
2040     if (!linkageOnly) {
2041         builder.setDebugSourceLocation(symbol->getLoc().line, symbol->getLoc().getFilename());
2042     }
2043 
2044     if (symbol->getBasicType() == glslang::EbtFunction) {
2045         return;
2046     }
2047 
2048     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2049     if (symbol->getType().isStruct())
2050         glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId();
2051 
2052     if (symbol->getType().getQualifier().isSpecConstant())
2053         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2054 #ifdef ENABLE_HLSL
2055     // Skip symbol handling if it is string-typed
2056     if (symbol->getBasicType() == glslang::EbtString)
2057         return;
2058 #endif
2059 
2060     // getSymbolId() will set up all the IO decorations on the first call.
2061     // Formal function parameters were mapped during makeFunctions().
2062     spv::Id id = getSymbolId(symbol);
2063 
2064     if (symbol->getType().getQualifier().isTaskPayload())
2065         taskPayloadID = id; // cache the taskPayloadID to be used it as operand for OpEmitMeshTasksEXT
2066 
2067     if (builder.isPointer(id)) {
2068         if (!symbol->getType().getQualifier().isParamInput() &&
2069             !symbol->getType().getQualifier().isParamOutput()) {
2070             // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
2071             // Consider adding to the OpEntryPoint interface list.
2072             // Only looking at structures if they have at least one member.
2073             if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) {
2074                 spv::StorageClass sc = builder.getStorageClass(id);
2075                 // Before SPIR-V 1.4, we only want to include Input and Output.
2076                 // Starting with SPIR-V 1.4, we want all globals.
2077                 if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalVariable(id)) ||
2078                     (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) {
2079                     iOSet.insert(id);
2080                 }
2081             }
2082         }
2083 
2084         // If the SPIR-V type is required to be different than the AST type
2085         // (for ex SubgroupMasks or 3x4 ObjectToWorld/WorldToObject matrices),
2086         // translate now from the SPIR-V type to the AST type, for the consuming
2087         // operation.
2088         // Note this turns it from an l-value to an r-value.
2089         // Currently, all symbols needing this are inputs; avoid the map lookup when non-input.
2090         if (symbol->getType().getQualifier().storage == glslang::EvqVaryingIn)
2091             id = translateForcedType(id);
2092     }
2093 
2094     // Only process non-linkage-only nodes for generating actual static uses
2095     if (! linkageOnly || symbol->getQualifier().isSpecConstant()) {
2096         // Prepare to generate code for the access
2097 
2098         // L-value chains will be computed left to right.  We're on the symbol now,
2099         // which is the left-most part of the access chain, so now is "clear" time,
2100         // followed by setting the base.
2101         builder.clearAccessChain();
2102 
2103         // For now, we consider all user variables as being in memory, so they are pointers,
2104         // except for
2105         // A) R-Value arguments to a function, which are an intermediate object.
2106         //    See comments in handleUserFunctionCall().
2107         // B) Specialization constants (normal constants don't even come in as a variable),
2108         //    These are also pure R-values.
2109         // C) R-Values from type translation, see above call to translateForcedType()
2110         glslang::TQualifier qualifier = symbol->getQualifier();
2111         if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end() ||
2112             !builder.isPointerType(builder.getTypeId(id)))
2113             builder.setAccessChainRValue(id);
2114         else
2115             builder.setAccessChainLValue(id);
2116     }
2117 
2118 #ifdef ENABLE_HLSL
2119     // Process linkage-only nodes for any special additional interface work.
2120     if (linkageOnly) {
2121         if (glslangIntermediate->getHlslFunctionality1()) {
2122             // Map implicit counter buffers to their originating buffers, which should have been
2123             // seen by now, given earlier pruning of unused counters, and preservation of order
2124             // of declaration.
2125             if (symbol->getType().getQualifier().isUniformOrBuffer()) {
2126                 if (!glslangIntermediate->hasCounterBufferName(symbol->getName())) {
2127                     // Save possible originating buffers for counter buffers, keyed by
2128                     // making the potential counter-buffer name.
2129                     std::string keyName = symbol->getName().c_str();
2130                     keyName = glslangIntermediate->addCounterBufferName(keyName);
2131                     counterOriginator[keyName] = symbol;
2132                 } else {
2133                     // Handle a counter buffer, by finding the saved originating buffer.
2134                     std::string keyName = symbol->getName().c_str();
2135                     auto it = counterOriginator.find(keyName);
2136                     if (it != counterOriginator.end()) {
2137                         id = getSymbolId(it->second);
2138                         if (id != spv::NoResult) {
2139                             spv::Id counterId = getSymbolId(symbol);
2140                             if (counterId != spv::NoResult) {
2141                                 builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
2142                                 builder.addDecorationId(id, spv::DecorationHlslCounterBufferGOOGLE, counterId);
2143                             }
2144                         }
2145                     }
2146                 }
2147             }
2148         }
2149     }
2150 #endif
2151 }
2152 
visitBinary(glslang::TVisit,glslang::TIntermBinary * node)2153 bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
2154 {
2155     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2156     if (node->getLeft()->getAsSymbolNode() != nullptr && node->getLeft()->getType().isStruct()) {
2157         glslangTypeToIdMap[node->getLeft()->getType().getStruct()] = node->getLeft()->getAsSymbolNode()->getId();
2158     }
2159     if (node->getRight()->getAsSymbolNode() != nullptr && node->getRight()->getType().isStruct()) {
2160         glslangTypeToIdMap[node->getRight()->getType().getStruct()] = node->getRight()->getAsSymbolNode()->getId();
2161     }
2162 
2163     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2164     if (node->getType().getQualifier().isSpecConstant())
2165         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2166 
2167     // First, handle special cases
2168     switch (node->getOp()) {
2169     case glslang::EOpAssign:
2170     case glslang::EOpAddAssign:
2171     case glslang::EOpSubAssign:
2172     case glslang::EOpMulAssign:
2173     case glslang::EOpVectorTimesMatrixAssign:
2174     case glslang::EOpVectorTimesScalarAssign:
2175     case glslang::EOpMatrixTimesScalarAssign:
2176     case glslang::EOpMatrixTimesMatrixAssign:
2177     case glslang::EOpDivAssign:
2178     case glslang::EOpModAssign:
2179     case glslang::EOpAndAssign:
2180     case glslang::EOpInclusiveOrAssign:
2181     case glslang::EOpExclusiveOrAssign:
2182     case glslang::EOpLeftShiftAssign:
2183     case glslang::EOpRightShiftAssign:
2184         // A bin-op assign "a += b" means the same thing as "a = a + b"
2185         // where a is evaluated before b. For a simple assignment, GLSL
2186         // says to evaluate the left before the right.  So, always, left
2187         // node then right node.
2188         {
2189             // get the left l-value, save it away
2190             builder.clearAccessChain();
2191             node->getLeft()->traverse(this);
2192             spv::Builder::AccessChain lValue = builder.getAccessChain();
2193 
2194             // evaluate the right
2195             builder.clearAccessChain();
2196             node->getRight()->traverse(this);
2197             spv::Id rValue = accessChainLoad(node->getRight()->getType());
2198 
2199             // reset line number for assignment
2200             builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2201 
2202             if (node->getOp() != glslang::EOpAssign) {
2203                 // the left is also an r-value
2204                 builder.setAccessChain(lValue);
2205                 spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
2206 
2207                 // do the operation
2208                 spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
2209                 coherentFlags |= TranslateCoherent(node->getRight()->getType());
2210                 OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2211                                               TranslateNoContractionDecoration(node->getType().getQualifier()),
2212                                               TranslateNonUniformDecoration(coherentFlags) };
2213                 rValue = createBinaryOperation(node->getOp(), decorations,
2214                                                convertGlslangToSpvType(node->getType()), leftRValue, rValue,
2215                                                node->getType().getBasicType());
2216 
2217                 // these all need their counterparts in createBinaryOperation()
2218                 assert(rValue != spv::NoResult);
2219             }
2220 
2221             // store the result
2222             builder.setAccessChain(lValue);
2223             multiTypeStore(node->getLeft()->getType(), rValue);
2224 
2225             // assignments are expressions having an rValue after they are evaluated...
2226             builder.clearAccessChain();
2227             builder.setAccessChainRValue(rValue);
2228         }
2229         return false;
2230     case glslang::EOpIndexDirect:
2231     case glslang::EOpIndexDirectStruct:
2232         {
2233             // Structure, array, matrix, or vector indirection with statically known index.
2234             // Get the left part of the access chain.
2235             node->getLeft()->traverse(this);
2236 
2237             // Add the next element in the chain
2238 
2239             const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
2240             if (! node->getLeft()->getType().isArray() &&
2241                 node->getLeft()->getType().isVector() &&
2242                 node->getOp() == glslang::EOpIndexDirect) {
2243                 // Swizzle is uniform so propagate uniform into access chain
2244                 spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
2245                 coherentFlags.nonUniform = 0;
2246                 // This is essentially a hard-coded vector swizzle of size 1,
2247                 // so short circuit the access-chain stuff with a swizzle.
2248                 std::vector<unsigned> swizzle;
2249                 swizzle.push_back(glslangIndex);
2250                 int dummySize;
2251                 builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
2252                                                coherentFlags,
2253                                                glslangIntermediate->getBaseAlignmentScalar(
2254                                                    node->getLeft()->getType(), dummySize));
2255             } else {
2256 
2257                 // Load through a block reference is performed with a dot operator that
2258                 // is mapped to EOpIndexDirectStruct. When we get to the actual reference,
2259                 // do a load and reset the access chain.
2260                 if (node->getLeft()->isReference() &&
2261                     !node->getLeft()->getType().isArray() &&
2262                     node->getOp() == glslang::EOpIndexDirectStruct)
2263                 {
2264                     spv::Id left = accessChainLoad(node->getLeft()->getType());
2265                     builder.clearAccessChain();
2266                     builder.setAccessChainLValue(left);
2267                 }
2268 
2269                 int spvIndex = glslangIndex;
2270                 if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
2271                     node->getOp() == glslang::EOpIndexDirectStruct)
2272                 {
2273                     // This may be, e.g., an anonymous block-member selection, which generally need
2274                     // index remapping due to hidden members in anonymous blocks.
2275                     long long glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()];
2276                     if (memberRemapper.find(glslangId) != memberRemapper.end()) {
2277                         std::vector<int>& remapper = memberRemapper[glslangId];
2278                         assert(remapper.size() > 0);
2279                         spvIndex = remapper[glslangIndex];
2280                     }
2281                 }
2282 
2283                 // Struct reference propagates uniform lvalue
2284                 spv::Builder::AccessChain::CoherentFlags coherentFlags =
2285                         TranslateCoherent(node->getLeft()->getType());
2286                 coherentFlags.nonUniform = 0;
2287 
2288                 // normal case for indexing array or structure or block
2289                 builder.accessChainPush(builder.makeIntConstant(spvIndex),
2290                         coherentFlags,
2291                         node->getLeft()->getType().getBufferReferenceAlignment());
2292 
2293                 // Add capabilities here for accessing PointSize and clip/cull distance.
2294                 // We have deferred generation of associated capabilities until now.
2295                 if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray())
2296                     declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex);
2297             }
2298         }
2299         return false;
2300     case glslang::EOpIndexIndirect:
2301         {
2302             // Array, matrix, or vector indirection with variable index.
2303             // Will use native SPIR-V access-chain for and array indirection;
2304             // matrices are arrays of vectors, so will also work for a matrix.
2305             // Will use the access chain's 'component' for variable index into a vector.
2306 
2307             // This adapter is building access chains left to right.
2308             // Set up the access chain to the left.
2309             node->getLeft()->traverse(this);
2310 
2311             // save it so that computing the right side doesn't trash it
2312             spv::Builder::AccessChain partial = builder.getAccessChain();
2313 
2314             // compute the next index in the chain
2315             builder.clearAccessChain();
2316             node->getRight()->traverse(this);
2317             spv::Id index = accessChainLoad(node->getRight()->getType());
2318 
2319             addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType());
2320 
2321             // restore the saved access chain
2322             builder.setAccessChain(partial);
2323 
2324             // Only if index is nonUniform should we propagate nonUniform into access chain
2325             spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType());
2326             spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType());
2327             coherent_flags.nonUniform = index_flags.nonUniform;
2328 
2329             if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
2330                 int dummySize;
2331                 builder.accessChainPushComponent(
2332                     index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags,
2333                                                 glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
2334                                                 dummySize));
2335             } else
2336                 builder.accessChainPush(index, coherent_flags,
2337                                         node->getLeft()->getType().getBufferReferenceAlignment());
2338         }
2339         return false;
2340     case glslang::EOpVectorSwizzle:
2341         {
2342             node->getLeft()->traverse(this);
2343             std::vector<unsigned> swizzle;
2344             convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);
2345             int dummySize;
2346             builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
2347                                            TranslateCoherent(node->getLeft()->getType()),
2348                                            glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
2349                                                dummySize));
2350         }
2351         return false;
2352     case glslang::EOpMatrixSwizzle:
2353         logger->missingFunctionality("matrix swizzle");
2354         return true;
2355     case glslang::EOpLogicalOr:
2356     case glslang::EOpLogicalAnd:
2357         {
2358 
2359             // These may require short circuiting, but can sometimes be done as straight
2360             // binary operations.  The right operand must be short circuited if it has
2361             // side effects, and should probably be if it is complex.
2362             if (isTrivial(node->getRight()->getAsTyped()))
2363                 break; // handle below as a normal binary operation
2364             // otherwise, we need to do dynamic short circuiting on the right operand
2365             spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(),
2366                 *node->getRight()->getAsTyped());
2367             builder.clearAccessChain();
2368             builder.setAccessChainRValue(result);
2369         }
2370         return false;
2371     default:
2372         break;
2373     }
2374 
2375     // Assume generic binary op...
2376 
2377     // get right operand
2378     builder.clearAccessChain();
2379     node->getLeft()->traverse(this);
2380     spv::Id left = accessChainLoad(node->getLeft()->getType());
2381 
2382     // get left operand
2383     builder.clearAccessChain();
2384     node->getRight()->traverse(this);
2385     spv::Id right = accessChainLoad(node->getRight()->getType());
2386 
2387     // get result
2388     OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2389                                   TranslateNoContractionDecoration(node->getType().getQualifier()),
2390                                   TranslateNonUniformDecoration(node->getType().getQualifier()) };
2391     spv::Id result = createBinaryOperation(node->getOp(), decorations,
2392                                            convertGlslangToSpvType(node->getType()), left, right,
2393                                            node->getLeft()->getType().getBasicType());
2394 
2395     builder.clearAccessChain();
2396     if (! result) {
2397         logger->missingFunctionality("unknown glslang binary operation");
2398         return true;  // pick up a child as the place-holder result
2399     } else {
2400         builder.setAccessChainRValue(result);
2401         return false;
2402     }
2403 }
2404 
convertLoadedBoolInUniformToUint(const glslang::TType & type,spv::Id nominalTypeId,spv::Id loadedId)2405 spv::Id TGlslangToSpvTraverser::convertLoadedBoolInUniformToUint(const glslang::TType& type,
2406                                                                  spv::Id nominalTypeId,
2407                                                                  spv::Id loadedId)
2408 {
2409     if (builder.isScalarType(nominalTypeId)) {
2410         // Conversion for bool
2411         spv::Id boolType = builder.makeBoolType();
2412         if (nominalTypeId != boolType)
2413             return builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0));
2414     } else if (builder.isVectorType(nominalTypeId)) {
2415         // Conversion for bvec
2416         int vecSize = builder.getNumTypeComponents(nominalTypeId);
2417         spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
2418         if (nominalTypeId != bvecType)
2419             loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId,
2420                 makeSmearedConstant(builder.makeUintConstant(0), vecSize));
2421     } else if (builder.isArrayType(nominalTypeId)) {
2422         // Conversion for bool array
2423         spv::Id boolArrayTypeId = convertGlslangToSpvType(type);
2424         if (nominalTypeId != boolArrayTypeId)
2425         {
2426             // Use OpCopyLogical from SPIR-V 1.4 if available.
2427             if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4)
2428                 return builder.createUnaryOp(spv::OpCopyLogical, boolArrayTypeId, loadedId);
2429 
2430             glslang::TType glslangElementType(type, 0);
2431             spv::Id elementNominalTypeId = builder.getContainedTypeId(nominalTypeId);
2432             std::vector<spv::Id> constituents;
2433             for (int index = 0; index < type.getOuterArraySize(); ++index) {
2434                 // get the element
2435                 spv::Id elementValue = builder.createCompositeExtract(loadedId, elementNominalTypeId, index);
2436 
2437                 // recursively convert it
2438                 spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint(glslangElementType, elementNominalTypeId, elementValue);
2439                 constituents.push_back(elementConvertedValue);
2440             }
2441             return builder.createCompositeConstruct(boolArrayTypeId, constituents);
2442         }
2443     }
2444 
2445     return loadedId;
2446 }
2447 
2448 // Figure out what, if any, type changes are needed when accessing a specific built-in.
2449 // Returns <the type SPIR-V requires for declarion, the type to translate to on use>.
2450 // Also see comment for 'forceType', regarding tracking SPIR-V-required types.
getForcedType(glslang::TBuiltInVariable glslangBuiltIn,const glslang::TType & glslangType)2451 std::pair<spv::Id, spv::Id> TGlslangToSpvTraverser::getForcedType(glslang::TBuiltInVariable glslangBuiltIn,
2452     const glslang::TType& glslangType)
2453 {
2454     switch(glslangBuiltIn)
2455     {
2456         case glslang::EbvSubGroupEqMask:
2457         case glslang::EbvSubGroupGeMask:
2458         case glslang::EbvSubGroupGtMask:
2459         case glslang::EbvSubGroupLeMask:
2460         case glslang::EbvSubGroupLtMask: {
2461             // these require changing a 64-bit scaler -> a vector of 32-bit components
2462             if (glslangType.isVector())
2463                 break;
2464             spv::Id ivec4_type = builder.makeVectorType(builder.makeUintType(32), 4);
2465             spv::Id uint64_type = builder.makeUintType(64);
2466             std::pair<spv::Id, spv::Id> ret(ivec4_type, uint64_type);
2467             return ret;
2468         }
2469         // There are no SPIR-V builtins defined for these and map onto original non-transposed
2470         // builtins. During visitBinary we insert a transpose
2471         case glslang::EbvWorldToObject3x4:
2472         case glslang::EbvObjectToWorld3x4: {
2473             spv::Id mat43 = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
2474             spv::Id mat34 = builder.makeMatrixType(builder.makeFloatType(32), 3, 4);
2475             std::pair<spv::Id, spv::Id> ret(mat43, mat34);
2476             return ret;
2477         }
2478         default:
2479             break;
2480     }
2481 
2482     std::pair<spv::Id, spv::Id> ret(spv::NoType, spv::NoType);
2483     return ret;
2484 }
2485 
2486 // For an object previously identified (see getForcedType() and forceType)
2487 // as needing type translations, do the translation needed for a load, turning
2488 // an L-value into in R-value.
translateForcedType(spv::Id object)2489 spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
2490 {
2491     const auto forceIt = forceType.find(object);
2492     if (forceIt == forceType.end())
2493         return object;
2494 
2495     spv::Id desiredTypeId = forceIt->second;
2496     spv::Id objectTypeId = builder.getTypeId(object);
2497     assert(builder.isPointerType(objectTypeId));
2498     objectTypeId = builder.getContainedTypeId(objectTypeId);
2499     if (builder.isVectorType(objectTypeId) &&
2500         builder.getScalarTypeWidth(builder.getContainedTypeId(objectTypeId)) == 32) {
2501         if (builder.getScalarTypeWidth(desiredTypeId) == 64) {
2502             // handle 32-bit v.xy* -> 64-bit
2503             builder.clearAccessChain();
2504             builder.setAccessChainLValue(object);
2505             object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
2506             std::vector<spv::Id> components;
2507             components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));
2508             components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));
2509 
2510             spv::Id vecType = builder.makeVectorType(builder.getContainedTypeId(objectTypeId), 2);
2511             return builder.createUnaryOp(spv::OpBitcast, desiredTypeId,
2512                                          builder.createCompositeConstruct(vecType, components));
2513         } else {
2514             logger->missingFunctionality("forcing 32-bit vector type to non 64-bit scalar");
2515         }
2516     } else if (builder.isMatrixType(objectTypeId)) {
2517             // There are no SPIR-V builtins defined for 3x4 variants of ObjectToWorld/WorldToObject
2518             // and we insert a transpose after loading the original non-transposed builtins
2519             builder.clearAccessChain();
2520             builder.setAccessChainLValue(object);
2521             object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
2522             return builder.createUnaryOp(spv::OpTranspose, desiredTypeId, object);
2523 
2524     } else  {
2525         logger->missingFunctionality("forcing non 32-bit vector type");
2526     }
2527 
2528     return object;
2529 }
2530 
visitUnary(glslang::TVisit,glslang::TIntermUnary * node)2531 bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
2532 {
2533     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2534 
2535     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2536     if (node->getType().getQualifier().isSpecConstant())
2537         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2538 
2539     spv::Id result = spv::NoResult;
2540 
2541     // try texturing first
2542     result = createImageTextureFunctionCall(node);
2543     if (result != spv::NoResult) {
2544         builder.clearAccessChain();
2545         builder.setAccessChainRValue(result);
2546 
2547         return false; // done with this node
2548     }
2549 
2550     // Non-texturing.
2551 
2552     if (node->getOp() == glslang::EOpArrayLength) {
2553         // Quite special; won't want to evaluate the operand.
2554 
2555         // Currently, the front-end does not allow .length() on an array until it is sized,
2556         // except for the last block membeor of an SSBO.
2557         // TODO: If this changes, link-time sized arrays might show up here, and need their
2558         // size extracted.
2559 
2560         // Normal .length() would have been constant folded by the front-end.
2561         // So, this has to be block.lastMember.length().
2562         // SPV wants "block" and member number as the operands, go get them.
2563 
2564         spv::Id length;
2565         if (node->getOperand()->getType().isCoopMat()) {
2566             spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType());
2567             assert(builder.isCooperativeMatrixType(typeId));
2568 
2569             if (node->getOperand()->getType().isCoopMatKHR()) {
2570                 length = builder.createCooperativeMatrixLengthKHR(typeId);
2571             } else {
2572                 spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2573                 length = builder.createCooperativeMatrixLengthNV(typeId);
2574             }
2575         } else {
2576             glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
2577             block->traverse(this);
2578             unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()
2579                 ->getConstArray()[0].getUConst();
2580             length = builder.createArrayLength(builder.accessChainGetLValue(), member);
2581         }
2582 
2583         // GLSL semantics say the result of .length() is an int, while SPIR-V says
2584         // signedness must be 0. So, convert from SPIR-V unsigned back to GLSL's
2585         // AST expectation of a signed result.
2586         if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
2587             if (builder.isInSpecConstCodeGenMode()) {
2588                 length = builder.createBinOp(spv::OpIAdd, builder.makeIntType(32), length, builder.makeIntConstant(0));
2589             } else {
2590                 length = builder.createUnaryOp(spv::OpBitcast, builder.makeIntType(32), length);
2591             }
2592         }
2593 
2594         builder.clearAccessChain();
2595         builder.setAccessChainRValue(length);
2596 
2597         return false;
2598     }
2599 
2600     // Force variable declaration - Debug Mode Only
2601     if (node->getOp() == glslang::EOpDeclare) {
2602         builder.clearAccessChain();
2603         node->getOperand()->traverse(this);
2604         builder.clearAccessChain();
2605         return false;
2606     }
2607 
2608     // Start by evaluating the operand
2609 
2610     // Does it need a swizzle inversion?  If so, evaluation is inverted;
2611     // operate first on the swizzle base, then apply the swizzle.
2612     spv::Id invertedType = spv::NoType;
2613     auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
2614         invertedType : convertGlslangToSpvType(node->getType()); };
2615     if (node->getOp() == glslang::EOpInterpolateAtCentroid)
2616         invertedType = getInvertedSwizzleType(*node->getOperand());
2617 
2618     builder.clearAccessChain();
2619     TIntermNode *operandNode;
2620     if (invertedType != spv::NoType)
2621         operandNode = node->getOperand()->getAsBinaryNode()->getLeft();
2622     else
2623         operandNode = node->getOperand();
2624 
2625     operandNode->traverse(this);
2626 
2627     spv::Id operand = spv::NoResult;
2628 
2629     spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
2630 
2631     const auto hitObjectOpsWithLvalue = [](glslang::TOperator op) {
2632         switch(op) {
2633             case glslang::EOpReorderThreadNV:
2634             case glslang::EOpHitObjectGetCurrentTimeNV:
2635             case glslang::EOpHitObjectGetHitKindNV:
2636             case glslang::EOpHitObjectGetPrimitiveIndexNV:
2637             case glslang::EOpHitObjectGetGeometryIndexNV:
2638             case glslang::EOpHitObjectGetInstanceIdNV:
2639             case glslang::EOpHitObjectGetInstanceCustomIndexNV:
2640             case glslang::EOpHitObjectGetObjectRayDirectionNV:
2641             case glslang::EOpHitObjectGetObjectRayOriginNV:
2642             case glslang::EOpHitObjectGetWorldRayDirectionNV:
2643             case glslang::EOpHitObjectGetWorldRayOriginNV:
2644             case glslang::EOpHitObjectGetWorldToObjectNV:
2645             case glslang::EOpHitObjectGetObjectToWorldNV:
2646             case glslang::EOpHitObjectGetRayTMaxNV:
2647             case glslang::EOpHitObjectGetRayTMinNV:
2648             case glslang::EOpHitObjectIsEmptyNV:
2649             case glslang::EOpHitObjectIsHitNV:
2650             case glslang::EOpHitObjectIsMissNV:
2651             case glslang::EOpHitObjectRecordEmptyNV:
2652             case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
2653             case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
2654                 return true;
2655             default:
2656                 return false;
2657         }
2658     };
2659 
2660     if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
2661         node->getOp() == glslang::EOpAtomicCounterDecrement ||
2662         node->getOp() == glslang::EOpAtomicCounter          ||
2663         (node->getOp() == glslang::EOpInterpolateAtCentroid &&
2664           glslangIntermediate->getSource() != glslang::EShSourceHlsl)  ||
2665         node->getOp() == glslang::EOpRayQueryProceed        ||
2666         node->getOp() == glslang::EOpRayQueryGetRayTMin     ||
2667         node->getOp() == glslang::EOpRayQueryGetRayFlags    ||
2668         node->getOp() == glslang::EOpRayQueryGetWorldRayOrigin ||
2669         node->getOp() == glslang::EOpRayQueryGetWorldRayDirection ||
2670         node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque ||
2671         node->getOp() == glslang::EOpRayQueryTerminate ||
2672         node->getOp() == glslang::EOpRayQueryConfirmIntersection ||
2673         (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference()) ||
2674         hitObjectOpsWithLvalue(node->getOp())) {
2675         operand = builder.accessChainGetLValue(); // Special case l-value operands
2676         lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
2677         lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType());
2678     } else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {
2679         // Will be translated to a literal value, make a placeholder here
2680         operand = spv::NoResult;
2681     } else {
2682         operand = accessChainLoad(node->getOperand()->getType());
2683     }
2684 
2685     OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2686                                   TranslateNoContractionDecoration(node->getType().getQualifier()),
2687                                   TranslateNonUniformDecoration(node->getType().getQualifier()) };
2688 
2689     // it could be a conversion
2690     if (! result) {
2691         result = createConversion(node->getOp(), decorations, resultType(), operand,
2692             node->getType().getBasicType(), node->getOperand()->getBasicType());
2693         if (result) {
2694             if (node->getType().isCoopMatKHR() && node->getOperand()->getAsTyped()->getType().isCoopMatKHR() &&
2695                 !node->getAsTyped()->getType().sameCoopMatUse(node->getOperand()->getAsTyped()->getType())) {
2696                 // Conversions that change use need CapabilityCooperativeMatrixConversionsNV
2697                 builder.addCapability(spv::CapabilityCooperativeMatrixConversionsNV);
2698                 builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
2699             }
2700         }
2701     }
2702 
2703     // if not, then possibly an operation
2704     if (! result)
2705         result = createUnaryOperation(node->getOp(), decorations, resultType(), operand,
2706             node->getOperand()->getBasicType(), lvalueCoherentFlags, node->getType());
2707 
2708     // it could be attached to a SPIR-V intruction
2709     if (!result) {
2710         if (node->getOp() == glslang::EOpSpirvInst) {
2711             const auto& spirvInst = node->getSpirvInstruction();
2712             if (spirvInst.set == "") {
2713                 spv::IdImmediate idImmOp = {true, operand};
2714                 if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {
2715                     // Translate the constant to a literal value
2716                     std::vector<unsigned> literals;
2717                     glslang::TVector<const glslang::TIntermConstantUnion*> constants;
2718                     constants.push_back(operandNode->getAsConstantUnion());
2719                     TranslateLiterals(constants, literals);
2720                     idImmOp = {false, literals[0]};
2721                 }
2722 
2723                 if (node->getBasicType() == glslang::EbtVoid)
2724                     builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), {idImmOp});
2725                 else
2726                     result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), {idImmOp});
2727             } else {
2728                 result = builder.createBuiltinCall(
2729                     resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),
2730                     spirvInst.id, {operand});
2731             }
2732 
2733             if (node->getBasicType() == glslang::EbtVoid)
2734                 return false; // done with this node
2735         }
2736     }
2737 
2738     if (result) {
2739         if (invertedType) {
2740             result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result);
2741             decorations.addNonUniform(builder, result);
2742         }
2743 
2744         builder.clearAccessChain();
2745         builder.setAccessChainRValue(result);
2746 
2747         return false; // done with this node
2748     }
2749 
2750     // it must be a special case, check...
2751     switch (node->getOp()) {
2752     case glslang::EOpPostIncrement:
2753     case glslang::EOpPostDecrement:
2754     case glslang::EOpPreIncrement:
2755     case glslang::EOpPreDecrement:
2756         {
2757             // we need the integer value "1" or the floating point "1.0" to add/subtract
2758             spv::Id one = 0;
2759             if (node->getBasicType() == glslang::EbtFloat)
2760                 one = builder.makeFloatConstant(1.0F);
2761             else if (node->getBasicType() == glslang::EbtDouble)
2762                 one = builder.makeDoubleConstant(1.0);
2763             else if (node->getBasicType() == glslang::EbtFloat16)
2764                 one = builder.makeFloat16Constant(1.0F);
2765             else if (node->getBasicType() == glslang::EbtInt8  || node->getBasicType() == glslang::EbtUint8)
2766                 one = builder.makeInt8Constant(1);
2767             else if (node->getBasicType() == glslang::EbtInt16 || node->getBasicType() == glslang::EbtUint16)
2768                 one = builder.makeInt16Constant(1);
2769             else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)
2770                 one = builder.makeInt64Constant(1);
2771             else
2772                 one = builder.makeIntConstant(1);
2773             glslang::TOperator op;
2774             if (node->getOp() == glslang::EOpPreIncrement ||
2775                 node->getOp() == glslang::EOpPostIncrement)
2776                 op = glslang::EOpAdd;
2777             else
2778                 op = glslang::EOpSub;
2779 
2780             spv::Id result = createBinaryOperation(op, decorations,
2781                                                    convertGlslangToSpvType(node->getType()), operand, one,
2782                                                    node->getType().getBasicType());
2783             assert(result != spv::NoResult);
2784 
2785             // The result of operation is always stored, but conditionally the
2786             // consumed result.  The consumed result is always an r-value.
2787             builder.accessChainStore(result,
2788                                      TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags));
2789             builder.clearAccessChain();
2790             if (node->getOp() == glslang::EOpPreIncrement ||
2791                 node->getOp() == glslang::EOpPreDecrement)
2792                 builder.setAccessChainRValue(result);
2793             else
2794                 builder.setAccessChainRValue(operand);
2795         }
2796 
2797         return false;
2798 
2799     case glslang::EOpAssumeEXT:
2800         builder.addCapability(spv::CapabilityExpectAssumeKHR);
2801         builder.addExtension(spv::E_SPV_KHR_expect_assume);
2802         builder.createNoResultOp(spv::OpAssumeTrueKHR, operand);
2803         return false;
2804     case glslang::EOpEmitStreamVertex:
2805         builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
2806         return false;
2807     case glslang::EOpEndStreamPrimitive:
2808         builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
2809         return false;
2810     case glslang::EOpRayQueryTerminate:
2811         builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operand);
2812         return false;
2813     case glslang::EOpRayQueryConfirmIntersection:
2814         builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operand);
2815         return false;
2816     case glslang::EOpReorderThreadNV:
2817         builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operand);
2818         return false;
2819     case glslang::EOpHitObjectRecordEmptyNV:
2820         builder.createNoResultOp(spv::OpHitObjectRecordEmptyNV, operand);
2821         return false;
2822 
2823     case glslang::EOpCreateTensorLayoutNV:
2824         result = builder.createOp(spv::OpCreateTensorLayoutNV, resultType(), std::vector<spv::Id>{});
2825         builder.clearAccessChain();
2826         builder.setAccessChainRValue(result);
2827         return false;
2828 
2829     case glslang::EOpCreateTensorViewNV:
2830         result = builder.createOp(spv::OpCreateTensorViewNV, resultType(), std::vector<spv::Id>{});
2831         builder.clearAccessChain();
2832         builder.setAccessChainRValue(result);
2833         return false;
2834 
2835     default:
2836         logger->missingFunctionality("unknown glslang unary");
2837         return true;  // pick up operand as placeholder result
2838     }
2839 }
2840 
2841 // Construct a composite object, recursively copying members if their types don't match
createCompositeConstruct(spv::Id resultTypeId,std::vector<spv::Id> constituents)2842 spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, std::vector<spv::Id> constituents)
2843 {
2844     for (int c = 0; c < (int)constituents.size(); ++c) {
2845         spv::Id& constituent = constituents[c];
2846         spv::Id lType = builder.getContainedTypeId(resultTypeId, c);
2847         spv::Id rType = builder.getTypeId(constituent);
2848         if (lType != rType) {
2849             if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
2850                 constituent = builder.createUnaryOp(spv::OpCopyLogical, lType, constituent);
2851             } else if (builder.isStructType(rType)) {
2852                 std::vector<spv::Id> rTypeConstituents;
2853                 int numrTypeConstituents = builder.getNumTypeConstituents(rType);
2854                 for (int i = 0; i < numrTypeConstituents; ++i) {
2855                     rTypeConstituents.push_back(builder.createCompositeExtract(constituent,
2856                         builder.getContainedTypeId(rType, i), i));
2857                 }
2858                 constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
2859             } else {
2860                 assert(builder.isArrayType(rType));
2861                 std::vector<spv::Id> rTypeConstituents;
2862                 int numrTypeConstituents = builder.getNumTypeConstituents(rType);
2863 
2864                 spv::Id elementRType = builder.getContainedTypeId(rType);
2865                 for (int i = 0; i < numrTypeConstituents; ++i) {
2866                     rTypeConstituents.push_back(builder.createCompositeExtract(constituent, elementRType, i));
2867                 }
2868                 constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
2869             }
2870         }
2871     }
2872     return builder.createCompositeConstruct(resultTypeId, constituents);
2873 }
2874 
visitAggregate(glslang::TVisit visit,glslang::TIntermAggregate * node)2875 bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
2876 {
2877     SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2878     if (node->getType().getQualifier().isSpecConstant())
2879         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2880 
2881     spv::Id result = spv::NoResult;
2882     spv::Id invertedType = spv::NoType;                     // to use to override the natural type of the node
2883     std::vector<spv::Builder::AccessChain> complexLvalues;  // for holding swizzling l-values too complex for
2884                                                             // SPIR-V, for an out parameter
2885     std::vector<spv::Id> temporaryLvalues;                  // temporaries to pass, as proxies for complexLValues
2886 
2887     auto resultType = [&invertedType, &node, this](){
2888         if (invertedType != spv::NoType) {
2889             return invertedType;
2890         } else {
2891             auto ret = convertGlslangToSpvType(node->getType());
2892             // convertGlslangToSpvType may clobber the debug location, reset it
2893             builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2894             return ret;
2895         }
2896     };
2897 
2898     // try texturing
2899     result = createImageTextureFunctionCall(node);
2900     if (result != spv::NoResult) {
2901         builder.clearAccessChain();
2902         builder.setAccessChainRValue(result);
2903 
2904         return false;
2905     } else if (node->getOp() == glslang::EOpImageStore ||
2906         node->getOp() == glslang::EOpImageStoreLod ||
2907         node->getOp() == glslang::EOpImageAtomicStore) {
2908         // "imageStore" is a special case, which has no result
2909         return false;
2910     }
2911 
2912     glslang::TOperator binOp = glslang::EOpNull;
2913     bool reduceComparison = true;
2914     bool isMatrix = false;
2915     bool noReturnValue = false;
2916     bool atomic = false;
2917 
2918     spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
2919 
2920     assert(node->getOp());
2921 
2922     spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());
2923 
2924     switch (node->getOp()) {
2925     case glslang::EOpScope:
2926     case glslang::EOpSequence:
2927     {
2928         if (visit == glslang::EvPreVisit) {
2929             ++sequenceDepth;
2930             if (sequenceDepth == 1) {
2931                 // If this is the parent node of all the functions, we want to see them
2932                 // early, so all call points have actual SPIR-V functions to reference.
2933                 // In all cases, still let the traverser visit the children for us.
2934                 makeFunctions(node->getAsAggregate()->getSequence());
2935 
2936                 // Global initializers is specific to the shader entry point, which does not exist in compile-only mode
2937                 if (!options.compileOnly) {
2938                     // Also, we want all globals initializers to go into the beginning of the entry point, before
2939                     // anything else gets there, so visit out of order, doing them all now.
2940                     makeGlobalInitializers(node->getAsAggregate()->getSequence());
2941                 }
2942 
2943                 //Pre process linker objects for ray tracing stages
2944                 if (glslangIntermediate->isRayTracingStage())
2945                   collectRayTracingLinkerObjects();
2946 
2947                 // Initializers are done, don't want to visit again, but functions and link objects need to be processed,
2948                 // so do them manually.
2949                 visitFunctions(node->getAsAggregate()->getSequence());
2950 
2951                 return false;
2952             } else {
2953                 if (node->getOp() == glslang::EOpScope) {
2954                     auto loc = node->getLoc();
2955                     builder.enterLexicalBlock(loc.line, loc.column);
2956                 }
2957             }
2958         } else {
2959             if (sequenceDepth > 1 && node->getOp() == glslang::EOpScope)
2960                 builder.leaveLexicalBlock();
2961             --sequenceDepth;
2962         }
2963 
2964         return true;
2965     }
2966     case glslang::EOpLinkerObjects:
2967     {
2968         if (visit == glslang::EvPreVisit)
2969             linkageOnly = true;
2970         else
2971             linkageOnly = false;
2972 
2973         return true;
2974     }
2975     case glslang::EOpComma:
2976     {
2977         // processing from left to right naturally leaves the right-most
2978         // lying around in the access chain
2979         glslang::TIntermSequence& glslangOperands = node->getSequence();
2980         for (int i = 0; i < (int)glslangOperands.size(); ++i)
2981             glslangOperands[i]->traverse(this);
2982 
2983         return false;
2984     }
2985     case glslang::EOpFunction:
2986         if (visit == glslang::EvPreVisit) {
2987             if (options.generateDebugInfo) {
2988                 builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2989             }
2990             if (isShaderEntryPoint(node)) {
2991                 inEntryPoint = true;
2992                 builder.setBuildPoint(shaderEntry->getLastBlock());
2993                 builder.enterFunction(shaderEntry);
2994                 currentFunction = shaderEntry;
2995             } else {
2996                 handleFunctionEntry(node);
2997             }
2998             if (options.generateDebugInfo && !options.emitNonSemanticShaderDebugInfo) {
2999                 const auto& loc = node->getLoc();
3000                 const char* sourceFileName = loc.getFilename();
3001                 spv::Id sourceFileId = sourceFileName ? builder.getStringId(sourceFileName) : builder.getMainFileId();
3002                 currentFunction->setDebugLineInfo(sourceFileId, loc.line, loc.column);
3003             }
3004         } else {
3005             if (options.generateDebugInfo) {
3006                 if (glslangIntermediate->getSource() == glslang::EShSourceGlsl && node->getSequence().size() > 1) {
3007                     auto endLoc = node->getSequence()[1]->getAsAggregate()->getEndLoc();
3008                     builder.setDebugSourceLocation(endLoc.line, endLoc.getFilename());
3009                 }
3010             }
3011             if (inEntryPoint)
3012                 entryPointTerminated = true;
3013             builder.leaveFunction();
3014             inEntryPoint = false;
3015         }
3016 
3017         return true;
3018     case glslang::EOpParameters:
3019         // Parameters will have been consumed by EOpFunction processing, but not
3020         // the body, so we still visited the function node's children, making this
3021         // child redundant.
3022         return false;
3023     case glslang::EOpFunctionCall:
3024     {
3025         builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3026         if (node->isUserDefined())
3027             result = handleUserFunctionCall(node);
3028         if (result) {
3029             builder.clearAccessChain();
3030             builder.setAccessChainRValue(result);
3031         } else
3032             logger->missingFunctionality("missing user function; linker needs to catch that");
3033 
3034         return false;
3035     }
3036     case glslang::EOpConstructMat2x2:
3037     case glslang::EOpConstructMat2x3:
3038     case glslang::EOpConstructMat2x4:
3039     case glslang::EOpConstructMat3x2:
3040     case glslang::EOpConstructMat3x3:
3041     case glslang::EOpConstructMat3x4:
3042     case glslang::EOpConstructMat4x2:
3043     case glslang::EOpConstructMat4x3:
3044     case glslang::EOpConstructMat4x4:
3045     case glslang::EOpConstructDMat2x2:
3046     case glslang::EOpConstructDMat2x3:
3047     case glslang::EOpConstructDMat2x4:
3048     case glslang::EOpConstructDMat3x2:
3049     case glslang::EOpConstructDMat3x3:
3050     case glslang::EOpConstructDMat3x4:
3051     case glslang::EOpConstructDMat4x2:
3052     case glslang::EOpConstructDMat4x3:
3053     case glslang::EOpConstructDMat4x4:
3054     case glslang::EOpConstructIMat2x2:
3055     case glslang::EOpConstructIMat2x3:
3056     case glslang::EOpConstructIMat2x4:
3057     case glslang::EOpConstructIMat3x2:
3058     case glslang::EOpConstructIMat3x3:
3059     case glslang::EOpConstructIMat3x4:
3060     case glslang::EOpConstructIMat4x2:
3061     case glslang::EOpConstructIMat4x3:
3062     case glslang::EOpConstructIMat4x4:
3063     case glslang::EOpConstructUMat2x2:
3064     case glslang::EOpConstructUMat2x3:
3065     case glslang::EOpConstructUMat2x4:
3066     case glslang::EOpConstructUMat3x2:
3067     case glslang::EOpConstructUMat3x3:
3068     case glslang::EOpConstructUMat3x4:
3069     case glslang::EOpConstructUMat4x2:
3070     case glslang::EOpConstructUMat4x3:
3071     case glslang::EOpConstructUMat4x4:
3072     case glslang::EOpConstructBMat2x2:
3073     case glslang::EOpConstructBMat2x3:
3074     case glslang::EOpConstructBMat2x4:
3075     case glslang::EOpConstructBMat3x2:
3076     case glslang::EOpConstructBMat3x3:
3077     case glslang::EOpConstructBMat3x4:
3078     case glslang::EOpConstructBMat4x2:
3079     case glslang::EOpConstructBMat4x3:
3080     case glslang::EOpConstructBMat4x4:
3081     case glslang::EOpConstructF16Mat2x2:
3082     case glslang::EOpConstructF16Mat2x3:
3083     case glslang::EOpConstructF16Mat2x4:
3084     case glslang::EOpConstructF16Mat3x2:
3085     case glslang::EOpConstructF16Mat3x3:
3086     case glslang::EOpConstructF16Mat3x4:
3087     case glslang::EOpConstructF16Mat4x2:
3088     case glslang::EOpConstructF16Mat4x3:
3089     case glslang::EOpConstructF16Mat4x4:
3090         isMatrix = true;
3091         [[fallthrough]];
3092     case glslang::EOpConstructFloat:
3093     case glslang::EOpConstructVec2:
3094     case glslang::EOpConstructVec3:
3095     case glslang::EOpConstructVec4:
3096     case glslang::EOpConstructDouble:
3097     case glslang::EOpConstructDVec2:
3098     case glslang::EOpConstructDVec3:
3099     case glslang::EOpConstructDVec4:
3100     case glslang::EOpConstructFloat16:
3101     case glslang::EOpConstructF16Vec2:
3102     case glslang::EOpConstructF16Vec3:
3103     case glslang::EOpConstructF16Vec4:
3104     case glslang::EOpConstructBool:
3105     case glslang::EOpConstructBVec2:
3106     case glslang::EOpConstructBVec3:
3107     case glslang::EOpConstructBVec4:
3108     case glslang::EOpConstructInt8:
3109     case glslang::EOpConstructI8Vec2:
3110     case glslang::EOpConstructI8Vec3:
3111     case glslang::EOpConstructI8Vec4:
3112     case glslang::EOpConstructUint8:
3113     case glslang::EOpConstructU8Vec2:
3114     case glslang::EOpConstructU8Vec3:
3115     case glslang::EOpConstructU8Vec4:
3116     case glslang::EOpConstructInt16:
3117     case glslang::EOpConstructI16Vec2:
3118     case glslang::EOpConstructI16Vec3:
3119     case glslang::EOpConstructI16Vec4:
3120     case glslang::EOpConstructUint16:
3121     case glslang::EOpConstructU16Vec2:
3122     case glslang::EOpConstructU16Vec3:
3123     case glslang::EOpConstructU16Vec4:
3124     case glslang::EOpConstructInt:
3125     case glslang::EOpConstructIVec2:
3126     case glslang::EOpConstructIVec3:
3127     case glslang::EOpConstructIVec4:
3128     case glslang::EOpConstructUint:
3129     case glslang::EOpConstructUVec2:
3130     case glslang::EOpConstructUVec3:
3131     case glslang::EOpConstructUVec4:
3132     case glslang::EOpConstructInt64:
3133     case glslang::EOpConstructI64Vec2:
3134     case glslang::EOpConstructI64Vec3:
3135     case glslang::EOpConstructI64Vec4:
3136     case glslang::EOpConstructUint64:
3137     case glslang::EOpConstructU64Vec2:
3138     case glslang::EOpConstructU64Vec3:
3139     case glslang::EOpConstructU64Vec4:
3140     case glslang::EOpConstructStruct:
3141     case glslang::EOpConstructTextureSampler:
3142     case glslang::EOpConstructReference:
3143     case glslang::EOpConstructCooperativeMatrixNV:
3144     case glslang::EOpConstructCooperativeMatrixKHR:
3145     {
3146         builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3147         std::vector<spv::Id> arguments;
3148         translateArguments(*node, arguments, lvalueCoherentFlags);
3149         spv::Id constructed;
3150         if (node->getOp() == glslang::EOpConstructTextureSampler) {
3151             const glslang::TType& texType = node->getSequence()[0]->getAsTyped()->getType();
3152             if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 &&
3153                 texType.getSampler().isBuffer()) {
3154                 // SamplerBuffer is not supported in spirv1.6 so
3155                 // `samplerBuffer(textureBuffer, sampler)` is a no-op
3156                 // and textureBuffer is the result going forward
3157                 constructed = arguments[0];
3158             } else
3159                 constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments);
3160         } else if (node->getOp() == glslang::EOpConstructCooperativeMatrixKHR &&
3161                    node->getType().isCoopMatKHR() && node->getSequence()[0]->getAsTyped()->getType().isCoopMatKHR()) {
3162             builder.addCapability(spv::CapabilityCooperativeMatrixConversionsNV);
3163             builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3164             constructed = builder.createCooperativeMatrixConversion(resultType(), arguments[0]);
3165         } else if (node->getOp() == glslang::EOpConstructStruct ||
3166                  node->getOp() == glslang::EOpConstructCooperativeMatrixNV ||
3167                  node->getOp() == glslang::EOpConstructCooperativeMatrixKHR ||
3168                  node->getType().isArray()) {
3169             std::vector<spv::Id> constituents;
3170             for (int c = 0; c < (int)arguments.size(); ++c)
3171                 constituents.push_back(arguments[c]);
3172             constructed = createCompositeConstruct(resultType(), constituents);
3173         } else if (isMatrix)
3174             constructed = builder.createMatrixConstructor(precision, arguments, resultType());
3175         else
3176             constructed = builder.createConstructor(precision, arguments, resultType());
3177 
3178         if (node->getType().getQualifier().isNonUniform()) {
3179             builder.addDecoration(constructed, spv::DecorationNonUniformEXT);
3180         }
3181 
3182         builder.clearAccessChain();
3183         builder.setAccessChainRValue(constructed);
3184 
3185         return false;
3186     }
3187 
3188     // These six are component-wise compares with component-wise results.
3189     // Forward on to createBinaryOperation(), requesting a vector result.
3190     case glslang::EOpLessThan:
3191     case glslang::EOpGreaterThan:
3192     case glslang::EOpLessThanEqual:
3193     case glslang::EOpGreaterThanEqual:
3194     case glslang::EOpVectorEqual:
3195     case glslang::EOpVectorNotEqual:
3196     {
3197         // Map the operation to a binary
3198         binOp = node->getOp();
3199         reduceComparison = false;
3200         switch (node->getOp()) {
3201         case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;
3202         case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;
3203         default:                          binOp = node->getOp();                break;
3204         }
3205 
3206         break;
3207     }
3208     case glslang::EOpMul:
3209         // component-wise matrix multiply
3210         binOp = glslang::EOpMul;
3211         break;
3212     case glslang::EOpOuterProduct:
3213         // two vectors multiplied to make a matrix
3214         binOp = glslang::EOpOuterProduct;
3215         break;
3216     case glslang::EOpDot:
3217     {
3218         // for scalar dot product, use multiply
3219         glslang::TIntermSequence& glslangOperands = node->getSequence();
3220         if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)
3221             binOp = glslang::EOpMul;
3222         break;
3223     }
3224     case glslang::EOpMod:
3225         // when an aggregate, this is the floating-point mod built-in function,
3226         // which can be emitted by the one in createBinaryOperation()
3227         binOp = glslang::EOpMod;
3228         break;
3229 
3230     case glslang::EOpEmitVertex:
3231     case glslang::EOpEndPrimitive:
3232     case glslang::EOpBarrier:
3233     case glslang::EOpMemoryBarrier:
3234     case glslang::EOpMemoryBarrierAtomicCounter:
3235     case glslang::EOpMemoryBarrierBuffer:
3236     case glslang::EOpMemoryBarrierImage:
3237     case glslang::EOpMemoryBarrierShared:
3238     case glslang::EOpGroupMemoryBarrier:
3239     case glslang::EOpDeviceMemoryBarrier:
3240     case glslang::EOpAllMemoryBarrierWithGroupSync:
3241     case glslang::EOpDeviceMemoryBarrierWithGroupSync:
3242     case glslang::EOpWorkgroupMemoryBarrier:
3243     case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
3244     case glslang::EOpSubgroupBarrier:
3245     case glslang::EOpSubgroupMemoryBarrier:
3246     case glslang::EOpSubgroupMemoryBarrierBuffer:
3247     case glslang::EOpSubgroupMemoryBarrierImage:
3248     case glslang::EOpSubgroupMemoryBarrierShared:
3249         noReturnValue = true;
3250         // These all have 0 operands and will naturally finish up in the code below for 0 operands
3251         break;
3252 
3253     case glslang::EOpAtomicAdd:
3254     case glslang::EOpAtomicSubtract:
3255     case glslang::EOpAtomicMin:
3256     case glslang::EOpAtomicMax:
3257     case glslang::EOpAtomicAnd:
3258     case glslang::EOpAtomicOr:
3259     case glslang::EOpAtomicXor:
3260     case glslang::EOpAtomicExchange:
3261     case glslang::EOpAtomicCompSwap:
3262         atomic = true;
3263         break;
3264 
3265     case glslang::EOpAtomicStore:
3266         noReturnValue = true;
3267         [[fallthrough]];
3268     case glslang::EOpAtomicLoad:
3269         atomic = true;
3270         break;
3271 
3272     case glslang::EOpAtomicCounterAdd:
3273     case glslang::EOpAtomicCounterSubtract:
3274     case glslang::EOpAtomicCounterMin:
3275     case glslang::EOpAtomicCounterMax:
3276     case glslang::EOpAtomicCounterAnd:
3277     case glslang::EOpAtomicCounterOr:
3278     case glslang::EOpAtomicCounterXor:
3279     case glslang::EOpAtomicCounterExchange:
3280     case glslang::EOpAtomicCounterCompSwap:
3281         builder.addExtension("SPV_KHR_shader_atomic_counter_ops");
3282         builder.addCapability(spv::CapabilityAtomicStorageOps);
3283         atomic = true;
3284         break;
3285 
3286     case glslang::EOpAbsDifference:
3287     case glslang::EOpAddSaturate:
3288     case glslang::EOpSubSaturate:
3289     case glslang::EOpAverage:
3290     case glslang::EOpAverageRounded:
3291     case glslang::EOpMul32x16:
3292         builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);
3293         builder.addExtension("SPV_INTEL_shader_integer_functions2");
3294         binOp = node->getOp();
3295         break;
3296 
3297     case glslang::EOpExpectEXT:
3298         builder.addCapability(spv::CapabilityExpectAssumeKHR);
3299         builder.addExtension(spv::E_SPV_KHR_expect_assume);
3300         binOp = node->getOp();
3301         break;
3302 
3303     case glslang::EOpIgnoreIntersectionNV:
3304     case glslang::EOpTerminateRayNV:
3305     case glslang::EOpTraceNV:
3306     case glslang::EOpTraceRayMotionNV:
3307     case glslang::EOpTraceKHR:
3308     case glslang::EOpExecuteCallableNV:
3309     case glslang::EOpExecuteCallableKHR:
3310     case glslang::EOpWritePackedPrimitiveIndices4x8NV:
3311     case glslang::EOpEmitMeshTasksEXT:
3312     case glslang::EOpSetMeshOutputsEXT:
3313         noReturnValue = true;
3314         break;
3315     case glslang::EOpRayQueryInitialize:
3316     case glslang::EOpRayQueryTerminate:
3317     case glslang::EOpRayQueryGenerateIntersection:
3318     case glslang::EOpRayQueryConfirmIntersection:
3319         builder.addExtension("SPV_KHR_ray_query");
3320         builder.addCapability(spv::CapabilityRayQueryKHR);
3321         noReturnValue = true;
3322         break;
3323     case glslang::EOpRayQueryProceed:
3324     case glslang::EOpRayQueryGetIntersectionType:
3325     case glslang::EOpRayQueryGetRayTMin:
3326     case glslang::EOpRayQueryGetRayFlags:
3327     case glslang::EOpRayQueryGetIntersectionT:
3328     case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
3329     case glslang::EOpRayQueryGetIntersectionInstanceId:
3330     case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
3331     case glslang::EOpRayQueryGetIntersectionGeometryIndex:
3332     case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
3333     case glslang::EOpRayQueryGetIntersectionBarycentrics:
3334     case glslang::EOpRayQueryGetIntersectionFrontFace:
3335     case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
3336     case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
3337     case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
3338     case glslang::EOpRayQueryGetWorldRayDirection:
3339     case glslang::EOpRayQueryGetWorldRayOrigin:
3340     case glslang::EOpRayQueryGetIntersectionObjectToWorld:
3341     case glslang::EOpRayQueryGetIntersectionWorldToObject:
3342         builder.addExtension("SPV_KHR_ray_query");
3343         builder.addCapability(spv::CapabilityRayQueryKHR);
3344         break;
3345     case glslang::EOpCooperativeMatrixLoad:
3346     case glslang::EOpCooperativeMatrixStore:
3347     case glslang::EOpCooperativeMatrixLoadNV:
3348     case glslang::EOpCooperativeMatrixStoreNV:
3349     case glslang::EOpCooperativeMatrixLoadTensorNV:
3350     case glslang::EOpCooperativeMatrixStoreTensorNV:
3351     case glslang::EOpCooperativeMatrixReduceNV:
3352     case glslang::EOpCooperativeMatrixPerElementOpNV:
3353     case glslang::EOpCooperativeMatrixTransposeNV:
3354         noReturnValue = true;
3355         break;
3356     case glslang::EOpBeginInvocationInterlock:
3357     case glslang::EOpEndInvocationInterlock:
3358         builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
3359         noReturnValue = true;
3360         break;
3361 
3362     case glslang::EOpHitObjectTraceRayNV:
3363     case glslang::EOpHitObjectTraceRayMotionNV:
3364     case glslang::EOpHitObjectGetAttributesNV:
3365     case glslang::EOpHitObjectExecuteShaderNV:
3366     case glslang::EOpHitObjectRecordEmptyNV:
3367     case glslang::EOpHitObjectRecordMissNV:
3368     case glslang::EOpHitObjectRecordMissMotionNV:
3369     case glslang::EOpHitObjectRecordHitNV:
3370     case glslang::EOpHitObjectRecordHitMotionNV:
3371     case glslang::EOpHitObjectRecordHitWithIndexNV:
3372     case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
3373     case glslang::EOpReorderThreadNV:
3374         noReturnValue = true;
3375         [[fallthrough]];
3376     case glslang::EOpHitObjectIsEmptyNV:
3377     case glslang::EOpHitObjectIsMissNV:
3378     case glslang::EOpHitObjectIsHitNV:
3379     case glslang::EOpHitObjectGetRayTMinNV:
3380     case glslang::EOpHitObjectGetRayTMaxNV:
3381     case glslang::EOpHitObjectGetObjectRayOriginNV:
3382     case glslang::EOpHitObjectGetObjectRayDirectionNV:
3383     case glslang::EOpHitObjectGetWorldRayOriginNV:
3384     case glslang::EOpHitObjectGetWorldRayDirectionNV:
3385     case glslang::EOpHitObjectGetObjectToWorldNV:
3386     case glslang::EOpHitObjectGetWorldToObjectNV:
3387     case glslang::EOpHitObjectGetInstanceCustomIndexNV:
3388     case glslang::EOpHitObjectGetInstanceIdNV:
3389     case glslang::EOpHitObjectGetGeometryIndexNV:
3390     case glslang::EOpHitObjectGetPrimitiveIndexNV:
3391     case glslang::EOpHitObjectGetHitKindNV:
3392     case glslang::EOpHitObjectGetCurrentTimeNV:
3393     case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
3394     case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
3395         builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);
3396         builder.addCapability(spv::CapabilityShaderInvocationReorderNV);
3397         break;
3398     case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
3399         builder.addExtension(spv::E_SPV_KHR_ray_tracing_position_fetch);
3400         builder.addCapability(spv::CapabilityRayQueryPositionFetchKHR);
3401         noReturnValue = true;
3402         break;
3403 
3404     case glslang::EOpImageSampleWeightedQCOM:
3405         builder.addCapability(spv::CapabilityTextureSampleWeightedQCOM);
3406         builder.addExtension(spv::E_SPV_QCOM_image_processing);
3407         break;
3408     case glslang::EOpImageBoxFilterQCOM:
3409         builder.addCapability(spv::CapabilityTextureBoxFilterQCOM);
3410         builder.addExtension(spv::E_SPV_QCOM_image_processing);
3411         break;
3412     case glslang::EOpImageBlockMatchSADQCOM:
3413     case glslang::EOpImageBlockMatchSSDQCOM:
3414         builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);
3415         builder.addExtension(spv::E_SPV_QCOM_image_processing);
3416         break;
3417 
3418     case glslang::EOpImageBlockMatchWindowSSDQCOM:
3419     case glslang::EOpImageBlockMatchWindowSADQCOM:
3420         builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);
3421         builder.addExtension(spv::E_SPV_QCOM_image_processing);
3422         builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM);
3423         builder.addExtension(spv::E_SPV_QCOM_image_processing2);
3424         break;
3425 
3426     case glslang::EOpImageBlockMatchGatherSSDQCOM:
3427     case glslang::EOpImageBlockMatchGatherSADQCOM:
3428         builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);
3429         builder.addExtension(spv::E_SPV_QCOM_image_processing);
3430         builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM);
3431         builder.addExtension(spv::E_SPV_QCOM_image_processing2);
3432         break;
3433 
3434     case glslang::EOpFetchMicroTriangleVertexPositionNV:
3435     case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
3436         builder.addExtension(spv::E_SPV_NV_displacement_micromap);
3437         builder.addCapability(spv::CapabilityDisplacementMicromapNV);
3438         break;
3439 
3440     case glslang::EOpDebugPrintf:
3441         noReturnValue = true;
3442         break;
3443 
3444     default:
3445         break;
3446     }
3447 
3448     //
3449     // See if it maps to a regular operation.
3450     //
3451     if (binOp != glslang::EOpNull) {
3452         glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
3453         glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
3454         assert(left && right);
3455 
3456         builder.clearAccessChain();
3457         left->traverse(this);
3458         spv::Id leftId = accessChainLoad(left->getType());
3459 
3460         builder.clearAccessChain();
3461         right->traverse(this);
3462         spv::Id rightId = accessChainLoad(right->getType());
3463 
3464         builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3465         OpDecorations decorations = { precision,
3466                                       TranslateNoContractionDecoration(node->getType().getQualifier()),
3467                                       TranslateNonUniformDecoration(node->getType().getQualifier()) };
3468         result = createBinaryOperation(binOp, decorations,
3469                                        resultType(), leftId, rightId,
3470                                        left->getType().getBasicType(), reduceComparison);
3471 
3472         // code above should only make binOp that exists in createBinaryOperation
3473         assert(result != spv::NoResult);
3474         builder.clearAccessChain();
3475         builder.setAccessChainRValue(result);
3476 
3477         return false;
3478     }
3479 
3480     //
3481     // Create the list of operands.
3482     //
3483     glslang::TIntermSequence& glslangOperands = node->getSequence();
3484     std::vector<spv::Id> operands;
3485     std::vector<spv::IdImmediate> memoryAccessOperands;
3486     for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
3487         // special case l-value operands; there are just a few
3488         bool lvalue = false;
3489         switch (node->getOp()) {
3490         case glslang::EOpModf:
3491             if (arg == 1)
3492                 lvalue = true;
3493             break;
3494 
3495 
3496 
3497         case glslang::EOpHitObjectRecordHitNV:
3498         case glslang::EOpHitObjectRecordHitMotionNV:
3499         case glslang::EOpHitObjectRecordHitWithIndexNV:
3500         case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
3501         case glslang::EOpHitObjectTraceRayNV:
3502         case glslang::EOpHitObjectTraceRayMotionNV:
3503         case glslang::EOpHitObjectExecuteShaderNV:
3504         case glslang::EOpHitObjectRecordMissNV:
3505         case glslang::EOpHitObjectRecordMissMotionNV:
3506         case glslang::EOpHitObjectGetAttributesNV:
3507             if (arg == 0)
3508                 lvalue = true;
3509             break;
3510 
3511         case glslang::EOpRayQueryInitialize:
3512         case glslang::EOpRayQueryTerminate:
3513         case glslang::EOpRayQueryConfirmIntersection:
3514         case glslang::EOpRayQueryProceed:
3515         case glslang::EOpRayQueryGenerateIntersection:
3516         case glslang::EOpRayQueryGetIntersectionType:
3517         case glslang::EOpRayQueryGetIntersectionT:
3518         case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
3519         case glslang::EOpRayQueryGetIntersectionInstanceId:
3520         case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
3521         case glslang::EOpRayQueryGetIntersectionGeometryIndex:
3522         case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
3523         case glslang::EOpRayQueryGetIntersectionBarycentrics:
3524         case glslang::EOpRayQueryGetIntersectionFrontFace:
3525         case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
3526         case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
3527         case glslang::EOpRayQueryGetIntersectionObjectToWorld:
3528         case glslang::EOpRayQueryGetIntersectionWorldToObject:
3529             if (arg == 0)
3530                 lvalue = true;
3531             break;
3532 
3533         case glslang::EOpAtomicAdd:
3534         case glslang::EOpAtomicSubtract:
3535         case glslang::EOpAtomicMin:
3536         case glslang::EOpAtomicMax:
3537         case glslang::EOpAtomicAnd:
3538         case glslang::EOpAtomicOr:
3539         case glslang::EOpAtomicXor:
3540         case glslang::EOpAtomicExchange:
3541         case glslang::EOpAtomicCompSwap:
3542             if (arg == 0)
3543                 lvalue = true;
3544             break;
3545 
3546         case glslang::EOpFrexp:
3547             if (arg == 1)
3548                 lvalue = true;
3549             break;
3550         case glslang::EOpInterpolateAtSample:
3551         case glslang::EOpInterpolateAtOffset:
3552         case glslang::EOpInterpolateAtVertex:
3553             if (arg == 0) {
3554                 // If GLSL, use the address of the interpolant argument.
3555                 // If HLSL, use an internal version of OpInterolates that takes
3556                 // the rvalue of the interpolant. A fixup pass in spirv-opt
3557                 // legalization will remove the OpLoad and convert to an lvalue.
3558                 // Had to do this because legalization will only propagate a
3559                 // builtin into an rvalue.
3560                 lvalue = glslangIntermediate->getSource() != glslang::EShSourceHlsl;
3561 
3562                 // Does it need a swizzle inversion?  If so, evaluation is inverted;
3563                 // operate first on the swizzle base, then apply the swizzle.
3564                 // That is, we transform
3565                 //
3566                 //    interpolate(v.zy)  ->  interpolate(v).zy
3567                 //
3568                 if (glslangOperands[0]->getAsOperator() &&
3569                     glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
3570                     invertedType = convertGlslangToSpvType(
3571                         glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());
3572             }
3573             break;
3574         case glslang::EOpAtomicLoad:
3575         case glslang::EOpAtomicStore:
3576         case glslang::EOpAtomicCounterAdd:
3577         case glslang::EOpAtomicCounterSubtract:
3578         case glslang::EOpAtomicCounterMin:
3579         case glslang::EOpAtomicCounterMax:
3580         case glslang::EOpAtomicCounterAnd:
3581         case glslang::EOpAtomicCounterOr:
3582         case glslang::EOpAtomicCounterXor:
3583         case glslang::EOpAtomicCounterExchange:
3584         case glslang::EOpAtomicCounterCompSwap:
3585             if (arg == 0)
3586                 lvalue = true;
3587             break;
3588         case glslang::EOpAddCarry:
3589         case glslang::EOpSubBorrow:
3590             if (arg == 2)
3591                 lvalue = true;
3592             break;
3593         case glslang::EOpUMulExtended:
3594         case glslang::EOpIMulExtended:
3595             if (arg >= 2)
3596                 lvalue = true;
3597             break;
3598         case glslang::EOpCooperativeMatrixLoad:
3599         case glslang::EOpCooperativeMatrixLoadNV:
3600         case glslang::EOpCooperativeMatrixLoadTensorNV:
3601             if (arg == 0 || arg == 1)
3602                 lvalue = true;
3603             break;
3604         case glslang::EOpCooperativeMatrixStore:
3605         case glslang::EOpCooperativeMatrixStoreNV:
3606         case glslang::EOpCooperativeMatrixStoreTensorNV:
3607             if (arg == 1)
3608                 lvalue = true;
3609             break;
3610         case glslang::EOpCooperativeMatrixReduceNV:
3611         case glslang::EOpCooperativeMatrixPerElementOpNV:
3612         case glslang::EOpCooperativeMatrixTransposeNV:
3613             if (arg == 0)
3614                 lvalue = true;
3615             break;
3616         case glslang::EOpSpirvInst:
3617             if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference())
3618                 lvalue = true;
3619             break;
3620         case glslang::EOpReorderThreadNV:
3621             //Three variants of reorderThreadNV, two of them use hitObjectNV
3622             if (arg == 0 && glslangOperands.size() != 2)
3623                 lvalue = true;
3624             break;
3625         case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
3626             if (arg == 0 || arg == 2)
3627                 lvalue = true;
3628             break;
3629         default:
3630             break;
3631         }
3632         builder.clearAccessChain();
3633         if (invertedType != spv::NoType && arg == 0)
3634             glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this);
3635         else
3636             glslangOperands[arg]->traverse(this);
3637 
3638         if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3639             node->getOp() == glslang::EOpCooperativeMatrixStore ||
3640             node->getOp() == glslang::EOpCooperativeMatrixLoadNV ||
3641             node->getOp() == glslang::EOpCooperativeMatrixStoreNV ||
3642             node->getOp() == glslang::EOpCooperativeMatrixLoadTensorNV ||
3643             node->getOp() == glslang::EOpCooperativeMatrixStoreTensorNV) {
3644 
3645             if (arg == 1) {
3646                 // fold "element" parameter into the access chain
3647                 spv::Builder::AccessChain save = builder.getAccessChain();
3648                 builder.clearAccessChain();
3649                 glslangOperands[2]->traverse(this);
3650 
3651                 spv::Id elementId = accessChainLoad(glslangOperands[2]->getAsTyped()->getType());
3652 
3653                 builder.setAccessChain(save);
3654 
3655                 // Point to the first element of the array.
3656                 builder.accessChainPush(elementId,
3657                     TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()),
3658                                       glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment());
3659 
3660                 spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
3661                 unsigned int alignment = builder.getAccessChain().alignment;
3662 
3663                 int memoryAccess = TranslateMemoryAccess(coherentFlags);
3664                 if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3665                     node->getOp() == glslang::EOpCooperativeMatrixLoadNV ||
3666                     node->getOp() == glslang::EOpCooperativeMatrixLoadTensorNV)
3667                     memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask;
3668                 if (node->getOp() == glslang::EOpCooperativeMatrixStore ||
3669                     node->getOp() == glslang::EOpCooperativeMatrixStoreNV ||
3670                     node->getOp() == glslang::EOpCooperativeMatrixStoreTensorNV)
3671                     memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask;
3672                 if (builder.getStorageClass(builder.getAccessChain().base) ==
3673                     spv::StorageClassPhysicalStorageBufferEXT) {
3674                     memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3675                 }
3676 
3677                 memoryAccessOperands.push_back(spv::IdImmediate(false, memoryAccess));
3678 
3679                 if (memoryAccess & spv::MemoryAccessAlignedMask) {
3680                     memoryAccessOperands.push_back(spv::IdImmediate(false, alignment));
3681                 }
3682 
3683                 if (memoryAccess &
3684                     (spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) {
3685                     memoryAccessOperands.push_back(spv::IdImmediate(true,
3686                         builder.makeUintConstant(TranslateMemoryScope(coherentFlags))));
3687                 }
3688             } else if (arg == 2) {
3689                 continue;
3690             }
3691         }
3692 
3693         // for l-values, pass the address, for r-values, pass the value
3694         if (lvalue) {
3695             if (invertedType == spv::NoType && !builder.isSpvLvalue()) {
3696                 // SPIR-V cannot represent an l-value containing a swizzle that doesn't
3697                 // reduce to a simple access chain.  So, we need a temporary vector to
3698                 // receive the result, and must later swizzle that into the original
3699                 // l-value.
3700                 complexLvalues.push_back(builder.getAccessChain());
3701                 temporaryLvalues.push_back(builder.createVariable(
3702                     spv::NoPrecision, spv::StorageClassFunction,
3703                     builder.accessChainGetInferredType(), "swizzleTemp"));
3704                 operands.push_back(temporaryLvalues.back());
3705             } else {
3706                 operands.push_back(builder.accessChainGetLValue());
3707             }
3708             lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
3709             lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());
3710         } else {
3711             builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3712              glslang::TOperator glslangOp = node->getOp();
3713              if (arg == 1 &&
3714                 (glslangOp == glslang::EOpRayQueryGetIntersectionType ||
3715                  glslangOp == glslang::EOpRayQueryGetIntersectionT ||
3716                  glslangOp == glslang::EOpRayQueryGetIntersectionInstanceCustomIndex ||
3717                  glslangOp == glslang::EOpRayQueryGetIntersectionInstanceId ||
3718                  glslangOp == glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset ||
3719                  glslangOp == glslang::EOpRayQueryGetIntersectionGeometryIndex ||
3720                  glslangOp == glslang::EOpRayQueryGetIntersectionPrimitiveIndex ||
3721                  glslangOp == glslang::EOpRayQueryGetIntersectionBarycentrics ||
3722                  glslangOp == glslang::EOpRayQueryGetIntersectionFrontFace ||
3723                  glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection ||
3724                  glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin ||
3725                  glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld ||
3726                  glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject ||
3727                  glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT
3728                     )) {
3729                 bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst();
3730                 operands.push_back(builder.makeIntConstant(cond ? 1 : 0));
3731              } else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) ||
3732                         (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) ||
3733                         (arg == 1  && glslangOp == glslang::EOpExecuteCallableKHR) ||
3734                         (arg == 1  && glslangOp == glslang::EOpHitObjectExecuteShaderNV) ||
3735                         (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV) ||
3736                         (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV)) {
3737                  const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0;
3738                  const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();
3739                  auto itNode = locationToSymbol[set].find(location);
3740                  visitSymbol(itNode->second);
3741                  spv::Id symId = getSymbolId(itNode->second);
3742                  operands.push_back(symId);
3743             } else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV) ||
3744                        (arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV) ||
3745                        (arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV) ||
3746                        (arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV) ||
3747                        (arg == 1  && glslangOp == glslang::EOpHitObjectGetAttributesNV)) {
3748                  const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();
3749                  const int set = 2;
3750                  auto itNode = locationToSymbol[set].find(location);
3751                  visitSymbol(itNode->second);
3752                  spv::Id symId = getSymbolId(itNode->second);
3753                  operands.push_back(symId);
3754              } else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) {
3755                  // Will be translated to a literal value, make a placeholder here
3756                  operands.push_back(spv::NoResult);
3757              } else if (glslangOperands[arg]->getAsTyped()->getBasicType() == glslang::EbtFunction) {
3758                  spv::Function* function = functionMap[glslangOperands[arg]->getAsSymbolNode()->getMangledName().c_str()];
3759                  assert(function);
3760                  operands.push_back(function->getId());
3761              } else  {
3762                 operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
3763              }
3764         }
3765     }
3766 
3767     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3768     if (node->getOp() == glslang::EOpCooperativeMatrixLoadTensorNV) {
3769         std::vector<spv::IdImmediate> idImmOps;
3770 
3771         builder.addCapability(spv::CapabilityCooperativeMatrixTensorAddressingNV);
3772         builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3773 
3774         spv::Id object = builder.createLoad(operands[0], spv::NoPrecision);
3775 
3776         idImmOps.push_back(spv::IdImmediate(true, operands[1])); // Pointer
3777         idImmOps.push_back(spv::IdImmediate(true, object)); // Object
3778         idImmOps.push_back(spv::IdImmediate(true, operands[2])); // tensorLayout
3779 
3780         idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); // memoryaccess
3781 
3782         // initialize tensor operands to zero, then OR in flags based on the operands
3783         size_t tensorOpIdx = idImmOps.size();
3784         idImmOps.push_back(spv::IdImmediate(false, 0));
3785 
3786         for (uint32_t i = 3; i < operands.size(); ++i) {
3787             if (builder.isTensorView(operands[i])) {
3788                 idImmOps[tensorOpIdx].word |= spv::TensorAddressingOperandsTensorViewMask;
3789             } else {
3790                 // must be the decode func
3791                 idImmOps[tensorOpIdx].word |= spv::TensorAddressingOperandsDecodeFuncMask;
3792                 builder.addCapability(spv::CapabilityCooperativeMatrixBlockLoadsNV);
3793             }
3794             idImmOps.push_back(spv::IdImmediate(true, operands[i])); // tensorView or decodeFunc
3795         }
3796 
3797         // get the pointee type
3798         spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
3799         assert(builder.isCooperativeMatrixType(typeId));
3800         // do the op
3801         spv::Id result = builder.createOp(spv::OpCooperativeMatrixLoadTensorNV, typeId, idImmOps);
3802         // store the result to the pointer (out param 'm')
3803         builder.createStore(result, operands[0]);
3804         result = 0;
3805     } else if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3806                node->getOp() == glslang::EOpCooperativeMatrixLoadNV) {
3807         std::vector<spv::IdImmediate> idImmOps;
3808 
3809         idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
3810         if (node->getOp() == glslang::EOpCooperativeMatrixLoad) {
3811             idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout
3812             auto layout = builder.getConstantScalar(operands[3]);
3813             if (layout == spv::CooperativeMatrixLayoutRowBlockedInterleavedARM ||
3814                 layout == spv::CooperativeMatrixLayoutColumnBlockedInterleavedARM) {
3815                 builder.addExtension(spv::E_SPV_ARM_cooperative_matrix_layouts);
3816                 builder.addCapability(spv::CapabilityCooperativeMatrixLayoutsARM);
3817             }
3818             idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3819         } else {
3820             idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3821             idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
3822         }
3823         idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
3824         // get the pointee type
3825         spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
3826         assert(builder.isCooperativeMatrixType(typeId));
3827         // do the op
3828         spv::Id result = node->getOp() == glslang::EOpCooperativeMatrixLoad
3829                        ? builder.createOp(spv::OpCooperativeMatrixLoadKHR, typeId, idImmOps)
3830                        : builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps);
3831         // store the result to the pointer (out param 'm')
3832         builder.createStore(result, operands[0]);
3833         result = 0;
3834     } else if (node->getOp() == glslang::EOpCooperativeMatrixStoreTensorNV) {
3835         std::vector<spv::IdImmediate> idImmOps;
3836 
3837         idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
3838         idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
3839 
3840         builder.addCapability(spv::CapabilityCooperativeMatrixTensorAddressingNV);
3841         builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3842 
3843         idImmOps.push_back(spv::IdImmediate(true, operands[2])); // tensorLayout
3844 
3845         idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); // memoryaccess
3846 
3847         if (operands.size() > 3) {
3848             idImmOps.push_back(spv::IdImmediate(false, spv::TensorAddressingOperandsTensorViewMask));
3849             idImmOps.push_back(spv::IdImmediate(true, operands[3])); // tensorView
3850         } else {
3851             idImmOps.push_back(spv::IdImmediate(false, 0));
3852         }
3853 
3854         builder.createNoResultOp(spv::OpCooperativeMatrixStoreTensorNV, idImmOps);
3855         result = 0;
3856     } else if (node->getOp() == glslang::EOpCooperativeMatrixStore ||
3857                node->getOp() == glslang::EOpCooperativeMatrixStoreNV) {
3858         std::vector<spv::IdImmediate> idImmOps;
3859 
3860         idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
3861         idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
3862         if (node->getOp() == glslang::EOpCooperativeMatrixStore) {
3863             idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout
3864             auto layout = builder.getConstantScalar(operands[3]);
3865             if (layout == spv::CooperativeMatrixLayoutRowBlockedInterleavedARM ||
3866                 layout == spv::CooperativeMatrixLayoutColumnBlockedInterleavedARM) {
3867                 builder.addExtension(spv::E_SPV_ARM_cooperative_matrix_layouts);
3868                 builder.addCapability(spv::CapabilityCooperativeMatrixLayoutsARM);
3869             }
3870             idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3871         } else {
3872             idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3873             idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
3874         }
3875         idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
3876 
3877         if (node->getOp() == glslang::EOpCooperativeMatrixStore)
3878             builder.createNoResultOp(spv::OpCooperativeMatrixStoreKHR, idImmOps);
3879         else
3880             builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps);
3881         result = 0;
3882     } else if (node->getOp() == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT) {
3883         std::vector<spv::IdImmediate> idImmOps;
3884 
3885         idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q
3886         idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed
3887 
3888         spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),
3889                                                builder.makeUintConstant(3), 0);
3890         // do the op
3891 
3892         spv::Op spvOp = spv::OpRayQueryGetIntersectionTriangleVertexPositionsKHR;
3893 
3894         spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
3895         // store the result to the pointer (out param 'm')
3896         builder.createStore(result, operands[2]);
3897         result = 0;
3898     } else if (node->getOp() == glslang::EOpCooperativeMatrixMulAdd) {
3899         uint32_t matrixOperands = 0;
3900 
3901         // If the optional operand is present, initialize matrixOperands to that value.
3902         if (glslangOperands.size() == 4 && glslangOperands[3]->getAsConstantUnion()) {
3903             matrixOperands = glslangOperands[3]->getAsConstantUnion()->getConstArray()[0].getIConst();
3904         }
3905 
3906         // Determine Cooperative Matrix Operands bits from the signedness of the types.
3907         if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType()))
3908             matrixOperands |= spv::CooperativeMatrixOperandsMatrixASignedComponentsKHRMask;
3909         if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType()))
3910             matrixOperands |= spv::CooperativeMatrixOperandsMatrixBSignedComponentsKHRMask;
3911         if (isTypeSignedInt(glslangOperands[2]->getAsTyped()->getBasicType()))
3912             matrixOperands |= spv::CooperativeMatrixOperandsMatrixCSignedComponentsKHRMask;
3913         if (isTypeSignedInt(node->getBasicType()))
3914             matrixOperands |= spv::CooperativeMatrixOperandsMatrixResultSignedComponentsKHRMask;
3915 
3916         std::vector<spv::IdImmediate> idImmOps;
3917         idImmOps.push_back(spv::IdImmediate(true, operands[0]));
3918         idImmOps.push_back(spv::IdImmediate(true, operands[1]));
3919         idImmOps.push_back(spv::IdImmediate(true, operands[2]));
3920         if (matrixOperands != 0)
3921             idImmOps.push_back(spv::IdImmediate(false, matrixOperands));
3922 
3923         result = builder.createOp(spv::OpCooperativeMatrixMulAddKHR, resultType(), idImmOps);
3924     } else if (node->getOp() == glslang::EOpCooperativeMatrixReduceNV) {
3925         builder.addCapability(spv::CapabilityCooperativeMatrixReductionsNV);
3926         builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3927 
3928         spv::Op opcode = spv::OpCooperativeMatrixReduceNV;
3929         unsigned mask = glslangOperands[2]->getAsConstantUnion()->getConstArray()[0].getUConst();
3930 
3931         spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
3932         assert(builder.isCooperativeMatrixType(typeId));
3933 
3934         result = builder.createCooperativeMatrixReduce(opcode, typeId, operands[1], mask, operands[3]);
3935         // store the result to the pointer (out param 'm')
3936         builder.createStore(result, operands[0]);
3937         result = 0;
3938     } else if (node->getOp() == glslang::EOpCooperativeMatrixPerElementOpNV) {
3939         builder.addCapability(spv::CapabilityCooperativeMatrixPerElementOperationsNV);
3940         builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3941 
3942         spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
3943         assert(builder.isCooperativeMatrixType(typeId));
3944 
3945         result = builder.createCooperativeMatrixPerElementOp(typeId, operands);
3946         // store the result to the pointer
3947         builder.createStore(result, operands[0]);
3948         result = 0;
3949     } else if (node->getOp() == glslang::EOpCooperativeMatrixTransposeNV) {
3950 
3951         builder.addCapability(spv::CapabilityCooperativeMatrixConversionsNV);
3952         builder.addExtension(spv::E_SPV_NV_cooperative_matrix2);
3953 
3954         spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
3955         assert(builder.isCooperativeMatrixType(typeId));
3956 
3957         result = builder.createUnaryOp(spv::OpCooperativeMatrixTransposeNV, typeId, operands[1]);
3958         // store the result to the pointer
3959         builder.createStore(result, operands[0]);
3960         result = 0;
3961     } else if (atomic) {
3962         // Handle all atomics
3963         glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore)
3964             ? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType();
3965         result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,
3966             lvalueCoherentFlags, node->getType());
3967     } else if (node->getOp() == glslang::EOpSpirvInst) {
3968         const auto& spirvInst = node->getSpirvInstruction();
3969         if (spirvInst.set == "") {
3970             std::vector<spv::IdImmediate> idImmOps;
3971             for (unsigned int i = 0; i < glslangOperands.size(); ++i) {
3972                 if (glslangOperands[i]->getAsTyped()->getQualifier().isSpirvLiteral()) {
3973                     // Translate the constant to a literal value
3974                     std::vector<unsigned> literals;
3975                     glslang::TVector<const glslang::TIntermConstantUnion*> constants;
3976                     constants.push_back(glslangOperands[i]->getAsConstantUnion());
3977                     TranslateLiterals(constants, literals);
3978                     idImmOps.push_back({false, literals[0]});
3979                 } else
3980                     idImmOps.push_back({true, operands[i]});
3981             }
3982 
3983             if (node->getBasicType() == glslang::EbtVoid)
3984                 builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), idImmOps);
3985             else
3986                 result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), idImmOps);
3987         } else {
3988             result = builder.createBuiltinCall(
3989                 resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),
3990                 spirvInst.id, operands);
3991         }
3992         noReturnValue = node->getBasicType() == glslang::EbtVoid;
3993     } else if (node->getOp() == glslang::EOpDebugPrintf) {
3994         if (!nonSemanticDebugPrintf) {
3995             nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf");
3996         }
3997         result = builder.createBuiltinCall(builder.makeVoidType(), nonSemanticDebugPrintf, spv::NonSemanticDebugPrintfDebugPrintf, operands);
3998         builder.addExtension(spv::E_SPV_KHR_non_semantic_info);
3999     } else {
4000         // Pass through to generic operations.
4001         switch (glslangOperands.size()) {
4002         case 0:
4003             result = createNoArgOperation(node->getOp(), precision, resultType());
4004             break;
4005         case 1:
4006             {
4007                 OpDecorations decorations = { precision,
4008                                               TranslateNoContractionDecoration(node->getType().getQualifier()),
4009                                               TranslateNonUniformDecoration(node->getType().getQualifier()) };
4010                 result = createUnaryOperation(
4011                     node->getOp(), decorations,
4012                     resultType(), operands.front(),
4013                     glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags, node->getType());
4014             }
4015             break;
4016         default:
4017             result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());
4018             break;
4019         }
4020 
4021         if (invertedType != spv::NoResult)
4022             result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result);
4023 
4024         for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) {
4025             builder.setAccessChain(complexLvalues[i]);
4026             builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision),
4027                 TranslateNonUniformDecoration(complexLvalues[i].coherentFlags));
4028         }
4029     }
4030 
4031     if (noReturnValue)
4032         return false;
4033 
4034     if (! result) {
4035         logger->missingFunctionality("unknown glslang aggregate");
4036         return true;  // pick up a child as a placeholder operand
4037     } else {
4038         builder.clearAccessChain();
4039         builder.setAccessChainRValue(result);
4040         return false;
4041     }
4042 }
4043 
4044 // This path handles both if-then-else and ?:
4045 // The if-then-else has a node type of void, while
4046 // ?: has either a void or a non-void node type
4047 //
4048 // Leaving the result, when not void:
4049 // GLSL only has r-values as the result of a :?, but
4050 // if we have an l-value, that can be more efficient if it will
4051 // become the base of a complex r-value expression, because the
4052 // next layer copies r-values into memory to use the access-chain mechanism
visitSelection(glslang::TVisit,glslang::TIntermSelection * node)4053 bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
4054 {
4055     // see if OpSelect can handle it
4056     const auto isOpSelectable = [&]() {
4057         if (node->getBasicType() == glslang::EbtVoid)
4058             return false;
4059         // OpSelect can do all other types starting with SPV 1.4
4060         if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4) {
4061             // pre-1.4, only scalars and vectors can be handled
4062             if ((!node->getType().isScalar() && !node->getType().isVector()))
4063                 return false;
4064         }
4065         return true;
4066     };
4067 
4068     // See if it simple and safe, or required, to execute both sides.
4069     // Crucially, side effects must be either semantically required or avoided,
4070     // and there are performance trade-offs.
4071     // Return true if required or a good idea (and safe) to execute both sides,
4072     // false otherwise.
4073     const auto bothSidesPolicy = [&]() -> bool {
4074         // do we have both sides?
4075         if (node->getTrueBlock()  == nullptr ||
4076             node->getFalseBlock() == nullptr)
4077             return false;
4078 
4079         // required? (unless we write additional code to look for side effects
4080         // and make performance trade-offs if none are present)
4081         if (!node->getShortCircuit())
4082             return true;
4083 
4084         // if not required to execute both, decide based on performance/practicality...
4085 
4086         if (!isOpSelectable())
4087             return false;
4088 
4089         assert(node->getType() == node->getTrueBlock() ->getAsTyped()->getType() &&
4090                node->getType() == node->getFalseBlock()->getAsTyped()->getType());
4091 
4092         // return true if a single operand to ? : is okay for OpSelect
4093         const auto operandOkay = [](glslang::TIntermTyped* node) {
4094             return node->getAsSymbolNode() || node->getType().getQualifier().isConstant();
4095         };
4096 
4097         return operandOkay(node->getTrueBlock() ->getAsTyped()) &&
4098                operandOkay(node->getFalseBlock()->getAsTyped());
4099     };
4100 
4101     spv::Id result = spv::NoResult; // upcoming result selecting between trueValue and falseValue
4102     // emit the condition before doing anything with selection
4103     node->getCondition()->traverse(this);
4104     spv::Id condition = accessChainLoad(node->getCondition()->getType());
4105 
4106     // Find a way of executing both sides and selecting the right result.
4107     const auto executeBothSides = [&]() -> void {
4108         // execute both sides
4109         spv::Id resultType = convertGlslangToSpvType(node->getType());
4110         node->getTrueBlock()->traverse(this);
4111         spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
4112         node->getFalseBlock()->traverse(this);
4113         spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
4114 
4115         builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4116 
4117         // done if void
4118         if (node->getBasicType() == glslang::EbtVoid)
4119             return;
4120 
4121         // emit code to select between trueValue and falseValue
4122         // see if OpSelect can handle the result type, and that the SPIR-V types
4123         // of the inputs match the result type.
4124         if (isOpSelectable()) {
4125             // Emit OpSelect for this selection.
4126 
4127             // smear condition to vector, if necessary (AST is always scalar)
4128             // Before 1.4, smear like for mix(), starting with 1.4, keep it scalar
4129             if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) {
4130                 condition = builder.smearScalar(spv::NoPrecision, condition,
4131                                                 builder.makeVectorType(builder.makeBoolType(),
4132                                                                        builder.getNumComponents(trueValue)));
4133             }
4134 
4135             // If the types do not match, it is because of mismatched decorations on aggregates.
4136             // Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject
4137             // to get matching types.
4138             if (builder.getTypeId(trueValue) != resultType) {
4139                 trueValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, trueValue);
4140             }
4141             if (builder.getTypeId(falseValue) != resultType) {
4142                 falseValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, falseValue);
4143             }
4144 
4145             // OpSelect
4146             result = builder.createTriOp(spv::OpSelect, resultType, condition, trueValue, falseValue);
4147 
4148             builder.clearAccessChain();
4149             builder.setAccessChainRValue(result);
4150         } else {
4151             // We need control flow to select the result.
4152             // TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.
4153             result = builder.createVariable(TranslatePrecisionDecoration(node->getType()),
4154                 spv::StorageClassFunction, resultType);
4155 
4156             // Selection control:
4157             const spv::SelectionControlMask control = TranslateSelectionControl(*node);
4158 
4159             // make an "if" based on the value created by the condition
4160             spv::Builder::If ifBuilder(condition, control, builder);
4161 
4162             // emit the "then" statement
4163             builder.clearAccessChain();
4164             builder.setAccessChainLValue(result);
4165             multiTypeStore(node->getType(), trueValue);
4166 
4167             ifBuilder.makeBeginElse();
4168             // emit the "else" statement
4169             builder.clearAccessChain();
4170             builder.setAccessChainLValue(result);
4171             multiTypeStore(node->getType(), falseValue);
4172 
4173             // finish off the control flow
4174             ifBuilder.makeEndIf();
4175 
4176             builder.clearAccessChain();
4177             builder.setAccessChainLValue(result);
4178         }
4179     };
4180 
4181     // Execute the one side needed, as per the condition
4182     const auto executeOneSide = [&]() {
4183         // Always emit control flow.
4184         if (node->getBasicType() != glslang::EbtVoid) {
4185             result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), spv::StorageClassFunction,
4186                 convertGlslangToSpvType(node->getType()));
4187         }
4188 
4189         // Selection control:
4190         const spv::SelectionControlMask control = TranslateSelectionControl(*node);
4191 
4192         // make an "if" based on the value created by the condition
4193         spv::Builder::If ifBuilder(condition, control, builder);
4194 
4195         // emit the "then" statement
4196         if (node->getTrueBlock() != nullptr) {
4197             node->getTrueBlock()->traverse(this);
4198             if (result != spv::NoResult) {
4199                 spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
4200 
4201                 builder.clearAccessChain();
4202                 builder.setAccessChainLValue(result);
4203                 multiTypeStore(node->getType(), load);
4204             }
4205         }
4206 
4207         if (node->getFalseBlock() != nullptr) {
4208             ifBuilder.makeBeginElse();
4209             // emit the "else" statement
4210             node->getFalseBlock()->traverse(this);
4211             if (result != spv::NoResult) {
4212                 spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
4213 
4214                 builder.clearAccessChain();
4215                 builder.setAccessChainLValue(result);
4216                 multiTypeStore(node->getType(), load);
4217             }
4218         }
4219 
4220         // finish off the control flow
4221         ifBuilder.makeEndIf();
4222 
4223         if (result != spv::NoResult) {
4224             builder.clearAccessChain();
4225             builder.setAccessChainLValue(result);
4226         }
4227     };
4228 
4229     // Try for OpSelect (or a requirement to execute both sides)
4230     if (bothSidesPolicy()) {
4231         SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
4232         if (node->getType().getQualifier().isSpecConstant())
4233             spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
4234         executeBothSides();
4235     } else
4236         executeOneSide();
4237 
4238     return false;
4239 }
4240 
visitSwitch(glslang::TVisit,glslang::TIntermSwitch * node)4241 bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
4242 {
4243     // emit and get the condition before doing anything with switch
4244     node->getCondition()->traverse(this);
4245     spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
4246 
4247     // Selection control:
4248     const spv::SelectionControlMask control = TranslateSwitchControl(*node);
4249 
4250     // browse the children to sort out code segments
4251     int defaultSegment = -1;
4252     std::vector<TIntermNode*> codeSegments;
4253     glslang::TIntermSequence& sequence = node->getBody()->getSequence();
4254     std::vector<int> caseValues;
4255     std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate
4256     for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
4257         TIntermNode* child = *c;
4258         if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
4259             defaultSegment = (int)codeSegments.size();
4260         else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
4261             valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
4262             caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()
4263                 ->getConstArray()[0].getIConst());
4264         } else
4265             codeSegments.push_back(child);
4266     }
4267 
4268     // handle the case where the last code segment is missing, due to no code
4269     // statements between the last case and the end of the switch statement
4270     if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
4271         (int)codeSegments.size() == defaultSegment)
4272         codeSegments.push_back(nullptr);
4273 
4274     // make the switch statement
4275     std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
4276     builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment,
4277         segmentBlocks);
4278 
4279     // emit all the code in the segments
4280     breakForLoop.push(false);
4281     for (unsigned int s = 0; s < codeSegments.size(); ++s) {
4282         builder.nextSwitchSegment(segmentBlocks, s);
4283         if (codeSegments[s])
4284             codeSegments[s]->traverse(this);
4285         else
4286             builder.addSwitchBreak(true);
4287     }
4288     breakForLoop.pop();
4289 
4290     builder.endSwitch(segmentBlocks);
4291 
4292     return false;
4293 }
4294 
visitConstantUnion(glslang::TIntermConstantUnion * node)4295 void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
4296 {
4297     if (node->getQualifier().isSpirvLiteral())
4298         return; // Translated to a literal value, skip further processing
4299 
4300     int nextConst = 0;
4301     spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
4302 
4303     builder.clearAccessChain();
4304     builder.setAccessChainRValue(constant);
4305 }
4306 
visitLoop(glslang::TVisit,glslang::TIntermLoop * node)4307 bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
4308 {
4309     auto blocks = builder.makeNewLoop();
4310     builder.createBranch(true, &blocks.head);
4311 
4312     // Loop control:
4313     std::vector<unsigned int> operands;
4314     const spv::LoopControlMask control = TranslateLoopControl(*node, operands);
4315 
4316     // Spec requires back edges to target header blocks, and every header block
4317     // must dominate its merge block.  Make a header block first to ensure these
4318     // conditions are met.  By definition, it will contain OpLoopMerge, followed
4319     // by a block-ending branch.  But we don't want to put any other body/test
4320     // instructions in it, since the body/test may have arbitrary instructions,
4321     // including merges of its own.
4322     builder.setBuildPoint(&blocks.head);
4323     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4324     builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);
4325     if (node->testFirst() && node->getTest()) {
4326         spv::Block& test = builder.makeNewBlock();
4327         builder.createBranch(true, &test);
4328 
4329         builder.setBuildPoint(&test);
4330         node->getTest()->traverse(this);
4331         spv::Id condition = accessChainLoad(node->getTest()->getType());
4332         builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
4333 
4334         builder.setBuildPoint(&blocks.body);
4335         breakForLoop.push(true);
4336         if (node->getBody())
4337             node->getBody()->traverse(this);
4338         builder.createBranch(true, &blocks.continue_target);
4339         breakForLoop.pop();
4340 
4341         builder.setBuildPoint(&blocks.continue_target);
4342         if (node->getTerminal())
4343             node->getTerminal()->traverse(this);
4344         builder.createBranch(true, &blocks.head);
4345     } else {
4346         builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4347         builder.createBranch(true, &blocks.body);
4348 
4349         breakForLoop.push(true);
4350         builder.setBuildPoint(&blocks.body);
4351         if (node->getBody())
4352             node->getBody()->traverse(this);
4353         builder.createBranch(true, &blocks.continue_target);
4354         breakForLoop.pop();
4355 
4356         builder.setBuildPoint(&blocks.continue_target);
4357         if (node->getTerminal())
4358             node->getTerminal()->traverse(this);
4359         if (node->getTest()) {
4360             node->getTest()->traverse(this);
4361             spv::Id condition =
4362                 accessChainLoad(node->getTest()->getType());
4363             builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
4364         } else {
4365             // TODO: unless there was a break/return/discard instruction
4366             // somewhere in the body, this is an infinite loop, so we should
4367             // issue a warning.
4368             builder.createBranch(true, &blocks.head);
4369         }
4370     }
4371     builder.setBuildPoint(&blocks.merge);
4372     builder.closeLoop();
4373     return false;
4374 }
4375 
visitBranch(glslang::TVisit,glslang::TIntermBranch * node)4376 bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
4377 {
4378     if (node->getExpression())
4379         node->getExpression()->traverse(this);
4380 
4381     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4382 
4383     switch (node->getFlowOp()) {
4384     case glslang::EOpKill:
4385         if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
4386             if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
4387               builder.addCapability(spv::CapabilityDemoteToHelperInvocation);
4388               builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
4389             } else {
4390                 builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation");
4391             }
4392         } else {
4393             builder.makeStatementTerminator(spv::OpKill, "post-discard");
4394         }
4395         break;
4396     case glslang::EOpTerminateInvocation:
4397         builder.addExtension(spv::E_SPV_KHR_terminate_invocation);
4398         builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation");
4399         break;
4400     case glslang::EOpBreak:
4401         if (breakForLoop.top())
4402             builder.createLoopExit();
4403         else
4404             builder.addSwitchBreak(false);
4405         break;
4406     case glslang::EOpContinue:
4407         builder.createLoopContinue();
4408         break;
4409     case glslang::EOpReturn:
4410         if (node->getExpression() != nullptr) {
4411             const glslang::TType& glslangReturnType = node->getExpression()->getType();
4412             spv::Id returnId = accessChainLoad(glslangReturnType);
4413             if (builder.getTypeId(returnId) != currentFunction->getReturnType() ||
4414                 TranslatePrecisionDecoration(glslangReturnType) != currentFunction->getReturnPrecision()) {
4415                 builder.clearAccessChain();
4416                 spv::Id copyId = builder.createVariable(currentFunction->getReturnPrecision(),
4417                     spv::StorageClassFunction, currentFunction->getReturnType());
4418                 builder.setAccessChainLValue(copyId);
4419                 multiTypeStore(glslangReturnType, returnId);
4420                 returnId = builder.createLoad(copyId, currentFunction->getReturnPrecision());
4421             }
4422             builder.makeReturn(false, returnId);
4423         } else
4424             builder.makeReturn(false);
4425 
4426         builder.clearAccessChain();
4427         break;
4428 
4429     case glslang::EOpDemote:
4430         builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
4431         builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
4432         builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);
4433         break;
4434     case glslang::EOpTerminateRayKHR:
4435         builder.makeStatementTerminator(spv::OpTerminateRayKHR, "post-terminateRayKHR");
4436         break;
4437     case glslang::EOpIgnoreIntersectionKHR:
4438         builder.makeStatementTerminator(spv::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR");
4439         break;
4440 
4441     default:
4442         assert(0);
4443         break;
4444     }
4445 
4446     return false;
4447 }
4448 
createSpvVariable(const glslang::TIntermSymbol * node,spv::Id forcedType)4449 spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node, spv::Id forcedType)
4450 {
4451     // First, steer off constants, which are not SPIR-V variables, but
4452     // can still have a mapping to a SPIR-V Id.
4453     // This includes specialization constants.
4454     if (node->getQualifier().isConstant()) {
4455         spv::Id result = createSpvConstant(*node);
4456         if (result != spv::NoResult)
4457             return result;
4458     }
4459 
4460     // Now, handle actual variables
4461     spv::StorageClass storageClass = TranslateStorageClass(node->getType());
4462     spv::Id spvType = forcedType == spv::NoType ? convertGlslangToSpvType(node->getType())
4463                                                 : forcedType;
4464 
4465     const bool contains16BitType = node->getType().contains16BitFloat() ||
4466                                    node->getType().contains16BitInt();
4467     if (contains16BitType) {
4468         switch (storageClass) {
4469         case spv::StorageClassInput:
4470         case spv::StorageClassOutput:
4471             builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4472             builder.addCapability(spv::CapabilityStorageInputOutput16);
4473             break;
4474         case spv::StorageClassUniform:
4475             builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4476             if (node->getType().getQualifier().storage == glslang::EvqBuffer)
4477                 builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
4478             else
4479                 builder.addCapability(spv::CapabilityStorageUniform16);
4480             break;
4481         case spv::StorageClassPushConstant:
4482             builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4483             builder.addCapability(spv::CapabilityStoragePushConstant16);
4484             break;
4485         case spv::StorageClassStorageBuffer:
4486         case spv::StorageClassPhysicalStorageBufferEXT:
4487             builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4488             builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
4489             break;
4490         default:
4491             if (storageClass == spv::StorageClassWorkgroup &&
4492                 node->getType().getBasicType() == glslang::EbtBlock) {
4493                 builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR);
4494                 break;
4495             }
4496             if (node->getType().contains16BitFloat())
4497                 builder.addCapability(spv::CapabilityFloat16);
4498             if (node->getType().contains16BitInt())
4499                 builder.addCapability(spv::CapabilityInt16);
4500             break;
4501         }
4502     }
4503 
4504     if (node->getType().contains8BitInt()) {
4505         if (storageClass == spv::StorageClassPushConstant) {
4506             builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
4507             builder.addCapability(spv::CapabilityStoragePushConstant8);
4508         } else if (storageClass == spv::StorageClassUniform) {
4509             builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
4510             builder.addCapability(spv::CapabilityUniformAndStorageBuffer8BitAccess);
4511         } else if (storageClass == spv::StorageClassStorageBuffer) {
4512             builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
4513             builder.addCapability(spv::CapabilityStorageBuffer8BitAccess);
4514         } else if (storageClass == spv::StorageClassWorkgroup &&
4515                    node->getType().getBasicType() == glslang::EbtBlock) {
4516             builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR);
4517         } else {
4518             builder.addCapability(spv::CapabilityInt8);
4519         }
4520     }
4521 
4522     const char* name = node->getName().c_str();
4523     if (glslang::IsAnonymous(name))
4524         name = "";
4525 
4526     spv::Id initializer = spv::NoResult;
4527 
4528     if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) {
4529         int nextConst = 0;
4530         initializer = createSpvConstantFromConstUnionArray(node->getType(),
4531                                                            node->getConstArray(),
4532                                                            nextConst,
4533                                                            false /* specConst */);
4534     } else if (node->getType().getQualifier().isNullInit()) {
4535         initializer = builder.makeNullConstant(spvType);
4536     }
4537 
4538     spv::Id var = builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer, false);
4539     std::vector<spv::Decoration> topLevelDecorations;
4540     glslang::TQualifier typeQualifier = node->getType().getQualifier();
4541     TranslateMemoryDecoration(typeQualifier, topLevelDecorations, glslangIntermediate->usingVulkanMemoryModel());
4542     for (auto deco : topLevelDecorations) {
4543         builder.addDecoration(var, deco);
4544     }
4545     return var;
4546 }
4547 
4548 // Return type Id of the sampled type.
getSampledType(const glslang::TSampler & sampler)4549 spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
4550 {
4551     switch (sampler.type) {
4552         case glslang::EbtInt:      return builder.makeIntType(32);
4553         case glslang::EbtUint:     return builder.makeUintType(32);
4554         case glslang::EbtFloat:    return builder.makeFloatType(32);
4555         case glslang::EbtFloat16:
4556             builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch);
4557             builder.addCapability(spv::CapabilityFloat16ImageAMD);
4558             return builder.makeFloatType(16);
4559         case glslang::EbtInt64:
4560             builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
4561             builder.addCapability(spv::CapabilityInt64ImageEXT);
4562             return builder.makeIntType(64);
4563         case glslang::EbtUint64:
4564             builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
4565             builder.addCapability(spv::CapabilityInt64ImageEXT);
4566             return builder.makeUintType(64);
4567         default:
4568             assert(0);
4569             return builder.makeFloatType(32);
4570     }
4571 }
4572 
4573 // If node is a swizzle operation, return the type that should be used if
4574 // the swizzle base is first consumed by another operation, before the swizzle
4575 // is applied.
getInvertedSwizzleType(const glslang::TIntermTyped & node)4576 spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node)
4577 {
4578     if (node.getAsOperator() &&
4579         node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
4580         return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType());
4581     else
4582         return spv::NoType;
4583 }
4584 
4585 // When inverting a swizzle with a parent op, this function
4586 // will apply the swizzle operation to a completed parent operation.
createInvertedSwizzle(spv::Decoration precision,const glslang::TIntermTyped & node,spv::Id parentResult)4587 spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node,
4588     spv::Id parentResult)
4589 {
4590     std::vector<unsigned> swizzle;
4591     convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle);
4592     return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle);
4593 }
4594 
4595 // Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.
convertSwizzle(const glslang::TIntermAggregate & node,std::vector<unsigned> & swizzle)4596 void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector<unsigned>& swizzle)
4597 {
4598     const glslang::TIntermSequence& swizzleSequence = node.getSequence();
4599     for (int i = 0; i < (int)swizzleSequence.size(); ++i)
4600         swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
4601 }
4602 
4603 // Convert from a glslang type to an SPV type, by calling into a
4604 // recursive version of this function. This establishes the inherited
4605 // layout state rooted from the top-level type.
convertGlslangToSpvType(const glslang::TType & type,bool forwardReferenceOnly)4606 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)
4607 {
4608     return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
4609 }
4610 
convertGlslangLinkageToSpv(glslang::TLinkType linkType)4611 spv::LinkageType TGlslangToSpvTraverser::convertGlslangLinkageToSpv(glslang::TLinkType linkType)
4612 {
4613     switch (linkType) {
4614     case glslang::ELinkExport:
4615         return spv::LinkageTypeExport;
4616     default:
4617         return spv::LinkageTypeMax;
4618     }
4619 }
4620 
4621 // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
4622 // explicitLayout can be kept the same throughout the hierarchical recursive walk.
4623 // Mutually recursive with convertGlslangStructToSpvType().
convertGlslangToSpvType(const glslang::TType & type,glslang::TLayoutPacking explicitLayout,const glslang::TQualifier & qualifier,bool lastBufferBlockMember,bool forwardReferenceOnly)4624 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,
4625     glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,
4626     bool lastBufferBlockMember, bool forwardReferenceOnly)
4627 {
4628     spv::Id spvType = spv::NoResult;
4629 
4630     switch (type.getBasicType()) {
4631     case glslang::EbtVoid:
4632         spvType = builder.makeVoidType();
4633         assert (! type.isArray());
4634         break;
4635     case glslang::EbtBool:
4636         // "transparent" bool doesn't exist in SPIR-V.  The GLSL convention is
4637         // a 32-bit int where non-0 means true.
4638         if (explicitLayout != glslang::ElpNone)
4639             spvType = builder.makeUintType(32);
4640         else
4641             spvType = builder.makeBoolType();
4642         break;
4643     case glslang::EbtInt:
4644         spvType = builder.makeIntType(32);
4645         break;
4646     case glslang::EbtUint:
4647         spvType = builder.makeUintType(32);
4648         break;
4649     case glslang::EbtFloat:
4650         spvType = builder.makeFloatType(32);
4651         break;
4652     case glslang::EbtDouble:
4653         spvType = builder.makeFloatType(64);
4654         break;
4655     case glslang::EbtFloat16:
4656         spvType = builder.makeFloatType(16);
4657         break;
4658     case glslang::EbtInt8:
4659         spvType = builder.makeIntType(8);
4660         break;
4661     case glslang::EbtUint8:
4662         spvType = builder.makeUintType(8);
4663         break;
4664     case glslang::EbtInt16:
4665         spvType = builder.makeIntType(16);
4666         break;
4667     case glslang::EbtUint16:
4668         spvType = builder.makeUintType(16);
4669         break;
4670     case glslang::EbtInt64:
4671         spvType = builder.makeIntType(64);
4672         break;
4673     case glslang::EbtUint64:
4674         spvType = builder.makeUintType(64);
4675         break;
4676     case glslang::EbtAtomicUint:
4677         builder.addCapability(spv::CapabilityAtomicStorage);
4678         spvType = builder.makeUintType(32);
4679         break;
4680     case glslang::EbtAccStruct:
4681         switch (glslangIntermediate->getStage()) {
4682         case EShLangRayGen:
4683         case EShLangIntersect:
4684         case EShLangAnyHit:
4685         case EShLangClosestHit:
4686         case EShLangMiss:
4687         case EShLangCallable:
4688             // these all should have the RayTracingNV/KHR capability already
4689             break;
4690         default:
4691             {
4692                 auto& extensions = glslangIntermediate->getRequestedExtensions();
4693                 if (extensions.find("GL_EXT_ray_query") != extensions.end()) {
4694                     builder.addExtension(spv::E_SPV_KHR_ray_query);
4695                     builder.addCapability(spv::CapabilityRayQueryKHR);
4696                 }
4697             }
4698             break;
4699         }
4700         spvType = builder.makeAccelerationStructureType();
4701         break;
4702     case glslang::EbtRayQuery:
4703         {
4704             auto& extensions = glslangIntermediate->getRequestedExtensions();
4705             if (extensions.find("GL_EXT_ray_query") != extensions.end()) {
4706                 builder.addExtension(spv::E_SPV_KHR_ray_query);
4707                 builder.addCapability(spv::CapabilityRayQueryKHR);
4708             }
4709             spvType = builder.makeRayQueryType();
4710         }
4711         break;
4712     case glslang::EbtReference:
4713         {
4714             // Make the forward pointer, then recurse to convert the structure type, then
4715             // patch up the forward pointer with a real pointer type.
4716             if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {
4717                 spv::Id forwardId = builder.makeForwardPointer(spv::StorageClassPhysicalStorageBufferEXT);
4718                 forwardPointers[type.getReferentType()] = forwardId;
4719             }
4720             spvType = forwardPointers[type.getReferentType()];
4721             if (!forwardReferenceOnly) {
4722                 spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());
4723                 builder.makePointerFromForwardPointer(spv::StorageClassPhysicalStorageBufferEXT,
4724                                                       forwardPointers[type.getReferentType()],
4725                                                       referentType);
4726             }
4727         }
4728         break;
4729     case glslang::EbtSampler:
4730         {
4731             const glslang::TSampler& sampler = type.getSampler();
4732             if (sampler.isPureSampler()) {
4733                 spvType = builder.makeSamplerType();
4734             } else {
4735                 // an image is present, make its type
4736                 spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler),
4737                                                 sampler.isShadow(), sampler.isArrayed(), sampler.isMultiSample(),
4738                                                 sampler.isImageClass() ? 2 : 1, TranslateImageFormat(type));
4739                 if (sampler.isCombined() &&
4740                     (!sampler.isBuffer() || glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6)) {
4741                     // Already has both image and sampler, make the combined type. Only combine sampler to
4742                     // buffer if before SPIR-V 1.6.
4743                     spvType = builder.makeSampledImageType(spvType);
4744                 }
4745             }
4746         }
4747         break;
4748     case glslang::EbtStruct:
4749     case glslang::EbtBlock:
4750         {
4751             // If we've seen this struct type, return it
4752             const glslang::TTypeList* glslangMembers = type.getStruct();
4753 
4754             // Try to share structs for different layouts, but not yet for other
4755             // kinds of qualification (primarily not yet including interpolant qualification).
4756             if (! HasNonLayoutQualifiers(type, qualifier))
4757                 spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers];
4758             if (spvType != spv::NoResult)
4759                 break;
4760 
4761             // else, we haven't seen it...
4762             if (type.getBasicType() == glslang::EbtBlock)
4763                 memberRemapper[glslangTypeToIdMap[glslangMembers]].resize(glslangMembers->size());
4764             spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
4765         }
4766         break;
4767     case glslang::EbtString:
4768         // no type used for OpString
4769         return 0;
4770 
4771     case glslang::EbtHitObjectNV: {
4772         builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);
4773         builder.addCapability(spv::CapabilityShaderInvocationReorderNV);
4774         spvType = builder.makeHitObjectNVType();
4775     }
4776     break;
4777     case glslang::EbtSpirvType: {
4778         // GL_EXT_spirv_intrinsics
4779         const auto& spirvType = type.getSpirvType();
4780         const auto& spirvInst = spirvType.spirvInst;
4781 
4782         std::vector<spv::IdImmediate> operands;
4783         for (const auto& typeParam : spirvType.typeParams) {
4784             if (typeParam.getAsConstant() != nullptr) {
4785                 // Constant expression
4786                 auto constant = typeParam.getAsConstant();
4787                 if (constant->isLiteral()) {
4788                     if (constant->getBasicType() == glslang::EbtFloat) {
4789                         float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());
4790                         unsigned literal;
4791                         static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");
4792                         memcpy(&literal, &floatValue, sizeof(literal));
4793                         operands.push_back({false, literal});
4794                     } else if (constant->getBasicType() == glslang::EbtInt) {
4795                         unsigned literal = constant->getConstArray()[0].getIConst();
4796                         operands.push_back({false, literal});
4797                     } else if (constant->getBasicType() == glslang::EbtUint) {
4798                         unsigned literal = constant->getConstArray()[0].getUConst();
4799                         operands.push_back({false, literal});
4800                     } else if (constant->getBasicType() == glslang::EbtBool) {
4801                         unsigned literal = constant->getConstArray()[0].getBConst();
4802                         operands.push_back({false, literal});
4803                     } else if (constant->getBasicType() == glslang::EbtString) {
4804                         auto str = constant->getConstArray()[0].getSConst()->c_str();
4805                         unsigned literal = 0;
4806                         char* literalPtr = reinterpret_cast<char*>(&literal);
4807                         unsigned charCount = 0;
4808                         char ch = 0;
4809                         do {
4810                             ch = *(str++);
4811                             *(literalPtr++) = ch;
4812                             ++charCount;
4813                             if (charCount == 4) {
4814                                 operands.push_back({false, literal});
4815                                 literalPtr = reinterpret_cast<char*>(&literal);
4816                                 charCount = 0;
4817                             }
4818                         } while (ch != 0);
4819 
4820                         // Partial literal is padded with 0
4821                         if (charCount > 0) {
4822                             for (; charCount < 4; ++charCount)
4823                                 *(literalPtr++) = 0;
4824                             operands.push_back({false, literal});
4825                         }
4826                     } else
4827                         assert(0); // Unexpected type
4828                 } else
4829                     operands.push_back({true, createSpvConstant(*constant)});
4830             } else {
4831                 // Type specifier
4832                 assert(typeParam.getAsType() != nullptr);
4833                 operands.push_back({true, convertGlslangToSpvType(*typeParam.getAsType())});
4834             }
4835         }
4836 
4837         assert(spirvInst.set == ""); // Currently, couldn't be extended instructions.
4838         spvType = builder.makeGenericType(static_cast<spv::Op>(spirvInst.id), operands);
4839 
4840         break;
4841     }
4842     case glslang::EbtTensorLayoutNV:
4843     {
4844         builder.addCapability(spv::CapabilityTensorAddressingNV);
4845         builder.addExtension(spv::E_SPV_NV_tensor_addressing);
4846 
4847         std::vector<spv::IdImmediate> operands;
4848         for (uint32_t i = 0; i < 2; ++i) {
4849             operands.push_back({true, makeArraySizeId(*type.getTypeParameters()->arraySizes, i, true)});
4850         }
4851         spvType = builder.makeGenericType(spv::OpTypeTensorLayoutNV, operands);
4852         break;
4853     }
4854     case glslang::EbtTensorViewNV:
4855     {
4856         builder.addCapability(spv::CapabilityTensorAddressingNV);
4857         builder.addExtension(spv::E_SPV_NV_tensor_addressing);
4858 
4859         uint32_t dim = type.getTypeParameters()->arraySizes->getDimSize(0);
4860         assert(dim >= 1 && dim <= 5);
4861         std::vector<spv::IdImmediate> operands;
4862         for (uint32_t i = 0; i < dim + 2; ++i) {
4863             operands.push_back({true, makeArraySizeId(*type.getTypeParameters()->arraySizes, i, true, i==1)});
4864         }
4865         spvType = builder.makeGenericType(spv::OpTypeTensorViewNV, operands);
4866         break;
4867     }
4868     default:
4869         assert(0);
4870         break;
4871     }
4872 
4873     if (type.isMatrix())
4874         spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
4875     else {
4876         // If this variable has a vector element count greater than 1, create a SPIR-V vector
4877         if (type.getVectorSize() > 1)
4878             spvType = builder.makeVectorType(spvType, type.getVectorSize());
4879     }
4880 
4881     if (type.isCoopMatNV()) {
4882         builder.addCapability(spv::CapabilityCooperativeMatrixNV);
4883         builder.addExtension(spv::E_SPV_NV_cooperative_matrix);
4884 
4885         if (type.getBasicType() == glslang::EbtFloat16)
4886             builder.addCapability(spv::CapabilityFloat16);
4887         if (type.getBasicType() == glslang::EbtUint8 ||
4888             type.getBasicType() == glslang::EbtInt8) {
4889             builder.addCapability(spv::CapabilityInt8);
4890         }
4891 
4892         spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);
4893         spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);
4894         spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 3);
4895 
4896         spvType = builder.makeCooperativeMatrixTypeNV(spvType, scope, rows, cols);
4897     }
4898 
4899     if (type.isCoopMatKHR()) {
4900         builder.addCapability(spv::CapabilityCooperativeMatrixKHR);
4901         builder.addExtension(spv::E_SPV_KHR_cooperative_matrix);
4902 
4903         if (type.getBasicType() == glslang::EbtFloat16)
4904             builder.addCapability(spv::CapabilityFloat16);
4905         if (type.getBasicType() == glslang::EbtUint8 || type.getBasicType() == glslang::EbtInt8) {
4906             builder.addCapability(spv::CapabilityInt8);
4907         }
4908 
4909         spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0);
4910         spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);
4911         spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);
4912         spv::Id use = builder.makeUintConstant(type.getCoopMatKHRuse());
4913 
4914         spvType = builder.makeCooperativeMatrixTypeKHR(spvType, scope, rows, cols, use);
4915     }
4916 
4917     if (type.isArray()) {
4918         int stride = 0;  // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
4919 
4920         // Do all but the outer dimension
4921         if (type.getArraySizes()->getNumDims() > 1) {
4922             // We need to decorate array strides for types needing explicit layout, except blocks.
4923             if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {
4924                 // Use a dummy glslang type for querying internal strides of
4925                 // arrays of arrays, but using just a one-dimensional array.
4926                 glslang::TType simpleArrayType(type, 0); // deference type of the array
4927                 while (simpleArrayType.getArraySizes()->getNumDims() > 1)
4928                     simpleArrayType.getArraySizes()->dereference();
4929 
4930                 // Will compute the higher-order strides here, rather than making a whole
4931                 // pile of types and doing repetitive recursion on their contents.
4932                 stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);
4933             }
4934 
4935             // make the arrays
4936             for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
4937                 spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride);
4938                 if (stride > 0)
4939                     builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
4940                 stride *= type.getArraySizes()->getDimSize(dim);
4941             }
4942         } else {
4943             // single-dimensional array, and don't yet have stride
4944 
4945             // We need to decorate array strides for types needing explicit layout, except blocks.
4946             if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)
4947                 stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);
4948         }
4949 
4950         // Do the outer dimension, which might not be known for a runtime-sized array.
4951         // (Unsized arrays that survive through linking will be runtime-sized arrays)
4952         if (type.isSizedArray())
4953             spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);
4954         else {
4955             if (!lastBufferBlockMember) {
4956                 builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
4957                 builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT);
4958             }
4959             spvType = builder.makeRuntimeArray(spvType);
4960         }
4961         if (stride > 0)
4962             builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
4963     }
4964 
4965     return spvType;
4966 }
4967 
4968 // Apply SPIR-V decorations to the SPIR-V object (provided by SPIR-V ID). If member index is provided, the
4969 // decorations are applied to this member.
applySpirvDecorate(const glslang::TType & type,spv::Id id,std::optional<int> member)4970 void TGlslangToSpvTraverser::applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member)
4971 {
4972     assert(type.getQualifier().hasSpirvDecorate());
4973 
4974     const glslang::TSpirvDecorate& spirvDecorate = type.getQualifier().getSpirvDecorate();
4975 
4976     // Add spirv_decorate
4977     for (auto& decorate : spirvDecorate.decorates) {
4978         if (!decorate.second.empty()) {
4979             std::vector<unsigned> literals;
4980             TranslateLiterals(decorate.second, literals);
4981             if (member.has_value())
4982                 builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first), literals);
4983             else
4984                 builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first), literals);
4985         } else {
4986             if (member.has_value())
4987                 builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first));
4988             else
4989                 builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first));
4990         }
4991     }
4992 
4993     // Add spirv_decorate_id
4994     if (member.has_value()) {
4995         // spirv_decorate_id not applied to members
4996         assert(spirvDecorate.decorateIds.empty());
4997     } else {
4998         for (auto& decorateId : spirvDecorate.decorateIds) {
4999             std::vector<spv::Id> operandIds;
5000             assert(!decorateId.second.empty());
5001             for (auto extraOperand : decorateId.second) {
5002                 if (extraOperand->getQualifier().isFrontEndConstant())
5003                     operandIds.push_back(createSpvConstant(*extraOperand));
5004                 else
5005                     operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));
5006             }
5007             builder.addDecorationId(id, static_cast<spv::Decoration>(decorateId.first), operandIds);
5008         }
5009     }
5010 
5011     // Add spirv_decorate_string
5012     for (auto& decorateString : spirvDecorate.decorateStrings) {
5013         std::vector<const char*> strings;
5014         assert(!decorateString.second.empty());
5015         for (auto extraOperand : decorateString.second) {
5016             const char* string = extraOperand->getConstArray()[0].getSConst()->c_str();
5017             strings.push_back(string);
5018         }
5019         if (member.has_value())
5020             builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorateString.first), strings);
5021         else
5022             builder.addDecoration(id, static_cast<spv::Decoration>(decorateString.first), strings);
5023     }
5024 }
5025 
5026 // TODO: this functionality should exist at a higher level, in creating the AST
5027 //
5028 // Identify interface members that don't have their required extension turned on.
5029 //
filterMember(const glslang::TType & member)5030 bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member)
5031 {
5032     auto& extensions = glslangIntermediate->getRequestedExtensions();
5033 
5034     if (member.getFieldName() == "gl_SecondaryViewportMaskNV" &&
5035         extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
5036         return true;
5037     if (member.getFieldName() == "gl_SecondaryPositionNV" &&
5038         extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
5039         return true;
5040 
5041     if (glslangIntermediate->getStage() == EShLangMesh) {
5042         if (member.getFieldName() == "gl_PrimitiveShadingRateEXT" &&
5043             extensions.find("GL_EXT_fragment_shading_rate") == extensions.end())
5044             return true;
5045     }
5046 
5047     if (glslangIntermediate->getStage() != EShLangMesh) {
5048         if (member.getFieldName() == "gl_ViewportMask" &&
5049             extensions.find("GL_NV_viewport_array2") == extensions.end())
5050             return true;
5051         if (member.getFieldName() == "gl_PositionPerViewNV" &&
5052             extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
5053             return true;
5054         if (member.getFieldName() == "gl_ViewportMaskPerViewNV" &&
5055             extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
5056             return true;
5057     }
5058 
5059     return false;
5060 }
5061 
5062 // Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.
5063 // explicitLayout can be kept the same throughout the hierarchical recursive walk.
5064 // Mutually recursive with convertGlslangToSpvType().
convertGlslangStructToSpvType(const glslang::TType & type,const glslang::TTypeList * glslangMembers,glslang::TLayoutPacking explicitLayout,const glslang::TQualifier & qualifier)5065 spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type,
5066                                                               const glslang::TTypeList* glslangMembers,
5067                                                               glslang::TLayoutPacking explicitLayout,
5068                                                               const glslang::TQualifier& qualifier)
5069 {
5070     // Create a vector of struct types for SPIR-V to consume
5071     std::vector<spv::Id> spvMembers;
5072     int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0,
5073                           // except sometimes for blocks
5074     std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
5075     for (int i = 0; i < (int)glslangMembers->size(); i++) {
5076         auto& glslangMember = (*glslangMembers)[i];
5077         if (glslangMember.type->hiddenMember()) {
5078             ++memberDelta;
5079             if (type.getBasicType() == glslang::EbtBlock)
5080                 memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
5081         } else {
5082             if (type.getBasicType() == glslang::EbtBlock) {
5083                 if (filterMember(*glslangMember.type)) {
5084                     memberDelta++;
5085                     memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
5086                     continue;
5087                 }
5088                 memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta;
5089             }
5090             // modify just this child's view of the qualifier
5091             glslang::TQualifier memberQualifier = glslangMember.type->getQualifier();
5092             InheritQualifiers(memberQualifier, qualifier);
5093 
5094             // manually inherit location
5095             if (! memberQualifier.hasLocation() && qualifier.hasLocation())
5096                 memberQualifier.layoutLocation = qualifier.layoutLocation;
5097 
5098             // recurse
5099             bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
5100                                          i == (int)glslangMembers->size() - 1;
5101 
5102             // Make forward pointers for any pointer members.
5103             if (glslangMember.type->isReference() &&
5104                 forwardPointers.find(glslangMember.type->getReferentType()) == forwardPointers.end()) {
5105                 deferredForwardPointers.push_back(std::make_pair(glslangMember.type, memberQualifier));
5106             }
5107 
5108             // Create the member type.
5109             auto const spvMember = convertGlslangToSpvType(*glslangMember.type, explicitLayout, memberQualifier, lastBufferBlockMember,
5110                 glslangMember.type->isReference());
5111             spvMembers.push_back(spvMember);
5112 
5113             // Update the builder with the type's location so that we can create debug types for the structure members.
5114             // There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now,
5115             // it is stored in the builder and consumed during the construction of composite debug types.
5116             // TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the
5117             // quick and dirty approaches that were tried.
5118             // Advantages of this approach:
5119             //  + Relatively clean. No direct calls into debug type system.
5120             //  + Handles nested recursive structures.
5121             // Disadvantages of this approach:
5122             //  + Not as clean as desired. Traverser queries/sets persistent state. This is fragile.
5123             //  + Table lookup during creation of composite debug types. This really shouldn't be necessary.
5124             if(options.emitNonSemanticShaderDebugInfo) {
5125                 builder.debugTypeLocs[spvMember].name = glslangMember.type->getFieldName().c_str();
5126                 builder.debugTypeLocs[spvMember].line = glslangMember.loc.line;
5127                 builder.debugTypeLocs[spvMember].column = glslangMember.loc.column;
5128             }
5129         }
5130     }
5131 
5132     // Make the SPIR-V type
5133     spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str(), false);
5134     if (! HasNonLayoutQualifiers(type, qualifier))
5135         structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;
5136 
5137     // Decorate it
5138     decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType, spvMembers);
5139 
5140     for (int i = 0; i < (int)deferredForwardPointers.size(); ++i) {
5141         auto it = deferredForwardPointers[i];
5142         convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);
5143     }
5144 
5145     return spvType;
5146 }
5147 
decorateStructType(const glslang::TType & type,const glslang::TTypeList * glslangMembers,glslang::TLayoutPacking explicitLayout,const glslang::TQualifier & qualifier,spv::Id spvType,const std::vector<spv::Id> & spvMembers)5148 void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
5149                                                 const glslang::TTypeList* glslangMembers,
5150                                                 glslang::TLayoutPacking explicitLayout,
5151                                                 const glslang::TQualifier& qualifier,
5152                                                 spv::Id spvType,
5153                                                 const std::vector<spv::Id>& spvMembers)
5154 {
5155     // Name and decorate the non-hidden members
5156     int offset = -1;
5157     bool memberLocationInvalid = type.isArrayOfArrays() ||
5158         (type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false));
5159     for (int i = 0; i < (int)glslangMembers->size(); i++) {
5160         glslang::TType& glslangMember = *(*glslangMembers)[i].type;
5161         int member = i;
5162         if (type.getBasicType() == glslang::EbtBlock) {
5163             member = memberRemapper[glslangTypeToIdMap[glslangMembers]][i];
5164             if (filterMember(glslangMember))
5165                 continue;
5166         }
5167 
5168         // modify just this child's view of the qualifier
5169         glslang::TQualifier memberQualifier = glslangMember.getQualifier();
5170         InheritQualifiers(memberQualifier, qualifier);
5171 
5172         // using -1 above to indicate a hidden member
5173         if (member < 0)
5174             continue;
5175 
5176         builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str());
5177         builder.addMemberDecoration(spvType, member,
5178                                     TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix));
5179         builder.addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember));
5180         // Add interpolation and auxiliary storage decorations only to
5181         // top-level members of Input and Output storage classes
5182         if (type.getQualifier().storage == glslang::EvqVaryingIn ||
5183             type.getQualifier().storage == glslang::EvqVaryingOut) {
5184             if (type.getBasicType() == glslang::EbtBlock ||
5185                 glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
5186                 builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier));
5187                 builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier));
5188                 addMeshNVDecoration(spvType, member, memberQualifier);
5189             }
5190         }
5191         builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier));
5192 
5193         if (type.getBasicType() == glslang::EbtBlock &&
5194             qualifier.storage == glslang::EvqBuffer) {
5195             // Add memory decorations only to top-level members of shader storage block
5196             std::vector<spv::Decoration> memory;
5197             TranslateMemoryDecoration(memberQualifier, memory, glslangIntermediate->usingVulkanMemoryModel());
5198             for (unsigned int i = 0; i < memory.size(); ++i)
5199                 builder.addMemberDecoration(spvType, member, memory[i]);
5200         }
5201 
5202         // Location assignment was already completed correctly by the front end,
5203         // just track whether a member needs to be decorated.
5204         // Ignore member locations if the container is an array, as that's
5205         // ill-specified and decisions have been made to not allow this.
5206         if (!memberLocationInvalid && memberQualifier.hasLocation())
5207             builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation);
5208 
5209         // component, XFB, others
5210         if (glslangMember.getQualifier().hasComponent())
5211             builder.addMemberDecoration(spvType, member, spv::DecorationComponent,
5212                                         glslangMember.getQualifier().layoutComponent);
5213         if (glslangMember.getQualifier().hasXfbOffset())
5214             builder.addMemberDecoration(spvType, member, spv::DecorationOffset,
5215                                         glslangMember.getQualifier().layoutXfbOffset);
5216         else if (explicitLayout != glslang::ElpNone) {
5217             // figure out what to do with offset, which is accumulating
5218             int nextOffset;
5219             updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix);
5220             if (offset >= 0)
5221                 builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
5222             offset = nextOffset;
5223         }
5224 
5225         if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone)
5226             builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride,
5227                                         getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix));
5228 
5229         // built-in variable decorations
5230         spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);
5231         if (builtIn != spv::BuiltInMax)
5232             builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
5233 
5234         // nonuniform
5235         builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier()));
5236 
5237         if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) {
5238             builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
5239             builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
5240                                         memberQualifier.semanticName);
5241         }
5242 
5243         if (builtIn == spv::BuiltInLayer) {
5244             // SPV_NV_viewport_array2 extension
5245             if (glslangMember.getQualifier().layoutViewportRelative){
5246                 builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationViewportRelativeNV);
5247                 builder.addCapability(spv::CapabilityShaderViewportMaskNV);
5248                 builder.addExtension(spv::E_SPV_NV_viewport_array2);
5249             }
5250             if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){
5251                 builder.addMemberDecoration(spvType, member,
5252                                             (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,
5253                                             glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset);
5254                 builder.addCapability(spv::CapabilityShaderStereoViewNV);
5255                 builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
5256             }
5257         }
5258         if (glslangMember.getQualifier().layoutPassthrough) {
5259             builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationPassthroughNV);
5260             builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
5261             builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
5262         }
5263 
5264         // Add SPIR-V decorations (GL_EXT_spirv_intrinsics)
5265         if (glslangMember.getQualifier().hasSpirvDecorate())
5266             applySpirvDecorate(glslangMember, spvType, member);
5267     }
5268 
5269     // Decorate the structure
5270     builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
5271     const auto basicType = type.getBasicType();
5272     const auto typeStorageQualifier = type.getQualifier().storage;
5273     if (basicType == glslang::EbtBlock) {
5274         builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));
5275     } else if (basicType == glslang::EbtStruct && glslangIntermediate->getSpv().vulkan > 0) {
5276         const auto hasRuntimeArray = !spvMembers.empty() && builder.getOpCode(spvMembers.back()) == spv::OpTypeRuntimeArray;
5277         if (hasRuntimeArray) {
5278             builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));
5279         }
5280     }
5281 
5282     if (qualifier.hasHitObjectShaderRecordNV())
5283         builder.addDecoration(spvType, spv::DecorationHitObjectShaderRecordBufferNV);
5284 }
5285 
5286 // Turn the expression forming the array size into an id.
5287 // This is not quite trivial, because of specialization constants.
5288 // Sometimes, a raw constant is turned into an Id, and sometimes
5289 // a specialization constant expression is.
makeArraySizeId(const glslang::TArraySizes & arraySizes,int dim,bool allowZero,bool boolType)5290 spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim, bool allowZero, bool boolType)
5291 {
5292     // First, see if this is sized with a node, meaning a specialization constant:
5293     glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim);
5294     if (specNode != nullptr) {
5295         builder.clearAccessChain();
5296         SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
5297         spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
5298         specNode->traverse(this);
5299         return accessChainLoad(specNode->getAsTyped()->getType());
5300     }
5301 
5302     // Otherwise, need a compile-time (front end) size, get it:
5303     int size = arraySizes.getDimSize(dim);
5304 
5305     if (!allowZero)
5306         assert(size > 0);
5307 
5308     if (boolType) {
5309         return builder.makeBoolConstant(size);
5310     } else {
5311         return builder.makeUintConstant(size);
5312     }
5313 }
5314 
5315 // Wrap the builder's accessChainLoad to:
5316 //  - localize handling of RelaxedPrecision
5317 //  - use the SPIR-V inferred type instead of another conversion of the glslang type
5318 //    (avoids unnecessary work and possible type punning for structures)
5319 //  - do conversion of concrete to abstract type
accessChainLoad(const glslang::TType & type)5320 spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
5321 {
5322     spv::Id nominalTypeId = builder.accessChainGetInferredType();
5323 
5324     spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
5325     coherentFlags |= TranslateCoherent(type);
5326 
5327     spv::MemoryAccessMask accessMask = spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask);
5328     // If the value being loaded is HelperInvocation, SPIR-V 1.6 is being generated (so that
5329     // SPV_EXT_demote_to_helper_invocation is in core) and the memory model is in use, add
5330     // the Volatile MemoryAccess semantic.
5331     if (type.getQualifier().builtIn == glslang::EbvHelperInvocation &&
5332         glslangIntermediate->usingVulkanMemoryModel() &&
5333         glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
5334         accessMask = spv::MemoryAccessMask(accessMask | spv::MemoryAccessVolatileMask);
5335     }
5336 
5337     unsigned int alignment = builder.getAccessChain().alignment;
5338     alignment |= type.getBufferReferenceAlignment();
5339 
5340     spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
5341         TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
5342         TranslateNonUniformDecoration(type.getQualifier()),
5343         nominalTypeId,
5344         accessMask,
5345         TranslateMemoryScope(coherentFlags),
5346         alignment);
5347 
5348     // Need to convert to abstract types when necessary
5349     if (type.getBasicType() == glslang::EbtBool) {
5350         loadedId = convertLoadedBoolInUniformToUint(type, nominalTypeId, loadedId);
5351     }
5352 
5353     return loadedId;
5354 }
5355 
5356 // Wrap the builder's accessChainStore to:
5357 //  - do conversion of concrete to abstract type
5358 //
5359 // Implicitly uses the existing builder.accessChain as the storage target.
accessChainStore(const glslang::TType & type,spv::Id rvalue)5360 void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)
5361 {
5362     // Need to convert to abstract types when necessary
5363     if (type.getBasicType() == glslang::EbtBool) {
5364         spv::Id nominalTypeId = builder.accessChainGetInferredType();
5365 
5366         if (builder.isScalarType(nominalTypeId)) {
5367             // Conversion for bool
5368             spv::Id boolType = builder.makeBoolType();
5369             if (nominalTypeId != boolType) {
5370                 // keep these outside arguments, for determinant order-of-evaluation
5371                 spv::Id one = builder.makeUintConstant(1);
5372                 spv::Id zero = builder.makeUintConstant(0);
5373                 rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
5374             } else if (builder.getTypeId(rvalue) != boolType)
5375                 rvalue = builder.createBinOp(spv::OpINotEqual, boolType, rvalue, builder.makeUintConstant(0));
5376         } else if (builder.isVectorType(nominalTypeId)) {
5377             // Conversion for bvec
5378             int vecSize = builder.getNumTypeComponents(nominalTypeId);
5379             spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
5380             if (nominalTypeId != bvecType) {
5381                 // keep these outside arguments, for determinant order-of-evaluation
5382                 spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize);
5383                 spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize);
5384                 rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
5385             } else if (builder.getTypeId(rvalue) != bvecType)
5386                 rvalue = builder.createBinOp(spv::OpINotEqual, bvecType, rvalue,
5387                                              makeSmearedConstant(builder.makeUintConstant(0), vecSize));
5388         }
5389     }
5390 
5391     spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
5392     coherentFlags |= TranslateCoherent(type);
5393 
5394     unsigned int alignment = builder.getAccessChain().alignment;
5395     alignment |= type.getBufferReferenceAlignment();
5396 
5397     builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
5398                              spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &
5399                                 ~spv::MemoryAccessMakePointerVisibleKHRMask),
5400                              TranslateMemoryScope(coherentFlags), alignment);
5401 }
5402 
5403 // For storing when types match at the glslang level, but not might match at the
5404 // SPIR-V level.
5405 //
5406 // This especially happens when a single glslang type expands to multiple
5407 // SPIR-V types, like a struct that is used in a member-undecorated way as well
5408 // as in a member-decorated way.
5409 //
5410 // NOTE: This function can handle any store request; if it's not special it
5411 // simplifies to a simple OpStore.
5412 //
5413 // Implicitly uses the existing builder.accessChain as the storage target.
multiTypeStore(const glslang::TType & type,spv::Id rValue)5414 void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue)
5415 {
5416     // we only do the complex path here if it's an aggregate
5417     if (! type.isStruct() && ! type.isArray()) {
5418         accessChainStore(type, rValue);
5419         return;
5420     }
5421 
5422     // and, it has to be a case of type aliasing
5423     spv::Id rType = builder.getTypeId(rValue);
5424     spv::Id lValue = builder.accessChainGetLValue();
5425     spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue));
5426     if (lType == rType) {
5427         accessChainStore(type, rValue);
5428         return;
5429     }
5430 
5431     // Recursively (as needed) copy an aggregate type to a different aggregate type,
5432     // where the two types were the same type in GLSL. This requires member
5433     // by member copy, recursively.
5434 
5435     // SPIR-V 1.4 added an instruction to do help do this.
5436     if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
5437         // However, bool in uniform space is changed to int, so
5438         // OpCopyLogical does not work for that.
5439         // TODO: It would be more robust to do a full recursive verification of the types satisfying SPIR-V rules.
5440         bool rBool = builder.containsType(builder.getTypeId(rValue), spv::OpTypeBool, 0);
5441         bool lBool = builder.containsType(lType, spv::OpTypeBool, 0);
5442         if (lBool == rBool) {
5443             spv::Id logicalCopy = builder.createUnaryOp(spv::OpCopyLogical, lType, rValue);
5444             accessChainStore(type, logicalCopy);
5445             return;
5446         }
5447     }
5448 
5449     // If an array, copy element by element.
5450     if (type.isArray()) {
5451         glslang::TType glslangElementType(type, 0);
5452         spv::Id elementRType = builder.getContainedTypeId(rType);
5453         for (int index = 0; index < type.getOuterArraySize(); ++index) {
5454             // get the source member
5455             spv::Id elementRValue = builder.createCompositeExtract(rValue, elementRType, index);
5456 
5457             // set up the target storage
5458             builder.clearAccessChain();
5459             builder.setAccessChainLValue(lValue);
5460             builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type),
5461                 type.getBufferReferenceAlignment());
5462 
5463             // store the member
5464             multiTypeStore(glslangElementType, elementRValue);
5465         }
5466     } else {
5467         assert(type.isStruct());
5468 
5469         // loop over structure members
5470         const glslang::TTypeList& members = *type.getStruct();
5471         for (int m = 0; m < (int)members.size(); ++m) {
5472             const glslang::TType& glslangMemberType = *members[m].type;
5473 
5474             // get the source member
5475             spv::Id memberRType = builder.getContainedTypeId(rType, m);
5476             spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m);
5477 
5478             // set up the target storage
5479             builder.clearAccessChain();
5480             builder.setAccessChainLValue(lValue);
5481             builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type),
5482                 type.getBufferReferenceAlignment());
5483 
5484             // store the member
5485             multiTypeStore(glslangMemberType, memberRValue);
5486         }
5487     }
5488 }
5489 
5490 // Decide whether or not this type should be
5491 // decorated with offsets and strides, and if so
5492 // whether std140 or std430 rules should be applied.
getExplicitLayout(const glslang::TType & type) const5493 glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
5494 {
5495     // has to be a block
5496     if (type.getBasicType() != glslang::EbtBlock)
5497         return glslang::ElpNone;
5498 
5499     // has to be a uniform or buffer block or task in/out blocks
5500     if (type.getQualifier().storage != glslang::EvqUniform &&
5501         type.getQualifier().storage != glslang::EvqBuffer &&
5502         type.getQualifier().storage != glslang::EvqShared &&
5503         !type.getQualifier().isTaskMemory())
5504         return glslang::ElpNone;
5505 
5506     // return the layout to use
5507     switch (type.getQualifier().layoutPacking) {
5508     case glslang::ElpStd140:
5509     case glslang::ElpStd430:
5510     case glslang::ElpScalar:
5511         return type.getQualifier().layoutPacking;
5512     default:
5513         return glslang::ElpNone;
5514     }
5515 }
5516 
5517 // Given an array type, returns the integer stride required for that array
getArrayStride(const glslang::TType & arrayType,glslang::TLayoutPacking explicitLayout,glslang::TLayoutMatrix matrixLayout)5518 int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout,
5519     glslang::TLayoutMatrix matrixLayout)
5520 {
5521     int size;
5522     int stride;
5523     glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout,
5524         matrixLayout == glslang::ElmRowMajor);
5525 
5526     return stride;
5527 }
5528 
5529 // Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
5530 // when used as a member of an interface block
getMatrixStride(const glslang::TType & matrixType,glslang::TLayoutPacking explicitLayout,glslang::TLayoutMatrix matrixLayout)5531 int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout,
5532     glslang::TLayoutMatrix matrixLayout)
5533 {
5534     glslang::TType elementType;
5535     elementType.shallowCopy(matrixType);
5536     elementType.clearArraySizes();
5537 
5538     int size;
5539     int stride;
5540     glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout,
5541         matrixLayout == glslang::ElmRowMajor);
5542 
5543     return stride;
5544 }
5545 
5546 // Given a member type of a struct, realign the current offset for it, and compute
5547 // the next (not yet aligned) offset for the next member, which will get aligned
5548 // on the next call.
5549 // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
5550 // the migration of data from nextOffset -> currentOffset.  It should be -1 on the first call.
5551 // -1 means a non-forced member offset (no decoration needed).
updateMemberOffset(const glslang::TType & structType,const glslang::TType & memberType,int & currentOffset,int & nextOffset,glslang::TLayoutPacking explicitLayout,glslang::TLayoutMatrix matrixLayout)5552 void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType,
5553     int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
5554 {
5555     // this will get a positive value when deemed necessary
5556     nextOffset = -1;
5557 
5558     // override anything in currentOffset with user-set offset
5559     if (memberType.getQualifier().hasOffset())
5560         currentOffset = memberType.getQualifier().layoutOffset;
5561 
5562     // It could be that current linker usage in glslang updated all the layoutOffset,
5563     // in which case the following code does not matter.  But, that's not quite right
5564     // once cross-compilation unit GLSL validation is done, as the original user
5565     // settings are needed in layoutOffset, and then the following will come into play.
5566 
5567     if (explicitLayout == glslang::ElpNone) {
5568         if (! memberType.getQualifier().hasOffset())
5569             currentOffset = -1;
5570 
5571         return;
5572     }
5573 
5574     // Getting this far means we need explicit offsets
5575     if (currentOffset < 0)
5576         currentOffset = 0;
5577 
5578     // Now, currentOffset is valid (either 0, or from a previous nextOffset),
5579     // but possibly not yet correctly aligned.
5580 
5581     int memberSize;
5582     int dummyStride;
5583     int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout,
5584         matrixLayout == glslang::ElmRowMajor);
5585 
5586     bool isVectorLike = memberType.isVector();
5587     if (memberType.isMatrix()) {
5588         if (matrixLayout == glslang::ElmRowMajor)
5589             isVectorLike = memberType.getMatrixRows() == 1;
5590         else
5591             isVectorLike = memberType.getMatrixCols() == 1;
5592     }
5593 
5594     // Adjust alignment for HLSL rules
5595     // TODO: make this consistent in early phases of code:
5596     //       adjusting this late means inconsistencies with earlier code, which for reflection is an issue
5597     // Until reflection is brought in sync with these adjustments, don't apply to $Global,
5598     // which is the most likely to rely on reflection, and least likely to rely implicit layouts
5599     if (glslangIntermediate->usingHlslOffsets() &&
5600         ! memberType.isStruct() && structType.getTypeName().compare("$Global") != 0) {
5601         int componentSize;
5602         int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, componentSize);
5603         if (! memberType.isArray() && isVectorLike && componentAlignment <= 4)
5604             memberAlignment = componentAlignment;
5605 
5606         // Don't add unnecessary padding after this member
5607         // (undo std140 bumping size to a mutliple of vec4)
5608         if (explicitLayout == glslang::ElpStd140) {
5609             if (memberType.isMatrix()) {
5610                 if (matrixLayout == glslang::ElmRowMajor)
5611                     memberSize -= componentSize * (4 - memberType.getMatrixCols());
5612                 else
5613                     memberSize -= componentSize * (4 - memberType.getMatrixRows());
5614             } else if (memberType.isArray())
5615                 memberSize -= componentSize * (4 - memberType.getVectorSize());
5616         }
5617     }
5618 
5619     // Bump up to member alignment
5620     glslang::RoundToPow2(currentOffset, memberAlignment);
5621 
5622     // Bump up to vec4 if there is a bad straddle
5623     if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize,
5624         currentOffset, isVectorLike))
5625         glslang::RoundToPow2(currentOffset, 16);
5626 
5627     nextOffset = currentOffset + memberSize;
5628 }
5629 
declareUseOfStructMember(const glslang::TTypeList & members,int glslangMember)5630 void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember)
5631 {
5632     const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn;
5633     switch (glslangBuiltIn)
5634     {
5635     case glslang::EbvPointSize:
5636     case glslang::EbvClipDistance:
5637     case glslang::EbvCullDistance:
5638     case glslang::EbvViewportMaskNV:
5639     case glslang::EbvSecondaryPositionNV:
5640     case glslang::EbvSecondaryViewportMaskNV:
5641     case glslang::EbvPositionPerViewNV:
5642     case glslang::EbvViewportMaskPerViewNV:
5643     case glslang::EbvTaskCountNV:
5644     case glslang::EbvPrimitiveCountNV:
5645     case glslang::EbvPrimitiveIndicesNV:
5646     case glslang::EbvClipDistancePerViewNV:
5647     case glslang::EbvCullDistancePerViewNV:
5648     case glslang::EbvLayerPerViewNV:
5649     case glslang::EbvMeshViewCountNV:
5650     case glslang::EbvMeshViewIndicesNV:
5651         // Generate the associated capability.  Delegate to TranslateBuiltInDecoration.
5652         // Alternately, we could just call this for any glslang built-in, since the
5653         // capability already guards against duplicates.
5654         TranslateBuiltInDecoration(glslangBuiltIn, false);
5655         break;
5656     default:
5657         // Capabilities were already generated when the struct was declared.
5658         break;
5659     }
5660 }
5661 
isShaderEntryPoint(const glslang::TIntermAggregate * node)5662 bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* node)
5663 {
5664     return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0;
5665 }
5666 
5667 // Does parameter need a place to keep writes, separate from the original?
5668 // Assumes called after originalParam(), which filters out block/buffer/opaque-based
5669 // qualifiers such that we should have only in/out/inout/constreadonly here.
writableParam(glslang::TStorageQualifier qualifier) const5670 bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) const
5671 {
5672     assert(qualifier == glslang::EvqIn ||
5673            qualifier == glslang::EvqOut ||
5674            qualifier == glslang::EvqInOut ||
5675            qualifier == glslang::EvqUniform ||
5676            qualifier == glslang::EvqConstReadOnly);
5677     return qualifier != glslang::EvqConstReadOnly &&
5678            qualifier != glslang::EvqUniform;
5679 }
5680 
5681 // Is parameter pass-by-original?
originalParam(glslang::TStorageQualifier qualifier,const glslang::TType & paramType,bool implicitThisParam)5682 bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType,
5683                                            bool implicitThisParam)
5684 {
5685     if (implicitThisParam)                                                                     // implicit this
5686         return true;
5687     if (glslangIntermediate->getSource() == glslang::EShSourceHlsl)
5688         return paramType.getBasicType() == glslang::EbtBlock;
5689     return (paramType.containsOpaque() && !glslangIntermediate->getBindlessMode()) ||       // sampler, etc.
5690            paramType.getQualifier().isSpirvByReference() ||                                    // spirv_by_reference
5691            (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO
5692 }
5693 
5694 // Make all the functions, skeletally, without actually visiting their bodies.
makeFunctions(const glslang::TIntermSequence & glslFunctions)5695 void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
5696 {
5697     const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type,
5698         bool useVulkanMemoryModel) {
5699         spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
5700         if (paramPrecision != spv::NoPrecision)
5701             decorations.push_back(paramPrecision);
5702         TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);
5703         if (type.isReference()) {
5704             // Original and non-writable params pass the pointer directly and
5705             // use restrict/aliased, others are stored to a pointer in Function
5706             // memory and use RestrictPointer/AliasedPointer.
5707             if (originalParam(type.getQualifier().storage, type, false) ||
5708                 !writableParam(type.getQualifier().storage)) {
5709                 // TranslateMemoryDecoration added Restrict decoration already.
5710                 if (!type.getQualifier().isRestrict()) {
5711                     decorations.push_back(spv::DecorationAliased);
5712                 }
5713             } else {
5714                 decorations.push_back(type.getQualifier().isRestrict() ? spv::DecorationRestrictPointerEXT :
5715                                                                          spv::DecorationAliasedPointerEXT);
5716             }
5717         }
5718     };
5719 
5720     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
5721         glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
5722         if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction)
5723             continue;
5724 
5725         builder.setDebugSourceLocation(glslFunction->getLoc().line, glslFunction->getLoc().getFilename());
5726 
5727         if (isShaderEntryPoint(glslFunction)) {
5728             // For HLSL, the entry function is actually a compiler generated function to resolve the difference of
5729             // entry function signature between HLSL and SPIR-V. So we don't emit debug information for that.
5730             if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) {
5731                 builder.setupFunctionDebugInfo(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(),
5732                                                std::vector<spv::Id>(), // main function has no param
5733                                                std::vector<char const*>());
5734             }
5735             continue;
5736         }
5737         // We're on a user function.  Set up the basic interface for the function now,
5738         // so that it's available to call.  Translating the body will happen later.
5739         //
5740         // Typically (except for a "const in" parameter), an address will be passed to the
5741         // function.  What it is an address of varies:
5742         //
5743         // - "in" parameters not marked as "const" can be written to without modifying the calling
5744         //   argument so that write needs to be to a copy, hence the address of a copy works.
5745         //
5746         // - "const in" parameters can just be the r-value, as no writes need occur.
5747         //
5748         // - "out" and "inout" arguments can't be done as pointers to the calling argument, because
5749         //   GLSL has copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
5750 
5751         std::vector<spv::Id> paramTypes;
5752         std::vector<char const*> paramNames;
5753         std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
5754         glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
5755 
5756 #ifdef ENABLE_HLSL
5757         bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==
5758                                                           glslangIntermediate->implicitThisName;
5759 #else
5760         bool implicitThis = false;
5761 #endif
5762 
5763         paramDecorations.resize(parameters.size());
5764         for (int p = 0; p < (int)parameters.size(); ++p) {
5765             const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
5766             spv::Id typeId = convertGlslangToSpvType(paramType);
5767             if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0))
5768                 typeId = builder.makePointer(TranslateStorageClass(paramType), typeId);
5769             else if (writableParam(paramType.getQualifier().storage))
5770                 typeId = builder.makePointer(spv::StorageClassFunction, typeId);
5771             else
5772                 rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
5773             getParamDecorations(paramDecorations[p], paramType, glslangIntermediate->usingVulkanMemoryModel());
5774             paramTypes.push_back(typeId);
5775         }
5776 
5777         for (auto const parameter:parameters) {
5778             paramNames.push_back(parameter->getAsSymbolNode()->getName().c_str());
5779         }
5780 
5781         spv::Block* functionBlock;
5782         spv::Function* function = builder.makeFunctionEntry(
5783             TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()),
5784             glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes,
5785             paramDecorations, &functionBlock);
5786         builder.setupFunctionDebugInfo(function, glslFunction->getName().c_str(), paramTypes, paramNames);
5787         if (implicitThis)
5788             function->setImplicitThis();
5789 
5790         // Track function to emit/call later
5791         functionMap[glslFunction->getName().c_str()] = function;
5792 
5793         // Set the parameter id's
5794         for (int p = 0; p < (int)parameters.size(); ++p) {
5795             symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
5796             // give a name too
5797             builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
5798 
5799             const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
5800             if (paramType.contains8BitInt())
5801                 builder.addCapability(spv::CapabilityInt8);
5802             if (paramType.contains16BitInt())
5803                 builder.addCapability(spv::CapabilityInt16);
5804             if (paramType.contains16BitFloat())
5805                 builder.addCapability(spv::CapabilityFloat16);
5806         }
5807     }
5808 }
5809 
5810 // Process all the initializers, while skipping the functions and link objects
makeGlobalInitializers(const glslang::TIntermSequence & initializers)5811 void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
5812 {
5813     builder.setBuildPoint(shaderEntry->getLastBlock());
5814     for (int i = 0; i < (int)initializers.size(); ++i) {
5815         glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
5816         if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() !=
5817             glslang::EOpLinkerObjects) {
5818 
5819             // We're on a top-level node that's not a function.  Treat as an initializer, whose
5820             // code goes into the beginning of the entry point.
5821             initializer->traverse(this);
5822         }
5823     }
5824 }
5825 // Walk over all linker objects to create a map for payload and callable data linker objects
5826 // and their location to be used during codegen for OpTraceKHR and OpExecuteCallableKHR
5827 // This is done here since it is possible that these linker objects are not be referenced in the AST
collectRayTracingLinkerObjects()5828 void TGlslangToSpvTraverser::collectRayTracingLinkerObjects()
5829 {
5830     glslang::TIntermAggregate* linkerObjects = glslangIntermediate->findLinkerObjects();
5831     for (auto& objSeq : linkerObjects->getSequence()) {
5832         auto objNode = objSeq->getAsSymbolNode();
5833         if (objNode != nullptr) {
5834             if (objNode->getQualifier().hasLocation()) {
5835                 unsigned int location = objNode->getQualifier().layoutLocation;
5836                 auto st = objNode->getQualifier().storage;
5837                 int set;
5838                 switch (st)
5839                 {
5840                 case glslang::EvqPayload:
5841                 case glslang::EvqPayloadIn:
5842                     set = 0;
5843                     break;
5844                 case glslang::EvqCallableData:
5845                 case glslang::EvqCallableDataIn:
5846                     set = 1;
5847                     break;
5848 
5849                 case glslang::EvqHitObjectAttrNV:
5850                     set = 2;
5851                     break;
5852 
5853                 default:
5854                     set = -1;
5855                 }
5856                 if (set != -1)
5857                     locationToSymbol[set].insert(std::make_pair(location, objNode));
5858             }
5859         }
5860     }
5861 }
5862 // Process all the functions, while skipping initializers.
visitFunctions(const glslang::TIntermSequence & glslFunctions)5863 void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
5864 {
5865     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
5866         glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
5867         if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang::EOpLinkerObjects))
5868             node->traverse(this);
5869     }
5870 }
5871 
handleFunctionEntry(const glslang::TIntermAggregate * node)5872 void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
5873 {
5874     // SPIR-V functions should already be in the functionMap from the prepass
5875     // that called makeFunctions().
5876     currentFunction = functionMap[node->getName().c_str()];
5877     spv::Block* functionBlock = currentFunction->getEntryBlock();
5878     builder.setBuildPoint(functionBlock);
5879     builder.enterFunction(currentFunction);
5880 }
5881 
translateArguments(const glslang::TIntermAggregate & node,std::vector<spv::Id> & arguments,spv::Builder::AccessChain::CoherentFlags & lvalueCoherentFlags)5882 void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
5883     spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
5884 {
5885     const glslang::TIntermSequence& glslangArguments = node.getSequence();
5886 
5887     glslang::TSampler sampler = {};
5888     bool cubeCompare = false;
5889     bool f16ShadowCompare = false;
5890     if (node.isTexture() || node.isImage()) {
5891         sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
5892         cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
5893         f16ShadowCompare = sampler.shadow &&
5894             glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16;
5895     }
5896 
5897     for (int i = 0; i < (int)glslangArguments.size(); ++i) {
5898         builder.clearAccessChain();
5899         glslangArguments[i]->traverse(this);
5900 
5901         // Special case l-value operands
5902         bool lvalue = false;
5903         switch (node.getOp()) {
5904         case glslang::EOpImageAtomicAdd:
5905         case glslang::EOpImageAtomicMin:
5906         case glslang::EOpImageAtomicMax:
5907         case glslang::EOpImageAtomicAnd:
5908         case glslang::EOpImageAtomicOr:
5909         case glslang::EOpImageAtomicXor:
5910         case glslang::EOpImageAtomicExchange:
5911         case glslang::EOpImageAtomicCompSwap:
5912         case glslang::EOpImageAtomicLoad:
5913         case glslang::EOpImageAtomicStore:
5914             if (i == 0)
5915                 lvalue = true;
5916             break;
5917         case glslang::EOpSparseImageLoad:
5918             if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))
5919                 lvalue = true;
5920             break;
5921         case glslang::EOpSparseTexture:
5922             if (((cubeCompare || f16ShadowCompare) && i == 3) || (! (cubeCompare || f16ShadowCompare) && i == 2))
5923                 lvalue = true;
5924             break;
5925         case glslang::EOpSparseTextureClamp:
5926             if (((cubeCompare || f16ShadowCompare) && i == 4) || (! (cubeCompare || f16ShadowCompare) && i == 3))
5927                 lvalue = true;
5928             break;
5929         case glslang::EOpSparseTextureLod:
5930         case glslang::EOpSparseTextureOffset:
5931             if  ((f16ShadowCompare && i == 4) || (! f16ShadowCompare && i == 3))
5932                 lvalue = true;
5933             break;
5934         case glslang::EOpSparseTextureFetch:
5935             if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))
5936                 lvalue = true;
5937             break;
5938         case glslang::EOpSparseTextureFetchOffset:
5939             if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))
5940                 lvalue = true;
5941             break;
5942         case glslang::EOpSparseTextureLodOffset:
5943         case glslang::EOpSparseTextureGrad:
5944         case glslang::EOpSparseTextureOffsetClamp:
5945             if ((f16ShadowCompare && i == 5) || (! f16ShadowCompare && i == 4))
5946                 lvalue = true;
5947             break;
5948         case glslang::EOpSparseTextureGradOffset:
5949         case glslang::EOpSparseTextureGradClamp:
5950             if ((f16ShadowCompare && i == 6) || (! f16ShadowCompare && i == 5))
5951                 lvalue = true;
5952             break;
5953         case glslang::EOpSparseTextureGradOffsetClamp:
5954             if ((f16ShadowCompare && i == 7) || (! f16ShadowCompare && i == 6))
5955                 lvalue = true;
5956             break;
5957         case glslang::EOpSparseTextureGather:
5958             if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
5959                 lvalue = true;
5960             break;
5961         case glslang::EOpSparseTextureGatherOffset:
5962         case glslang::EOpSparseTextureGatherOffsets:
5963             if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
5964                 lvalue = true;
5965             break;
5966         case glslang::EOpSparseTextureGatherLod:
5967             if (i == 3)
5968                 lvalue = true;
5969             break;
5970         case glslang::EOpSparseTextureGatherLodOffset:
5971         case glslang::EOpSparseTextureGatherLodOffsets:
5972             if (i == 4)
5973                 lvalue = true;
5974             break;
5975         case glslang::EOpSparseImageLoadLod:
5976             if (i == 3)
5977                 lvalue = true;
5978             break;
5979         case glslang::EOpImageSampleFootprintNV:
5980             if (i == 4)
5981                 lvalue = true;
5982             break;
5983         case glslang::EOpImageSampleFootprintClampNV:
5984         case glslang::EOpImageSampleFootprintLodNV:
5985             if (i == 5)
5986                 lvalue = true;
5987             break;
5988         case glslang::EOpImageSampleFootprintGradNV:
5989             if (i == 6)
5990                 lvalue = true;
5991             break;
5992         case glslang::EOpImageSampleFootprintGradClampNV:
5993             if (i == 7)
5994                 lvalue = true;
5995             break;
5996         case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
5997             if (i == 2)
5998                 lvalue = true;
5999             break;
6000         default:
6001             break;
6002         }
6003 
6004         if (lvalue) {
6005             spv::Id lvalue_id = builder.accessChainGetLValue();
6006             arguments.push_back(lvalue_id);
6007             lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
6008             builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags));
6009             lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());
6010         } else {
6011             if (i > 0 &&
6012                 glslangArguments[i]->getAsSymbolNode() && glslangArguments[i-1]->getAsSymbolNode() &&
6013                 glslangArguments[i]->getAsSymbolNode()->getId() == glslangArguments[i-1]->getAsSymbolNode()->getId()) {
6014                 // Reuse the id if possible
6015                 arguments.push_back(arguments[i-1]);
6016             } else {
6017                 arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));
6018             }
6019         }
6020     }
6021 }
6022 
translateArguments(glslang::TIntermUnary & node,std::vector<spv::Id> & arguments)6023 void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)
6024 {
6025     builder.clearAccessChain();
6026     node.getOperand()->traverse(this);
6027     arguments.push_back(accessChainLoad(node.getOperand()->getType()));
6028 }
6029 
createImageTextureFunctionCall(glslang::TIntermOperator * node)6030 spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
6031 {
6032     if (! node->isImage() && ! node->isTexture())
6033         return spv::NoResult;
6034 
6035     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
6036 
6037     // Process a GLSL texturing op (will be SPV image)
6038 
6039     const glslang::TType &imageType = node->getAsAggregate()
6040                                         ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType()
6041                                         : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType();
6042     const glslang::TSampler sampler = imageType.getSampler();
6043     bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate())
6044             ? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16
6045             : false;
6046 
6047     const auto signExtensionMask = [&]() {
6048         if (builder.getSpvVersion() >= spv::Spv_1_4) {
6049             if (sampler.type == glslang::EbtUint)
6050                 return spv::ImageOperandsZeroExtendMask;
6051             else if (sampler.type == glslang::EbtInt)
6052                 return spv::ImageOperandsSignExtendMask;
6053         }
6054         return spv::ImageOperandsMaskNone;
6055     };
6056 
6057     spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
6058 
6059     std::vector<spv::Id> arguments;
6060     if (node->getAsAggregate())
6061         translateArguments(*node->getAsAggregate(), arguments, lvalueCoherentFlags);
6062     else
6063         translateArguments(*node->getAsUnaryNode(), arguments);
6064     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
6065 
6066     spv::Builder::TextureParameters params = { };
6067     params.sampler = arguments[0];
6068 
6069     glslang::TCrackedTextureOp cracked;
6070     node->crackTexture(sampler, cracked);
6071 
6072     const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint;
6073 
6074     if (builder.isSampledImage(params.sampler) &&
6075         ((cracked.query && node->getOp() != glslang::EOpTextureQueryLod) || cracked.fragMask || cracked.fetch)) {
6076         params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
6077         if (imageType.getQualifier().isNonUniform()) {
6078             builder.addDecoration(params.sampler, spv::DecorationNonUniformEXT);
6079         }
6080     }
6081     // Check for queries
6082     if (cracked.query) {
6083         switch (node->getOp()) {
6084         case glslang::EOpImageQuerySize:
6085         case glslang::EOpTextureQuerySize:
6086             if (arguments.size() > 1) {
6087                 params.lod = arguments[1];
6088                 return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params, isUnsignedResult);
6089             } else
6090                 return builder.createTextureQueryCall(spv::OpImageQuerySize, params, isUnsignedResult);
6091         case glslang::EOpImageQuerySamples:
6092         case glslang::EOpTextureQuerySamples:
6093             return builder.createTextureQueryCall(spv::OpImageQuerySamples, params, isUnsignedResult);
6094         case glslang::EOpTextureQueryLod:
6095             params.coords = arguments[1];
6096             return builder.createTextureQueryCall(spv::OpImageQueryLod, params, isUnsignedResult);
6097         case glslang::EOpTextureQueryLevels:
6098             return builder.createTextureQueryCall(spv::OpImageQueryLevels, params, isUnsignedResult);
6099         case glslang::EOpSparseTexelsResident:
6100             return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);
6101         default:
6102             assert(0);
6103             break;
6104         }
6105     }
6106 
6107     int components = node->getType().getVectorSize();
6108 
6109     if (node->getOp() == glslang::EOpImageLoad ||
6110         node->getOp() == glslang::EOpImageLoadLod ||
6111         node->getOp() == glslang::EOpTextureFetch ||
6112         node->getOp() == glslang::EOpTextureFetchOffset) {
6113         // These must produce 4 components, per SPIR-V spec.  We'll add a conversion constructor if needed.
6114         // This will only happen through the HLSL path for operator[], so we do not have to handle e.g.
6115         // the EOpTexture/Proj/Lod/etc family.  It would be harmless to do so, but would need more logic
6116         // here around e.g. which ones return scalars or other types.
6117         components = 4;
6118     }
6119 
6120     glslang::TType returnType(node->getType().getBasicType(), glslang::EvqTemporary, components);
6121 
6122     auto resultType = [&returnType,this]{ return convertGlslangToSpvType(returnType); };
6123 
6124     // Check for image functions other than queries
6125     if (node->isImage()) {
6126         std::vector<spv::IdImmediate> operands;
6127         auto opIt = arguments.begin();
6128         spv::IdImmediate image = { true, *(opIt++) };
6129         operands.push_back(image);
6130 
6131         // Handle subpass operations
6132         // TODO: GLSL should change to have the "MS" only on the type rather than the
6133         // built-in function.
6134         if (cracked.subpass) {
6135             // add on the (0,0) coordinate
6136             spv::Id zero = builder.makeIntConstant(0);
6137             std::vector<spv::Id> comps;
6138             comps.push_back(zero);
6139             comps.push_back(zero);
6140             spv::IdImmediate coord = { true,
6141                 builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps) };
6142             operands.push_back(coord);
6143             spv::IdImmediate imageOperands = { false, spv::ImageOperandsMaskNone };
6144             imageOperands.word = imageOperands.word | signExtensionMask();
6145             if (sampler.isMultiSample()) {
6146                 imageOperands.word = imageOperands.word | spv::ImageOperandsSampleMask;
6147             }
6148             if (imageOperands.word != spv::ImageOperandsMaskNone) {
6149                 operands.push_back(imageOperands);
6150                 if (sampler.isMultiSample()) {
6151                     spv::IdImmediate imageOperand = { true, *(opIt++) };
6152                     operands.push_back(imageOperand);
6153                 }
6154             }
6155             spv::Id result = builder.createOp(spv::OpImageRead, resultType(), operands);
6156             builder.setPrecision(result, precision);
6157             return result;
6158         }
6159 
6160         if (cracked.attachmentEXT) {
6161             if (opIt != arguments.end()) {
6162                 spv::IdImmediate sample = { true, *opIt };
6163                 operands.push_back(sample);
6164             }
6165             spv::Id result = builder.createOp(spv::OpColorAttachmentReadEXT, resultType(), operands);
6166             builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
6167             builder.setPrecision(result, precision);
6168             return result;
6169         }
6170 
6171         spv::IdImmediate coord = { true, *(opIt++) };
6172         operands.push_back(coord);
6173         if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) {
6174             spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
6175             if (sampler.isMultiSample()) {
6176                 mask = mask | spv::ImageOperandsSampleMask;
6177             }
6178             if (cracked.lod) {
6179                 builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6180                 builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
6181                 mask = mask | spv::ImageOperandsLodMask;
6182             }
6183             mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6184             mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);
6185             mask = mask | signExtensionMask();
6186             if (mask != spv::ImageOperandsMaskNone) {
6187                 spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6188                 operands.push_back(imageOperands);
6189             }
6190             if (mask & spv::ImageOperandsSampleMask) {
6191                 spv::IdImmediate imageOperand = { true, *opIt++ };
6192                 operands.push_back(imageOperand);
6193             }
6194             if (mask & spv::ImageOperandsLodMask) {
6195                 spv::IdImmediate imageOperand = { true, *opIt++ };
6196                 operands.push_back(imageOperand);
6197             }
6198             if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
6199                 spv::IdImmediate imageOperand = { true,
6200                                     builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
6201                 operands.push_back(imageOperand);
6202             }
6203 
6204             if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
6205                 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
6206 
6207             std::vector<spv::Id> result(1, builder.createOp(spv::OpImageRead, resultType(), operands));
6208             builder.setPrecision(result[0], precision);
6209 
6210             // If needed, add a conversion constructor to the proper size.
6211             if (components != node->getType().getVectorSize())
6212                 result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
6213 
6214             return result[0];
6215         } else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) {
6216 
6217             // Push the texel value before the operands
6218             if (sampler.isMultiSample() || cracked.lod) {
6219                 spv::IdImmediate texel = { true, *(opIt + 1) };
6220                 operands.push_back(texel);
6221             } else {
6222                 spv::IdImmediate texel = { true, *opIt };
6223                 operands.push_back(texel);
6224             }
6225 
6226             spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
6227             if (sampler.isMultiSample()) {
6228                 mask = mask | spv::ImageOperandsSampleMask;
6229             }
6230             if (cracked.lod) {
6231                 builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6232                 builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
6233                 mask = mask | spv::ImageOperandsLodMask;
6234             }
6235             mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6236             mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelVisibleKHRMask);
6237             mask = mask | signExtensionMask();
6238             if (mask != spv::ImageOperandsMaskNone) {
6239                 spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6240                 operands.push_back(imageOperands);
6241             }
6242             if (mask & spv::ImageOperandsSampleMask) {
6243                 spv::IdImmediate imageOperand = { true, *opIt++ };
6244                 operands.push_back(imageOperand);
6245             }
6246             if (mask & spv::ImageOperandsLodMask) {
6247                 spv::IdImmediate imageOperand = { true, *opIt++ };
6248                 operands.push_back(imageOperand);
6249             }
6250             if (mask & spv::ImageOperandsMakeTexelAvailableKHRMask) {
6251                 spv::IdImmediate imageOperand = { true,
6252                     builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
6253                 operands.push_back(imageOperand);
6254             }
6255 
6256             builder.createNoResultOp(spv::OpImageWrite, operands);
6257             if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
6258                 builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat);
6259             return spv::NoResult;
6260         } else if (node->getOp() == glslang::EOpSparseImageLoad ||
6261                    node->getOp() == glslang::EOpSparseImageLoadLod) {
6262             builder.addCapability(spv::CapabilitySparseResidency);
6263             if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
6264                 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
6265 
6266             spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
6267             if (sampler.isMultiSample()) {
6268                 mask = mask | spv::ImageOperandsSampleMask;
6269             }
6270             if (cracked.lod) {
6271                 builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6272                 builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
6273 
6274                 mask = mask | spv::ImageOperandsLodMask;
6275             }
6276             mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6277             mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);
6278             mask = mask | signExtensionMask();
6279             if (mask != spv::ImageOperandsMaskNone) {
6280                 spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6281                 operands.push_back(imageOperands);
6282             }
6283             if (mask & spv::ImageOperandsSampleMask) {
6284                 spv::IdImmediate imageOperand = { true, *opIt++ };
6285                 operands.push_back(imageOperand);
6286             }
6287             if (mask & spv::ImageOperandsLodMask) {
6288                 spv::IdImmediate imageOperand = { true, *opIt++ };
6289                 operands.push_back(imageOperand);
6290             }
6291             if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
6292                 spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(
6293                     TranslateCoherent(imageType))) };
6294                 operands.push_back(imageOperand);
6295             }
6296 
6297             // Create the return type that was a special structure
6298             spv::Id texelOut = *opIt;
6299             spv::Id typeId0 = resultType();
6300             spv::Id typeId1 = builder.getDerefTypeId(texelOut);
6301             spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);
6302 
6303             spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands);
6304 
6305             // Decode the return type
6306             builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);
6307             return builder.createCompositeExtract(resultId, typeId0, 0);
6308         } else {
6309             // Process image atomic operations
6310 
6311             // GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
6312             // as the first source operand, is required by SPIR-V atomic operations.
6313             // For non-MS, the sample value should be 0
6314             spv::IdImmediate sample = { true, sampler.isMultiSample() ? *(opIt++) : builder.makeUintConstant(0) };
6315             operands.push_back(sample);
6316 
6317             spv::Id resultTypeId;
6318             glslang::TBasicType typeProxy = node->getBasicType();
6319             // imageAtomicStore has a void return type so base the pointer type on
6320             // the type of the value operand.
6321             if (node->getOp() == glslang::EOpImageAtomicStore) {
6322                 resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(*opIt));
6323                 typeProxy = node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler().type;
6324             } else {
6325                 resultTypeId = builder.makePointer(spv::StorageClassImage, resultType());
6326             }
6327             spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands);
6328             if (imageType.getQualifier().nonUniform) {
6329                 builder.addDecoration(pointer, spv::DecorationNonUniformEXT);
6330             }
6331 
6332             std::vector<spv::Id> operands;
6333             operands.push_back(pointer);
6334             for (; opIt != arguments.end(); ++opIt)
6335                 operands.push_back(*opIt);
6336 
6337             return createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,
6338                 lvalueCoherentFlags, node->getType());
6339         }
6340     }
6341 
6342     // Check for fragment mask functions other than queries
6343     if (cracked.fragMask) {
6344         assert(sampler.ms);
6345 
6346         auto opIt = arguments.begin();
6347         std::vector<spv::Id> operands;
6348 
6349         operands.push_back(params.sampler);
6350         ++opIt;
6351 
6352         if (sampler.isSubpass()) {
6353             // add on the (0,0) coordinate
6354             spv::Id zero = builder.makeIntConstant(0);
6355             std::vector<spv::Id> comps;
6356             comps.push_back(zero);
6357             comps.push_back(zero);
6358             operands.push_back(builder.makeCompositeConstant(
6359                 builder.makeVectorType(builder.makeIntType(32), 2), comps));
6360         }
6361 
6362         for (; opIt != arguments.end(); ++opIt)
6363             operands.push_back(*opIt);
6364 
6365         spv::Op fragMaskOp = spv::OpNop;
6366         if (node->getOp() == glslang::EOpFragmentMaskFetch)
6367             fragMaskOp = spv::OpFragmentMaskFetchAMD;
6368         else if (node->getOp() == glslang::EOpFragmentFetch)
6369             fragMaskOp = spv::OpFragmentFetchAMD;
6370 
6371         builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask);
6372         builder.addCapability(spv::CapabilityFragmentMaskAMD);
6373         return builder.createOp(fragMaskOp, resultType(), operands);
6374     }
6375 
6376     // Check for texture functions other than queries
6377     bool sparse = node->isSparseTexture();
6378     bool imageFootprint = node->isImageFootprint();
6379     bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.isArrayed() && sampler.isShadow();
6380 
6381     // check for bias argument
6382     bool bias = false;
6383     if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
6384         int nonBiasArgCount = 2;
6385         if (cracked.gather)
6386             ++nonBiasArgCount; // comp argument should be present when bias argument is present
6387 
6388         if (f16ShadowCompare)
6389             ++nonBiasArgCount;
6390         if (cracked.offset)
6391             ++nonBiasArgCount;
6392         else if (cracked.offsets)
6393             ++nonBiasArgCount;
6394         if (cracked.grad)
6395             nonBiasArgCount += 2;
6396         if (cracked.lodClamp)
6397             ++nonBiasArgCount;
6398         if (sparse)
6399             ++nonBiasArgCount;
6400         if (imageFootprint)
6401             //Following three extra arguments
6402             // int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
6403             nonBiasArgCount += 3;
6404         if ((int)arguments.size() > nonBiasArgCount)
6405             bias = true;
6406     }
6407 
6408     if (cracked.gather) {
6409         const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
6410         if (bias || cracked.lod ||
6411             sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) {
6412             builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod);
6413             builder.addCapability(spv::CapabilityImageGatherBiasLodAMD);
6414         }
6415     }
6416 
6417     // set the rest of the arguments
6418 
6419     params.coords = arguments[1];
6420     int extraArgs = 0;
6421     bool noImplicitLod = false;
6422 
6423     // sort out where Dref is coming from
6424     if (cubeCompare || f16ShadowCompare) {
6425         params.Dref = arguments[2];
6426         ++extraArgs;
6427     } else if (sampler.shadow && cracked.gather) {
6428         params.Dref = arguments[2];
6429         ++extraArgs;
6430     } else if (sampler.shadow) {
6431         std::vector<spv::Id> indexes;
6432         int dRefComp;
6433         if (cracked.proj)
6434             dRefComp = 2;  // "The resulting 3rd component of P in the shadow forms is used as Dref"
6435         else
6436             dRefComp = builder.getNumComponents(params.coords) - 1;
6437         indexes.push_back(dRefComp);
6438         params.Dref = builder.createCompositeExtract(params.coords,
6439             builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
6440     }
6441 
6442     // lod
6443     if (cracked.lod) {
6444         params.lod = arguments[2 + extraArgs];
6445         ++extraArgs;
6446     } else if (glslangIntermediate->getStage() != EShLangFragment &&
6447                !(glslangIntermediate->getStage() == EShLangCompute &&
6448                  glslangIntermediate->hasLayoutDerivativeModeNone())) {
6449         // we need to invent the default lod for an explicit lod instruction for a non-fragment stage
6450         noImplicitLod = true;
6451     }
6452 
6453     // multisample
6454     if (sampler.isMultiSample()) {
6455         params.sample = arguments[2 + extraArgs]; // For MS, "sample" should be specified
6456         ++extraArgs;
6457     }
6458 
6459     // gradient
6460     if (cracked.grad) {
6461         params.gradX = arguments[2 + extraArgs];
6462         params.gradY = arguments[3 + extraArgs];
6463         extraArgs += 2;
6464     }
6465 
6466     // offset and offsets
6467     if (cracked.offset) {
6468         params.offset = arguments[2 + extraArgs];
6469         ++extraArgs;
6470     } else if (cracked.offsets) {
6471         params.offsets = arguments[2 + extraArgs];
6472         ++extraArgs;
6473     }
6474 
6475     // lod clamp
6476     if (cracked.lodClamp) {
6477         params.lodClamp = arguments[2 + extraArgs];
6478         ++extraArgs;
6479     }
6480     // sparse
6481     if (sparse) {
6482         params.texelOut = arguments[2 + extraArgs];
6483         ++extraArgs;
6484     }
6485     // gather component
6486     if (cracked.gather && ! sampler.shadow) {
6487         // default component is 0, if missing, otherwise an argument
6488         if (2 + extraArgs < (int)arguments.size()) {
6489             params.component = arguments[2 + extraArgs];
6490             ++extraArgs;
6491         } else
6492             params.component = builder.makeIntConstant(0);
6493     }
6494     spv::Id  resultStruct = spv::NoResult;
6495     if (imageFootprint) {
6496         //Following three extra arguments
6497         // int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
6498         params.granularity = arguments[2 + extraArgs];
6499         params.coarse = arguments[3 + extraArgs];
6500         resultStruct = arguments[4 + extraArgs];
6501         extraArgs += 3;
6502     }
6503 
6504     // bias
6505     if (bias) {
6506         params.bias = arguments[2 + extraArgs];
6507         ++extraArgs;
6508     }
6509 
6510     if (imageFootprint) {
6511         builder.addExtension(spv::E_SPV_NV_shader_image_footprint);
6512         builder.addCapability(spv::CapabilityImageFootprintNV);
6513 
6514 
6515         //resultStructType(OpenGL type) contains 5 elements:
6516         //struct gl_TextureFootprint2DNV {
6517         //    uvec2 anchor;
6518         //    uvec2 offset;
6519         //    uvec2 mask;
6520         //    uint  lod;
6521         //    uint  granularity;
6522         //};
6523         //or
6524         //struct gl_TextureFootprint3DNV {
6525         //    uvec3 anchor;
6526         //    uvec3 offset;
6527         //    uvec2 mask;
6528         //    uint  lod;
6529         //    uint  granularity;
6530         //};
6531         spv::Id resultStructType = builder.getContainedTypeId(builder.getTypeId(resultStruct));
6532         assert(builder.isStructType(resultStructType));
6533 
6534         //resType (SPIR-V type) contains 6 elements:
6535         //Member 0 must be a Boolean type scalar(LOD),
6536         //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor),
6537         //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset),
6538         //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask),
6539         //Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod),
6540         //Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity).
6541         std::vector<spv::Id> members;
6542         members.push_back(resultType());
6543         for (int i = 0; i < 5; i++) {
6544             members.push_back(builder.getContainedTypeId(resultStructType, i));
6545         }
6546         spv::Id resType = builder.makeStructType(members, "ResType");
6547 
6548         //call ImageFootprintNV
6549         spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj,
6550                                                 cracked.gather, noImplicitLod, params, signExtensionMask());
6551 
6552         //copy resType (SPIR-V type) to resultStructType(OpenGL type)
6553         for (int i = 0; i < 5; i++) {
6554             builder.clearAccessChain();
6555             builder.setAccessChainLValue(resultStruct);
6556 
6557             //Accessing to a struct we created, no coherent flag is set
6558             spv::Builder::AccessChain::CoherentFlags flags;
6559             flags.clear();
6560 
6561             builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
6562             builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1),
6563                 i+1), TranslateNonUniformDecoration(imageType.getQualifier()));
6564         }
6565         return builder.createCompositeExtract(res, resultType(), 0);
6566     }
6567 
6568     // projective component (might not to move)
6569     // GLSL: "The texture coordinates consumed from P, not including the last component of P,
6570     //       are divided by the last component of P."
6571     // SPIR-V:  "... (u [, v] [, w], q)... It may be a vector larger than needed, but all
6572     //          unused components will appear after all used components."
6573     if (cracked.proj) {
6574         int projSourceComp = builder.getNumComponents(params.coords) - 1;
6575         int projTargetComp;
6576         switch (sampler.dim) {
6577         case glslang::Esd1D:   projTargetComp = 1;              break;
6578         case glslang::Esd2D:   projTargetComp = 2;              break;
6579         case glslang::EsdRect: projTargetComp = 2;              break;
6580         default:               projTargetComp = projSourceComp; break;
6581         }
6582         // copy the projective coordinate if we have to
6583         if (projTargetComp != projSourceComp) {
6584             spv::Id projComp = builder.createCompositeExtract(params.coords,
6585                                     builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp);
6586             params.coords = builder.createCompositeInsert(projComp, params.coords,
6587                                     builder.getTypeId(params.coords), projTargetComp);
6588         }
6589     }
6590 
6591     // nonprivate
6592     if (imageType.getQualifier().nonprivate) {
6593         params.nonprivate = true;
6594     }
6595 
6596     // volatile
6597     if (imageType.getQualifier().volatil) {
6598         params.volatil = true;
6599     }
6600 
6601     std::vector<spv::Id> result( 1,
6602         builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather,
6603                                   noImplicitLod, params, signExtensionMask())
6604     );
6605 
6606     if (components != node->getType().getVectorSize())
6607         result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
6608 
6609     return result[0];
6610 }
6611 
handleUserFunctionCall(const glslang::TIntermAggregate * node)6612 spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
6613 {
6614     // Grab the function's pointer from the previously created function
6615     spv::Function* function = functionMap[node->getName().c_str()];
6616     if (! function)
6617         return 0;
6618 
6619     const glslang::TIntermSequence& glslangArgs = node->getSequence();
6620     const glslang::TQualifierList& qualifiers = node->getQualifierList();
6621 
6622     //  See comments in makeFunctions() for details about the semantics for parameter passing.
6623     //
6624     // These imply we need a four step process:
6625     // 1. Evaluate the arguments
6626     // 2. Allocate and make copies of in, out, and inout arguments
6627     // 3. Make the call
6628     // 4. Copy back the results
6629 
6630     // 1. Evaluate the arguments and their types
6631     std::vector<spv::Builder::AccessChain> lValues;
6632     std::vector<spv::Id> rValues;
6633     std::vector<const glslang::TType*> argTypes;
6634     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
6635         argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType());
6636         // build l-value
6637         builder.clearAccessChain();
6638         glslangArgs[a]->traverse(this);
6639         // keep outputs and pass-by-originals as l-values, evaluate others as r-values
6640         if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0) ||
6641             writableParam(qualifiers[a])) {
6642             // save l-value
6643             lValues.push_back(builder.getAccessChain());
6644         } else {
6645             // process r-value
6646             rValues.push_back(accessChainLoad(*argTypes.back()));
6647         }
6648     }
6649 
6650     // Reset source location to the function call location after argument evaluation
6651     builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
6652 
6653     // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
6654     // copy the original into that space.
6655     //
6656     // Also, build up the list of actual arguments to pass in for the call
6657     int lValueCount = 0;
6658     int rValueCount = 0;
6659     std::vector<spv::Id> spvArgs;
6660     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
6661         spv::Id arg;
6662         if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) {
6663             builder.setAccessChain(lValues[lValueCount]);
6664             arg = builder.accessChainGetLValue();
6665             ++lValueCount;
6666         } else if (writableParam(qualifiers[a])) {
6667             // need space to hold the copy
6668             arg = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction,
6669                 builder.getContainedTypeId(function->getParamType(a)), "param");
6670             if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
6671                 // need to copy the input into output space
6672                 builder.setAccessChain(lValues[lValueCount]);
6673                 spv::Id copy = accessChainLoad(*argTypes[a]);
6674                 builder.clearAccessChain();
6675                 builder.setAccessChainLValue(arg);
6676                 multiTypeStore(*argTypes[a], copy);
6677             }
6678             ++lValueCount;
6679         } else {
6680             // process r-value, which involves a copy for a type mismatch
6681             if (function->getParamType(a) != builder.getTypeId(rValues[rValueCount]) ||
6682                 TranslatePrecisionDecoration(*argTypes[a]) != function->getParamPrecision(a))
6683             {
6684                 spv::Id argCopy = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction, function->getParamType(a), "arg");
6685                 builder.clearAccessChain();
6686                 builder.setAccessChainLValue(argCopy);
6687                 multiTypeStore(*argTypes[a], rValues[rValueCount]);
6688                 arg = builder.createLoad(argCopy, function->getParamPrecision(a));
6689             } else
6690                 arg = rValues[rValueCount];
6691             ++rValueCount;
6692         }
6693         spvArgs.push_back(arg);
6694     }
6695 
6696     // 3. Make the call.
6697     spv::Id result = builder.createFunctionCall(function, spvArgs);
6698     builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
6699     builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier()));
6700 
6701     // 4. Copy back out an "out" arguments.
6702     lValueCount = 0;
6703     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
6704         if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0))
6705             ++lValueCount;
6706         else if (writableParam(qualifiers[a])) {
6707             if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
6708                 spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision);
6709                 builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier()));
6710                 builder.setAccessChain(lValues[lValueCount]);
6711                 multiTypeStore(*argTypes[a], copy);
6712             }
6713             ++lValueCount;
6714         }
6715     }
6716 
6717     return result;
6718 }
6719 
6720 // Translate AST operation to SPV operation, already having SPV-based operands/types.
createBinaryOperation(glslang::TOperator op,OpDecorations & decorations,spv::Id typeId,spv::Id left,spv::Id right,glslang::TBasicType typeProxy,bool reduceComparison)6721 spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpDecorations& decorations,
6722                                                       spv::Id typeId, spv::Id left, spv::Id right,
6723                                                       glslang::TBasicType typeProxy, bool reduceComparison)
6724 {
6725     bool isUnsigned = isTypeUnsignedInt(typeProxy);
6726     bool isFloat = isTypeFloat(typeProxy);
6727     bool isBool = typeProxy == glslang::EbtBool;
6728 
6729     spv::Op binOp = spv::OpNop;
6730     bool needMatchingVectors = true;  // for non-matrix ops, would a scalar need to smear to match a vector?
6731     bool comparison = false;
6732 
6733     switch (op) {
6734     case glslang::EOpAdd:
6735     case glslang::EOpAddAssign:
6736         if (isFloat)
6737             binOp = spv::OpFAdd;
6738         else
6739             binOp = spv::OpIAdd;
6740         break;
6741     case glslang::EOpSub:
6742     case glslang::EOpSubAssign:
6743         if (isFloat)
6744             binOp = spv::OpFSub;
6745         else
6746             binOp = spv::OpISub;
6747         break;
6748     case glslang::EOpMul:
6749     case glslang::EOpMulAssign:
6750         if (isFloat)
6751             binOp = spv::OpFMul;
6752         else
6753             binOp = spv::OpIMul;
6754         break;
6755     case glslang::EOpVectorTimesScalar:
6756     case glslang::EOpVectorTimesScalarAssign:
6757         if (isFloat && (builder.isVector(left) || builder.isVector(right))) {
6758             if (builder.isVector(right))
6759                 std::swap(left, right);
6760             assert(builder.isScalar(right));
6761             needMatchingVectors = false;
6762             binOp = spv::OpVectorTimesScalar;
6763         } else if (isFloat)
6764             binOp = spv::OpFMul;
6765           else
6766             binOp = spv::OpIMul;
6767         break;
6768     case glslang::EOpVectorTimesMatrix:
6769     case glslang::EOpVectorTimesMatrixAssign:
6770         binOp = spv::OpVectorTimesMatrix;
6771         break;
6772     case glslang::EOpMatrixTimesVector:
6773         binOp = spv::OpMatrixTimesVector;
6774         break;
6775     case glslang::EOpMatrixTimesScalar:
6776     case glslang::EOpMatrixTimesScalarAssign:
6777         binOp = spv::OpMatrixTimesScalar;
6778         break;
6779     case glslang::EOpMatrixTimesMatrix:
6780     case glslang::EOpMatrixTimesMatrixAssign:
6781         binOp = spv::OpMatrixTimesMatrix;
6782         break;
6783     case glslang::EOpOuterProduct:
6784         binOp = spv::OpOuterProduct;
6785         needMatchingVectors = false;
6786         break;
6787 
6788     case glslang::EOpDiv:
6789     case glslang::EOpDivAssign:
6790         if (isFloat)
6791             binOp = spv::OpFDiv;
6792         else if (isUnsigned)
6793             binOp = spv::OpUDiv;
6794         else
6795             binOp = spv::OpSDiv;
6796         break;
6797     case glslang::EOpMod:
6798     case glslang::EOpModAssign:
6799         if (isFloat)
6800             binOp = spv::OpFMod;
6801         else if (isUnsigned)
6802             binOp = spv::OpUMod;
6803         else
6804             binOp = spv::OpSMod;
6805         break;
6806     case glslang::EOpRightShift:
6807     case glslang::EOpRightShiftAssign:
6808         if (isUnsigned)
6809             binOp = spv::OpShiftRightLogical;
6810         else
6811             binOp = spv::OpShiftRightArithmetic;
6812         break;
6813     case glslang::EOpLeftShift:
6814     case glslang::EOpLeftShiftAssign:
6815         binOp = spv::OpShiftLeftLogical;
6816         break;
6817     case glslang::EOpAnd:
6818     case glslang::EOpAndAssign:
6819         binOp = spv::OpBitwiseAnd;
6820         break;
6821     case glslang::EOpLogicalAnd:
6822         needMatchingVectors = false;
6823         binOp = spv::OpLogicalAnd;
6824         break;
6825     case glslang::EOpInclusiveOr:
6826     case glslang::EOpInclusiveOrAssign:
6827         binOp = spv::OpBitwiseOr;
6828         break;
6829     case glslang::EOpLogicalOr:
6830         needMatchingVectors = false;
6831         binOp = spv::OpLogicalOr;
6832         break;
6833     case glslang::EOpExclusiveOr:
6834     case glslang::EOpExclusiveOrAssign:
6835         binOp = spv::OpBitwiseXor;
6836         break;
6837     case glslang::EOpLogicalXor:
6838         needMatchingVectors = false;
6839         binOp = spv::OpLogicalNotEqual;
6840         break;
6841 
6842     case glslang::EOpAbsDifference:
6843         binOp = isUnsigned ? spv::OpAbsUSubINTEL : spv::OpAbsISubINTEL;
6844         break;
6845 
6846     case glslang::EOpAddSaturate:
6847         binOp = isUnsigned ? spv::OpUAddSatINTEL : spv::OpIAddSatINTEL;
6848         break;
6849 
6850     case glslang::EOpSubSaturate:
6851         binOp = isUnsigned ? spv::OpUSubSatINTEL : spv::OpISubSatINTEL;
6852         break;
6853 
6854     case glslang::EOpAverage:
6855         binOp = isUnsigned ? spv::OpUAverageINTEL : spv::OpIAverageINTEL;
6856         break;
6857 
6858     case glslang::EOpAverageRounded:
6859         binOp = isUnsigned ? spv::OpUAverageRoundedINTEL : spv::OpIAverageRoundedINTEL;
6860         break;
6861 
6862     case glslang::EOpMul32x16:
6863         binOp = isUnsigned ? spv::OpUMul32x16INTEL : spv::OpIMul32x16INTEL;
6864         break;
6865 
6866     case glslang::EOpExpectEXT:
6867         binOp = spv::OpExpectKHR;
6868         break;
6869 
6870     case glslang::EOpLessThan:
6871     case glslang::EOpGreaterThan:
6872     case glslang::EOpLessThanEqual:
6873     case glslang::EOpGreaterThanEqual:
6874     case glslang::EOpEqual:
6875     case glslang::EOpNotEqual:
6876     case glslang::EOpVectorEqual:
6877     case glslang::EOpVectorNotEqual:
6878         comparison = true;
6879         break;
6880     default:
6881         break;
6882     }
6883 
6884     // handle mapped binary operations (should be non-comparison)
6885     if (binOp != spv::OpNop) {
6886         assert(comparison == false);
6887         if (builder.isMatrix(left) || builder.isMatrix(right) ||
6888             builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
6889             return createBinaryMatrixOperation(binOp, decorations, typeId, left, right);
6890 
6891         // No matrix involved; make both operands be the same number of components, if needed
6892         if (needMatchingVectors)
6893             builder.promoteScalar(decorations.precision, left, right);
6894 
6895         spv::Id result = builder.createBinOp(binOp, typeId, left, right);
6896         decorations.addNoContraction(builder, result);
6897         decorations.addNonUniform(builder, result);
6898         return builder.setPrecision(result, decorations.precision);
6899     }
6900 
6901     if (! comparison)
6902         return 0;
6903 
6904     // Handle comparison instructions
6905 
6906     if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual)
6907                          && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
6908         spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual);
6909         decorations.addNonUniform(builder, result);
6910         return result;
6911     }
6912 
6913     switch (op) {
6914     case glslang::EOpLessThan:
6915         if (isFloat)
6916             binOp = spv::OpFOrdLessThan;
6917         else if (isUnsigned)
6918             binOp = spv::OpULessThan;
6919         else
6920             binOp = spv::OpSLessThan;
6921         break;
6922     case glslang::EOpGreaterThan:
6923         if (isFloat)
6924             binOp = spv::OpFOrdGreaterThan;
6925         else if (isUnsigned)
6926             binOp = spv::OpUGreaterThan;
6927         else
6928             binOp = spv::OpSGreaterThan;
6929         break;
6930     case glslang::EOpLessThanEqual:
6931         if (isFloat)
6932             binOp = spv::OpFOrdLessThanEqual;
6933         else if (isUnsigned)
6934             binOp = spv::OpULessThanEqual;
6935         else
6936             binOp = spv::OpSLessThanEqual;
6937         break;
6938     case glslang::EOpGreaterThanEqual:
6939         if (isFloat)
6940             binOp = spv::OpFOrdGreaterThanEqual;
6941         else if (isUnsigned)
6942             binOp = spv::OpUGreaterThanEqual;
6943         else
6944             binOp = spv::OpSGreaterThanEqual;
6945         break;
6946     case glslang::EOpEqual:
6947     case glslang::EOpVectorEqual:
6948         if (isFloat)
6949             binOp = spv::OpFOrdEqual;
6950         else if (isBool)
6951             binOp = spv::OpLogicalEqual;
6952         else
6953             binOp = spv::OpIEqual;
6954         break;
6955     case glslang::EOpNotEqual:
6956     case glslang::EOpVectorNotEqual:
6957         if (isFloat)
6958             binOp = spv::OpFUnordNotEqual;
6959         else if (isBool)
6960             binOp = spv::OpLogicalNotEqual;
6961         else
6962             binOp = spv::OpINotEqual;
6963         break;
6964     default:
6965         break;
6966     }
6967 
6968     if (binOp != spv::OpNop) {
6969         spv::Id result = builder.createBinOp(binOp, typeId, left, right);
6970         decorations.addNoContraction(builder, result);
6971         decorations.addNonUniform(builder, result);
6972         return builder.setPrecision(result, decorations.precision);
6973     }
6974 
6975     return 0;
6976 }
6977 
6978 //
6979 // Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
6980 // These can be any of:
6981 //
6982 //   matrix * scalar
6983 //   scalar * matrix
6984 //   matrix * matrix     linear algebraic
6985 //   matrix * vector
6986 //   vector * matrix
6987 //   matrix * matrix     componentwise
6988 //   matrix op matrix    op in {+, -, /}
6989 //   matrix op scalar    op in {+, -, /}
6990 //   scalar op matrix    op in {+, -, /}
6991 //
createBinaryMatrixOperation(spv::Op op,OpDecorations & decorations,spv::Id typeId,spv::Id left,spv::Id right)6992 spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
6993                                                             spv::Id left, spv::Id right)
6994 {
6995     bool firstClass = true;
6996 
6997     // First, handle first-class matrix operations (* and matrix/scalar)
6998     switch (op) {
6999     case spv::OpFDiv:
7000         if (builder.isMatrix(left) && builder.isScalar(right)) {
7001             // turn matrix / scalar into a multiply...
7002             spv::Id resultType = builder.getTypeId(right);
7003             right = builder.createBinOp(spv::OpFDiv, resultType, builder.makeFpConstant(resultType, 1.0), right);
7004             op = spv::OpMatrixTimesScalar;
7005         } else
7006             firstClass = false;
7007         break;
7008     case spv::OpMatrixTimesScalar:
7009         if (builder.isMatrix(right) || builder.isCooperativeMatrix(right))
7010             std::swap(left, right);
7011         assert(builder.isScalar(right));
7012         break;
7013     case spv::OpVectorTimesMatrix:
7014         assert(builder.isVector(left));
7015         assert(builder.isMatrix(right));
7016         break;
7017     case spv::OpMatrixTimesVector:
7018         assert(builder.isMatrix(left));
7019         assert(builder.isVector(right));
7020         break;
7021     case spv::OpMatrixTimesMatrix:
7022         assert(builder.isMatrix(left));
7023         assert(builder.isMatrix(right));
7024         break;
7025     default:
7026         firstClass = false;
7027         break;
7028     }
7029 
7030     if (builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
7031         firstClass = true;
7032 
7033     if (firstClass) {
7034         spv::Id result = builder.createBinOp(op, typeId, left, right);
7035         decorations.addNoContraction(builder, result);
7036         decorations.addNonUniform(builder, result);
7037         return builder.setPrecision(result, decorations.precision);
7038     }
7039 
7040     // Handle component-wise +, -, *, %, and / for all combinations of type.
7041     // The result type of all of them is the same type as the (a) matrix operand.
7042     // The algorithm is to:
7043     //   - break the matrix(es) into vectors
7044     //   - smear any scalar to a vector
7045     //   - do vector operations
7046     //   - make a matrix out the vector results
7047     switch (op) {
7048     case spv::OpFAdd:
7049     case spv::OpFSub:
7050     case spv::OpFDiv:
7051     case spv::OpFMod:
7052     case spv::OpFMul:
7053     {
7054         // one time set up...
7055         bool  leftMat = builder.isMatrix(left);
7056         bool rightMat = builder.isMatrix(right);
7057         unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);
7058         int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);
7059         spv::Id scalarType = builder.getScalarTypeId(typeId);
7060         spv::Id vecType = builder.makeVectorType(scalarType, numRows);
7061         std::vector<spv::Id> results;
7062         spv::Id smearVec = spv::NoResult;
7063         if (builder.isScalar(left))
7064             smearVec = builder.smearScalar(decorations.precision, left, vecType);
7065         else if (builder.isScalar(right))
7066             smearVec = builder.smearScalar(decorations.precision, right, vecType);
7067 
7068         // do each vector op
7069         for (unsigned int c = 0; c < numCols; ++c) {
7070             std::vector<unsigned int> indexes;
7071             indexes.push_back(c);
7072             spv::Id  leftVec =  leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
7073             spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
7074             spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
7075             decorations.addNoContraction(builder, result);
7076             decorations.addNonUniform(builder, result);
7077             results.push_back(builder.setPrecision(result, decorations.precision));
7078         }
7079 
7080         // put the pieces together
7081         spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
7082         decorations.addNonUniform(builder, result);
7083         return result;
7084     }
7085     default:
7086         assert(0);
7087         return spv::NoResult;
7088     }
7089 }
7090 
createUnaryOperation(glslang::TOperator op,OpDecorations & decorations,spv::Id typeId,spv::Id operand,glslang::TBasicType typeProxy,const spv::Builder::AccessChain::CoherentFlags & lvalueCoherentFlags,const glslang::TType & opType)7091 spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId,
7092     spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
7093     const glslang::TType &opType)
7094 {
7095     spv::Op unaryOp = spv::OpNop;
7096     int extBuiltins = -1;
7097     int libCall = -1;
7098     bool isUnsigned = isTypeUnsignedInt(typeProxy);
7099     bool isFloat = isTypeFloat(typeProxy);
7100 
7101     switch (op) {
7102     case glslang::EOpNegative:
7103         if (isFloat) {
7104             unaryOp = spv::OpFNegate;
7105             if (builder.isMatrixType(typeId))
7106                 return createUnaryMatrixOperation(unaryOp, decorations, typeId, operand, typeProxy);
7107         } else
7108             unaryOp = spv::OpSNegate;
7109         break;
7110 
7111     case glslang::EOpLogicalNot:
7112     case glslang::EOpVectorLogicalNot:
7113         unaryOp = spv::OpLogicalNot;
7114         break;
7115     case glslang::EOpBitwiseNot:
7116         unaryOp = spv::OpNot;
7117         break;
7118 
7119     case glslang::EOpDeterminant:
7120         libCall = spv::GLSLstd450Determinant;
7121         break;
7122     case glslang::EOpMatrixInverse:
7123         libCall = spv::GLSLstd450MatrixInverse;
7124         break;
7125     case glslang::EOpTranspose:
7126         unaryOp = spv::OpTranspose;
7127         break;
7128 
7129     case glslang::EOpRadians:
7130         libCall = spv::GLSLstd450Radians;
7131         break;
7132     case glslang::EOpDegrees:
7133         libCall = spv::GLSLstd450Degrees;
7134         break;
7135     case glslang::EOpSin:
7136         libCall = spv::GLSLstd450Sin;
7137         break;
7138     case glslang::EOpCos:
7139         libCall = spv::GLSLstd450Cos;
7140         break;
7141     case glslang::EOpTan:
7142         libCall = spv::GLSLstd450Tan;
7143         break;
7144     case glslang::EOpAcos:
7145         libCall = spv::GLSLstd450Acos;
7146         break;
7147     case glslang::EOpAsin:
7148         libCall = spv::GLSLstd450Asin;
7149         break;
7150     case glslang::EOpAtan:
7151         libCall = spv::GLSLstd450Atan;
7152         break;
7153 
7154     case glslang::EOpAcosh:
7155         libCall = spv::GLSLstd450Acosh;
7156         break;
7157     case glslang::EOpAsinh:
7158         libCall = spv::GLSLstd450Asinh;
7159         break;
7160     case glslang::EOpAtanh:
7161         libCall = spv::GLSLstd450Atanh;
7162         break;
7163     case glslang::EOpTanh:
7164         libCall = spv::GLSLstd450Tanh;
7165         break;
7166     case glslang::EOpCosh:
7167         libCall = spv::GLSLstd450Cosh;
7168         break;
7169     case glslang::EOpSinh:
7170         libCall = spv::GLSLstd450Sinh;
7171         break;
7172 
7173     case glslang::EOpLength:
7174         libCall = spv::GLSLstd450Length;
7175         break;
7176     case glslang::EOpNormalize:
7177         libCall = spv::GLSLstd450Normalize;
7178         break;
7179 
7180     case glslang::EOpExp:
7181         libCall = spv::GLSLstd450Exp;
7182         break;
7183     case glslang::EOpLog:
7184         libCall = spv::GLSLstd450Log;
7185         break;
7186     case glslang::EOpExp2:
7187         libCall = spv::GLSLstd450Exp2;
7188         break;
7189     case glslang::EOpLog2:
7190         libCall = spv::GLSLstd450Log2;
7191         break;
7192     case glslang::EOpSqrt:
7193         libCall = spv::GLSLstd450Sqrt;
7194         break;
7195     case glslang::EOpInverseSqrt:
7196         libCall = spv::GLSLstd450InverseSqrt;
7197         break;
7198 
7199     case glslang::EOpFloor:
7200         libCall = spv::GLSLstd450Floor;
7201         break;
7202     case glslang::EOpTrunc:
7203         libCall = spv::GLSLstd450Trunc;
7204         break;
7205     case glslang::EOpRound:
7206         libCall = spv::GLSLstd450Round;
7207         break;
7208     case glslang::EOpRoundEven:
7209         libCall = spv::GLSLstd450RoundEven;
7210         break;
7211     case glslang::EOpCeil:
7212         libCall = spv::GLSLstd450Ceil;
7213         break;
7214     case glslang::EOpFract:
7215         libCall = spv::GLSLstd450Fract;
7216         break;
7217 
7218     case glslang::EOpIsNan:
7219         unaryOp = spv::OpIsNan;
7220         break;
7221     case glslang::EOpIsInf:
7222         unaryOp = spv::OpIsInf;
7223         break;
7224     case glslang::EOpIsFinite:
7225         unaryOp = spv::OpIsFinite;
7226         break;
7227 
7228     case glslang::EOpFloatBitsToInt:
7229     case glslang::EOpFloatBitsToUint:
7230     case glslang::EOpIntBitsToFloat:
7231     case glslang::EOpUintBitsToFloat:
7232     case glslang::EOpDoubleBitsToInt64:
7233     case glslang::EOpDoubleBitsToUint64:
7234     case glslang::EOpInt64BitsToDouble:
7235     case glslang::EOpUint64BitsToDouble:
7236     case glslang::EOpFloat16BitsToInt16:
7237     case glslang::EOpFloat16BitsToUint16:
7238     case glslang::EOpInt16BitsToFloat16:
7239     case glslang::EOpUint16BitsToFloat16:
7240         unaryOp = spv::OpBitcast;
7241         break;
7242 
7243     case glslang::EOpPackSnorm2x16:
7244         libCall = spv::GLSLstd450PackSnorm2x16;
7245         break;
7246     case glslang::EOpUnpackSnorm2x16:
7247         libCall = spv::GLSLstd450UnpackSnorm2x16;
7248         break;
7249     case glslang::EOpPackUnorm2x16:
7250         libCall = spv::GLSLstd450PackUnorm2x16;
7251         break;
7252     case glslang::EOpUnpackUnorm2x16:
7253         libCall = spv::GLSLstd450UnpackUnorm2x16;
7254         break;
7255     case glslang::EOpPackHalf2x16:
7256         libCall = spv::GLSLstd450PackHalf2x16;
7257         break;
7258     case glslang::EOpUnpackHalf2x16:
7259         libCall = spv::GLSLstd450UnpackHalf2x16;
7260         break;
7261     case glslang::EOpPackSnorm4x8:
7262         libCall = spv::GLSLstd450PackSnorm4x8;
7263         break;
7264     case glslang::EOpUnpackSnorm4x8:
7265         libCall = spv::GLSLstd450UnpackSnorm4x8;
7266         break;
7267     case glslang::EOpPackUnorm4x8:
7268         libCall = spv::GLSLstd450PackUnorm4x8;
7269         break;
7270     case glslang::EOpUnpackUnorm4x8:
7271         libCall = spv::GLSLstd450UnpackUnorm4x8;
7272         break;
7273     case glslang::EOpPackDouble2x32:
7274         libCall = spv::GLSLstd450PackDouble2x32;
7275         break;
7276     case glslang::EOpUnpackDouble2x32:
7277         libCall = spv::GLSLstd450UnpackDouble2x32;
7278         break;
7279 
7280     case glslang::EOpPackInt2x32:
7281     case glslang::EOpUnpackInt2x32:
7282     case glslang::EOpPackUint2x32:
7283     case glslang::EOpUnpackUint2x32:
7284     case glslang::EOpPack16:
7285     case glslang::EOpPack32:
7286     case glslang::EOpPack64:
7287     case glslang::EOpUnpack32:
7288     case glslang::EOpUnpack16:
7289     case glslang::EOpUnpack8:
7290     case glslang::EOpPackInt2x16:
7291     case glslang::EOpUnpackInt2x16:
7292     case glslang::EOpPackUint2x16:
7293     case glslang::EOpUnpackUint2x16:
7294     case glslang::EOpPackInt4x16:
7295     case glslang::EOpUnpackInt4x16:
7296     case glslang::EOpPackUint4x16:
7297     case glslang::EOpUnpackUint4x16:
7298     case glslang::EOpPackFloat2x16:
7299     case glslang::EOpUnpackFloat2x16:
7300         unaryOp = spv::OpBitcast;
7301         break;
7302 
7303     case glslang::EOpDPdx:
7304         unaryOp = spv::OpDPdx;
7305         break;
7306     case glslang::EOpDPdy:
7307         unaryOp = spv::OpDPdy;
7308         break;
7309     case glslang::EOpFwidth:
7310         unaryOp = spv::OpFwidth;
7311         break;
7312 
7313     case glslang::EOpAny:
7314         unaryOp = spv::OpAny;
7315         break;
7316     case glslang::EOpAll:
7317         unaryOp = spv::OpAll;
7318         break;
7319 
7320     case glslang::EOpAbs:
7321         if (isFloat)
7322             libCall = spv::GLSLstd450FAbs;
7323         else
7324             libCall = spv::GLSLstd450SAbs;
7325         break;
7326     case glslang::EOpSign:
7327         if (isFloat)
7328             libCall = spv::GLSLstd450FSign;
7329         else
7330             libCall = spv::GLSLstd450SSign;
7331         break;
7332 
7333     case glslang::EOpDPdxFine:
7334         unaryOp = spv::OpDPdxFine;
7335         break;
7336     case glslang::EOpDPdyFine:
7337         unaryOp = spv::OpDPdyFine;
7338         break;
7339     case glslang::EOpFwidthFine:
7340         unaryOp = spv::OpFwidthFine;
7341         break;
7342     case glslang::EOpDPdxCoarse:
7343         unaryOp = spv::OpDPdxCoarse;
7344         break;
7345     case glslang::EOpDPdyCoarse:
7346         unaryOp = spv::OpDPdyCoarse;
7347         break;
7348     case glslang::EOpFwidthCoarse:
7349         unaryOp = spv::OpFwidthCoarse;
7350         break;
7351     case glslang::EOpRayQueryProceed:
7352         unaryOp = spv::OpRayQueryProceedKHR;
7353         break;
7354     case glslang::EOpRayQueryGetRayTMin:
7355         unaryOp = spv::OpRayQueryGetRayTMinKHR;
7356         break;
7357     case glslang::EOpRayQueryGetRayFlags:
7358         unaryOp = spv::OpRayQueryGetRayFlagsKHR;
7359         break;
7360     case glslang::EOpRayQueryGetWorldRayOrigin:
7361         unaryOp = spv::OpRayQueryGetWorldRayOriginKHR;
7362         break;
7363     case glslang::EOpRayQueryGetWorldRayDirection:
7364         unaryOp = spv::OpRayQueryGetWorldRayDirectionKHR;
7365         break;
7366     case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
7367         unaryOp = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;
7368         break;
7369     case glslang::EOpInterpolateAtCentroid:
7370         if (typeProxy == glslang::EbtFloat16)
7371             builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
7372         libCall = spv::GLSLstd450InterpolateAtCentroid;
7373         break;
7374     case glslang::EOpAtomicCounterIncrement:
7375     case glslang::EOpAtomicCounterDecrement:
7376     case glslang::EOpAtomicCounter:
7377     {
7378         // Handle all of the atomics in one place, in createAtomicOperation()
7379         std::vector<spv::Id> operands;
7380         operands.push_back(operand);
7381         return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags, opType);
7382     }
7383 
7384     case glslang::EOpBitFieldReverse:
7385         unaryOp = spv::OpBitReverse;
7386         break;
7387     case glslang::EOpBitCount:
7388         unaryOp = spv::OpBitCount;
7389         break;
7390     case glslang::EOpFindLSB:
7391         libCall = spv::GLSLstd450FindILsb;
7392         break;
7393     case glslang::EOpFindMSB:
7394         if (isUnsigned)
7395             libCall = spv::GLSLstd450FindUMsb;
7396         else
7397             libCall = spv::GLSLstd450FindSMsb;
7398         break;
7399 
7400     case glslang::EOpCountLeadingZeros:
7401         builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);
7402         builder.addExtension("SPV_INTEL_shader_integer_functions2");
7403         unaryOp = spv::OpUCountLeadingZerosINTEL;
7404         break;
7405 
7406     case glslang::EOpCountTrailingZeros:
7407         builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);
7408         builder.addExtension("SPV_INTEL_shader_integer_functions2");
7409         unaryOp = spv::OpUCountTrailingZerosINTEL;
7410         break;
7411 
7412     case glslang::EOpBallot:
7413     case glslang::EOpReadFirstInvocation:
7414     case glslang::EOpAnyInvocation:
7415     case glslang::EOpAllInvocations:
7416     case glslang::EOpAllInvocationsEqual:
7417     case glslang::EOpMinInvocations:
7418     case glslang::EOpMaxInvocations:
7419     case glslang::EOpAddInvocations:
7420     case glslang::EOpMinInvocationsNonUniform:
7421     case glslang::EOpMaxInvocationsNonUniform:
7422     case glslang::EOpAddInvocationsNonUniform:
7423     case glslang::EOpMinInvocationsInclusiveScan:
7424     case glslang::EOpMaxInvocationsInclusiveScan:
7425     case glslang::EOpAddInvocationsInclusiveScan:
7426     case glslang::EOpMinInvocationsInclusiveScanNonUniform:
7427     case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
7428     case glslang::EOpAddInvocationsInclusiveScanNonUniform:
7429     case glslang::EOpMinInvocationsExclusiveScan:
7430     case glslang::EOpMaxInvocationsExclusiveScan:
7431     case glslang::EOpAddInvocationsExclusiveScan:
7432     case glslang::EOpMinInvocationsExclusiveScanNonUniform:
7433     case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
7434     case glslang::EOpAddInvocationsExclusiveScanNonUniform:
7435     {
7436         std::vector<spv::Id> operands;
7437         operands.push_back(operand);
7438         return createInvocationsOperation(op, typeId, operands, typeProxy);
7439     }
7440     case glslang::EOpSubgroupAll:
7441     case glslang::EOpSubgroupAny:
7442     case glslang::EOpSubgroupAllEqual:
7443     case glslang::EOpSubgroupBroadcastFirst:
7444     case glslang::EOpSubgroupBallot:
7445     case glslang::EOpSubgroupInverseBallot:
7446     case glslang::EOpSubgroupBallotBitCount:
7447     case glslang::EOpSubgroupBallotInclusiveBitCount:
7448     case glslang::EOpSubgroupBallotExclusiveBitCount:
7449     case glslang::EOpSubgroupBallotFindLSB:
7450     case glslang::EOpSubgroupBallotFindMSB:
7451     case glslang::EOpSubgroupAdd:
7452     case glslang::EOpSubgroupMul:
7453     case glslang::EOpSubgroupMin:
7454     case glslang::EOpSubgroupMax:
7455     case glslang::EOpSubgroupAnd:
7456     case glslang::EOpSubgroupOr:
7457     case glslang::EOpSubgroupXor:
7458     case glslang::EOpSubgroupInclusiveAdd:
7459     case glslang::EOpSubgroupInclusiveMul:
7460     case glslang::EOpSubgroupInclusiveMin:
7461     case glslang::EOpSubgroupInclusiveMax:
7462     case glslang::EOpSubgroupInclusiveAnd:
7463     case glslang::EOpSubgroupInclusiveOr:
7464     case glslang::EOpSubgroupInclusiveXor:
7465     case glslang::EOpSubgroupExclusiveAdd:
7466     case glslang::EOpSubgroupExclusiveMul:
7467     case glslang::EOpSubgroupExclusiveMin:
7468     case glslang::EOpSubgroupExclusiveMax:
7469     case glslang::EOpSubgroupExclusiveAnd:
7470     case glslang::EOpSubgroupExclusiveOr:
7471     case glslang::EOpSubgroupExclusiveXor:
7472     case glslang::EOpSubgroupQuadSwapHorizontal:
7473     case glslang::EOpSubgroupQuadSwapVertical:
7474     case glslang::EOpSubgroupQuadSwapDiagonal:
7475     case glslang::EOpSubgroupQuadAll:
7476     case glslang::EOpSubgroupQuadAny: {
7477         std::vector<spv::Id> operands;
7478         operands.push_back(operand);
7479         return createSubgroupOperation(op, typeId, operands, typeProxy);
7480     }
7481     case glslang::EOpMbcnt:
7482         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
7483         libCall = spv::MbcntAMD;
7484         break;
7485 
7486     case glslang::EOpCubeFaceIndex:
7487         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
7488         libCall = spv::CubeFaceIndexAMD;
7489         break;
7490 
7491     case glslang::EOpCubeFaceCoord:
7492         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
7493         libCall = spv::CubeFaceCoordAMD;
7494         break;
7495     case glslang::EOpSubgroupPartition:
7496         unaryOp = spv::OpGroupNonUniformPartitionNV;
7497         break;
7498     case glslang::EOpConstructReference:
7499         unaryOp = spv::OpBitcast;
7500         break;
7501 
7502     case glslang::EOpConvUint64ToAccStruct:
7503     case glslang::EOpConvUvec2ToAccStruct:
7504         unaryOp = spv::OpConvertUToAccelerationStructureKHR;
7505         break;
7506 
7507     case glslang::EOpHitObjectIsEmptyNV:
7508         unaryOp = spv::OpHitObjectIsEmptyNV;
7509         break;
7510 
7511     case glslang::EOpHitObjectIsMissNV:
7512         unaryOp = spv::OpHitObjectIsMissNV;
7513         break;
7514 
7515     case glslang::EOpHitObjectIsHitNV:
7516         unaryOp = spv::OpHitObjectIsHitNV;
7517         break;
7518 
7519     case glslang::EOpHitObjectGetObjectRayOriginNV:
7520         unaryOp = spv::OpHitObjectGetObjectRayOriginNV;
7521         break;
7522 
7523     case glslang::EOpHitObjectGetObjectRayDirectionNV:
7524         unaryOp = spv::OpHitObjectGetObjectRayDirectionNV;
7525         break;
7526 
7527     case glslang::EOpHitObjectGetWorldRayOriginNV:
7528         unaryOp = spv::OpHitObjectGetWorldRayOriginNV;
7529         break;
7530 
7531     case glslang::EOpHitObjectGetWorldRayDirectionNV:
7532         unaryOp = spv::OpHitObjectGetWorldRayDirectionNV;
7533         break;
7534 
7535     case glslang::EOpHitObjectGetObjectToWorldNV:
7536         unaryOp = spv::OpHitObjectGetObjectToWorldNV;
7537         break;
7538 
7539     case glslang::EOpHitObjectGetWorldToObjectNV:
7540         unaryOp = spv::OpHitObjectGetWorldToObjectNV;
7541         break;
7542 
7543     case glslang::EOpHitObjectGetRayTMinNV:
7544         unaryOp = spv::OpHitObjectGetRayTMinNV;
7545         break;
7546 
7547     case glslang::EOpHitObjectGetRayTMaxNV:
7548         unaryOp = spv::OpHitObjectGetRayTMaxNV;
7549         break;
7550 
7551     case glslang::EOpHitObjectGetPrimitiveIndexNV:
7552         unaryOp = spv::OpHitObjectGetPrimitiveIndexNV;
7553         break;
7554 
7555     case glslang::EOpHitObjectGetInstanceIdNV:
7556         unaryOp = spv::OpHitObjectGetInstanceIdNV;
7557         break;
7558 
7559     case glslang::EOpHitObjectGetInstanceCustomIndexNV:
7560         unaryOp = spv::OpHitObjectGetInstanceCustomIndexNV;
7561         break;
7562 
7563     case glslang::EOpHitObjectGetGeometryIndexNV:
7564         unaryOp = spv::OpHitObjectGetGeometryIndexNV;
7565         break;
7566 
7567     case glslang::EOpHitObjectGetHitKindNV:
7568         unaryOp = spv::OpHitObjectGetHitKindNV;
7569         break;
7570 
7571     case glslang::EOpHitObjectGetCurrentTimeNV:
7572         unaryOp = spv::OpHitObjectGetCurrentTimeNV;
7573         break;
7574 
7575     case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
7576         unaryOp = spv::OpHitObjectGetShaderBindingTableRecordIndexNV;
7577         break;
7578 
7579     case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
7580         unaryOp = spv::OpHitObjectGetShaderRecordBufferHandleNV;
7581         break;
7582 
7583     case glslang::EOpFetchMicroTriangleVertexPositionNV:
7584         unaryOp = spv::OpFetchMicroTriangleVertexPositionNV;
7585         break;
7586 
7587     case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
7588         unaryOp = spv::OpFetchMicroTriangleVertexBarycentricNV;
7589         break;
7590 
7591     case glslang::EOpCopyObject:
7592         unaryOp = spv::OpCopyObject;
7593         break;
7594 
7595     case glslang::EOpDepthAttachmentReadEXT:
7596         builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
7597         builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);
7598         unaryOp = spv::OpDepthAttachmentReadEXT;
7599         decorations.precision = spv::NoPrecision;
7600         break;
7601     case glslang::EOpStencilAttachmentReadEXT:
7602         builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
7603         builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);
7604         unaryOp = spv::OpStencilAttachmentReadEXT;
7605         decorations.precision = spv::DecorationRelaxedPrecision;
7606         break;
7607 
7608     default:
7609         return 0;
7610     }
7611 
7612     spv::Id id;
7613     if (libCall >= 0) {
7614         std::vector<spv::Id> args;
7615         args.push_back(operand);
7616         id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args);
7617     } else {
7618         id = builder.createUnaryOp(unaryOp, typeId, operand);
7619     }
7620 
7621     decorations.addNoContraction(builder, id);
7622     decorations.addNonUniform(builder, id);
7623     return builder.setPrecision(id, decorations.precision);
7624 }
7625 
7626 // Create a unary operation on a matrix
createUnaryMatrixOperation(spv::Op op,OpDecorations & decorations,spv::Id typeId,spv::Id operand,glslang::TBasicType)7627 spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
7628                                                            spv::Id operand, glslang::TBasicType /* typeProxy */)
7629 {
7630     // Handle unary operations vector by vector.
7631     // The result type is the same type as the original type.
7632     // The algorithm is to:
7633     //   - break the matrix into vectors
7634     //   - apply the operation to each vector
7635     //   - make a matrix out the vector results
7636 
7637     // get the types sorted out
7638     int numCols = builder.getNumColumns(operand);
7639     int numRows = builder.getNumRows(operand);
7640     spv::Id srcVecType  = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows);
7641     spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows);
7642     std::vector<spv::Id> results;
7643 
7644     // do each vector op
7645     for (int c = 0; c < numCols; ++c) {
7646         std::vector<unsigned int> indexes;
7647         indexes.push_back(c);
7648         spv::Id srcVec  = builder.createCompositeExtract(operand, srcVecType, indexes);
7649         spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);
7650         decorations.addNoContraction(builder, destVec);
7651         decorations.addNonUniform(builder, destVec);
7652         results.push_back(builder.setPrecision(destVec, decorations.precision));
7653     }
7654 
7655     // put the pieces together
7656     spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
7657     decorations.addNonUniform(builder, result);
7658     return result;
7659 }
7660 
7661 // For converting integers where both the bitwidth and the signedness could
7662 // change, but only do the width change here. The caller is still responsible
7663 // for the signedness conversion.
7664 // destType is the final type that will be converted to, but this function
7665 // may only be doing part of that conversion.
createIntWidthConversion(spv::Id operand,int vectorSize,spv::Id destType,glslang::TBasicType resultBasicType,glslang::TBasicType operandBasicType)7666 spv::Id TGlslangToSpvTraverser::createIntWidthConversion(spv::Id operand, int vectorSize, spv::Id destType,
7667                                                          glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType)
7668 {
7669     // Get the result type width, based on the type to convert to.
7670     int width = GetNumBits(resultBasicType);
7671 
7672     // Get the conversion operation and result type,
7673     // based on the target width, but the source type.
7674     spv::Id type = spv::NoType;
7675     spv::Op convOp = spv::OpNop;
7676     if (isTypeSignedInt(operandBasicType)) {
7677         convOp = spv::OpSConvert;
7678         type = builder.makeIntType(width);
7679     } else {
7680         convOp = spv::OpUConvert;
7681         type = builder.makeUintType(width);
7682     }
7683 
7684     if (vectorSize > 0)
7685         type = builder.makeVectorType(type, vectorSize);
7686     else if (builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixKHR ||
7687              builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixNV) {
7688 
7689         type = builder.makeCooperativeMatrixTypeWithSameShape(type, destType);
7690     }
7691 
7692     return builder.createUnaryOp(convOp, type, operand);
7693 }
7694 
createConversion(glslang::TOperator op,OpDecorations & decorations,spv::Id destType,spv::Id operand,glslang::TBasicType resultBasicType,glslang::TBasicType operandBasicType)7695 spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecorations& decorations, spv::Id destType,
7696                                                  spv::Id operand, glslang::TBasicType resultBasicType, glslang::TBasicType operandBasicType)
7697 {
7698     spv::Op convOp = spv::OpNop;
7699     spv::Id zero = 0;
7700     spv::Id one = 0;
7701 
7702     int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
7703 
7704     if (IsOpNumericConv(op)) {
7705         if (isTypeSignedInt(operandBasicType) && isTypeFloat(resultBasicType)) {
7706             convOp = spv::OpConvertSToF;
7707         }
7708         if (isTypeUnsignedInt(operandBasicType) && isTypeFloat(resultBasicType)) {
7709             convOp = spv::OpConvertUToF;
7710         }
7711         if (isTypeFloat(operandBasicType) && isTypeSignedInt(resultBasicType)) {
7712             convOp = spv::OpConvertFToS;
7713         }
7714         if (isTypeFloat(operandBasicType) && isTypeUnsignedInt(resultBasicType)) {
7715             convOp = spv::OpConvertFToU;
7716         }
7717         if (isTypeSignedInt(operandBasicType) && isTypeSignedInt(resultBasicType)) {
7718             convOp = spv::OpSConvert;
7719         }
7720         if (isTypeUnsignedInt(operandBasicType) && isTypeUnsignedInt(resultBasicType)) {
7721             convOp = spv::OpUConvert;
7722         }
7723         if (isTypeFloat(operandBasicType) && isTypeFloat(resultBasicType)) {
7724             convOp = spv::OpFConvert;
7725             if (builder.isMatrixType(destType))
7726                 return createUnaryMatrixOperation(convOp, decorations, destType, operand, operandBasicType);
7727         }
7728         if (isTypeInt(operandBasicType) && isTypeInt(resultBasicType) &&
7729             isTypeUnsignedInt(operandBasicType) != isTypeUnsignedInt(resultBasicType)) {
7730 
7731             if (GetNumBits(operandBasicType) != GetNumBits(resultBasicType)) {
7732                 // OpSConvert/OpUConvert + OpBitCast
7733                 operand = createIntWidthConversion(operand, vectorSize, destType, resultBasicType, operandBasicType);
7734             }
7735 
7736             if (builder.isInSpecConstCodeGenMode()) {
7737                 uint32_t bits = GetNumBits(resultBasicType);
7738                 spv::Id zeroType = builder.makeUintType(bits);
7739                 if (bits == 64) {
7740                     zero = builder.makeInt64Constant(zeroType, 0, false);
7741                 } else {
7742                     zero = builder.makeIntConstant(zeroType, 0, false);
7743                 }
7744                 zero = makeSmearedConstant(zero, vectorSize);
7745                 // Use OpIAdd, instead of OpBitcast to do the conversion when
7746                 // generating for OpSpecConstantOp instruction.
7747                 return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
7748             }
7749             // For normal run-time conversion instruction, use OpBitcast.
7750             convOp = spv::OpBitcast;
7751         }
7752         if (resultBasicType == glslang::EbtBool) {
7753             uint32_t bits = GetNumBits(operandBasicType);
7754             if (isTypeInt(operandBasicType)) {
7755                 spv::Id zeroType = builder.makeUintType(bits);
7756                 if (bits == 64) {
7757                     zero = builder.makeInt64Constant(zeroType, 0, false);
7758                 } else {
7759                     zero = builder.makeIntConstant(zeroType, 0, false);
7760                 }
7761                 zero = makeSmearedConstant(zero, vectorSize);
7762                 return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
7763             } else {
7764                 assert(isTypeFloat(operandBasicType));
7765                 if (bits == 64) {
7766                     zero = builder.makeDoubleConstant(0.0);
7767                 } else if (bits == 32) {
7768                     zero = builder.makeFloatConstant(0.0);
7769                 } else {
7770                     assert(bits == 16);
7771                     zero = builder.makeFloat16Constant(0.0);
7772                 }
7773                 zero = makeSmearedConstant(zero, vectorSize);
7774                 return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);
7775             }
7776         }
7777         if (operandBasicType == glslang::EbtBool) {
7778             uint32_t bits = GetNumBits(resultBasicType);
7779             convOp = spv::OpSelect;
7780             if (isTypeInt(resultBasicType)) {
7781                 spv::Id zeroType = isTypeSignedInt(resultBasicType) ? builder.makeIntType(bits) : builder.makeUintType(bits);
7782                 if (bits == 64) {
7783                     zero = builder.makeInt64Constant(zeroType, 0, false);
7784                     one = builder.makeInt64Constant(zeroType, 1, false);
7785                 } else {
7786                     zero = builder.makeIntConstant(zeroType, 0, false);
7787                     one = builder.makeIntConstant(zeroType, 1, false);
7788                 }
7789             } else {
7790                 assert(isTypeFloat(resultBasicType));
7791                 if (bits == 64) {
7792                     zero = builder.makeDoubleConstant(0.0);
7793                     one = builder.makeDoubleConstant(1.0);
7794                 } else if (bits == 32) {
7795                     zero = builder.makeFloatConstant(0.0);
7796                     one = builder.makeFloatConstant(1.0);
7797                 } else {
7798                     assert(bits == 16);
7799                     zero = builder.makeFloat16Constant(0.0);
7800                     one = builder.makeFloat16Constant(1.0);
7801                 }
7802             }
7803         }
7804     }
7805 
7806     if (convOp == spv::OpNop) {
7807         switch (op) {
7808         case glslang::EOpConvUint64ToPtr:
7809             convOp = spv::OpConvertUToPtr;
7810             break;
7811         case glslang::EOpConvPtrToUint64:
7812             convOp = spv::OpConvertPtrToU;
7813             break;
7814         case glslang::EOpConvPtrToUvec2:
7815         case glslang::EOpConvUvec2ToPtr:
7816             convOp = spv::OpBitcast;
7817             break;
7818 
7819         default:
7820             break;
7821         }
7822     }
7823 
7824     spv::Id result = 0;
7825     if (convOp == spv::OpNop)
7826         return result;
7827 
7828     if (convOp == spv::OpSelect) {
7829         zero = makeSmearedConstant(zero, vectorSize);
7830         one  = makeSmearedConstant(one, vectorSize);
7831         result = builder.createTriOp(convOp, destType, operand, one, zero);
7832     } else
7833         result = builder.createUnaryOp(convOp, destType, operand);
7834 
7835     result = builder.setPrecision(result, decorations.precision);
7836     decorations.addNonUniform(builder, result);
7837     return result;
7838 }
7839 
makeSmearedConstant(spv::Id constant,int vectorSize)7840 spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
7841 {
7842     if (vectorSize == 0)
7843         return constant;
7844 
7845     spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
7846     std::vector<spv::Id> components;
7847     for (int c = 0; c < vectorSize; ++c)
7848         components.push_back(constant);
7849     return builder.makeCompositeConstant(vectorTypeId, components);
7850 }
7851 
7852 // For glslang ops that map to SPV atomic opCodes
createAtomicOperation(glslang::TOperator op,spv::Decoration,spv::Id typeId,std::vector<spv::Id> & operands,glslang::TBasicType typeProxy,const spv::Builder::AccessChain::CoherentFlags & lvalueCoherentFlags,const glslang::TType & opType)7853 spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/,
7854     spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
7855     const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, const glslang::TType &opType)
7856 {
7857     spv::Op opCode = spv::OpNop;
7858 
7859     switch (op) {
7860     case glslang::EOpAtomicAdd:
7861     case glslang::EOpImageAtomicAdd:
7862     case glslang::EOpAtomicCounterAdd:
7863         opCode = spv::OpAtomicIAdd;
7864         if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
7865             opCode = spv::OpAtomicFAddEXT;
7866             if (typeProxy == glslang::EbtFloat16 &&
7867                 (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7868                 builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7869                 builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7870             } else {
7871                 builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add);
7872                 if (typeProxy == glslang::EbtFloat16) {
7873                     builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add);
7874                     builder.addCapability(spv::CapabilityAtomicFloat16AddEXT);
7875                 } else if (typeProxy == glslang::EbtFloat) {
7876                     builder.addCapability(spv::CapabilityAtomicFloat32AddEXT);
7877                 } else {
7878                     builder.addCapability(spv::CapabilityAtomicFloat64AddEXT);
7879                 }
7880             }
7881         }
7882         break;
7883     case glslang::EOpAtomicSubtract:
7884     case glslang::EOpAtomicCounterSubtract:
7885         opCode = spv::OpAtomicISub;
7886         break;
7887     case glslang::EOpAtomicMin:
7888     case glslang::EOpImageAtomicMin:
7889     case glslang::EOpAtomicCounterMin:
7890         if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
7891             opCode = spv::OpAtomicFMinEXT;
7892             if (typeProxy == glslang::EbtFloat16 &&
7893                 (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7894                 builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7895                 builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7896             } else {
7897                 builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);
7898                 if (typeProxy == glslang::EbtFloat16)
7899                     builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT);
7900                 else if (typeProxy == glslang::EbtFloat)
7901                     builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT);
7902                 else
7903                     builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT);
7904             }
7905         } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {
7906             opCode = spv::OpAtomicUMin;
7907         } else {
7908             opCode = spv::OpAtomicSMin;
7909         }
7910         break;
7911     case glslang::EOpAtomicMax:
7912     case glslang::EOpImageAtomicMax:
7913     case glslang::EOpAtomicCounterMax:
7914         if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
7915             opCode = spv::OpAtomicFMaxEXT;
7916             if (typeProxy == glslang::EbtFloat16 &&
7917                 (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7918                 builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7919                 builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7920             } else {
7921                 builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);
7922                 if (typeProxy == glslang::EbtFloat16)
7923                     builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT);
7924                 else if (typeProxy == glslang::EbtFloat)
7925                     builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT);
7926                 else
7927                     builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT);
7928             }
7929         } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {
7930             opCode = spv::OpAtomicUMax;
7931         } else {
7932             opCode = spv::OpAtomicSMax;
7933         }
7934         break;
7935     case glslang::EOpAtomicAnd:
7936     case glslang::EOpImageAtomicAnd:
7937     case glslang::EOpAtomicCounterAnd:
7938         opCode = spv::OpAtomicAnd;
7939         break;
7940     case glslang::EOpAtomicOr:
7941     case glslang::EOpImageAtomicOr:
7942     case glslang::EOpAtomicCounterOr:
7943         opCode = spv::OpAtomicOr;
7944         break;
7945     case glslang::EOpAtomicXor:
7946     case glslang::EOpImageAtomicXor:
7947     case glslang::EOpAtomicCounterXor:
7948         opCode = spv::OpAtomicXor;
7949         break;
7950     case glslang::EOpAtomicExchange:
7951     case glslang::EOpImageAtomicExchange:
7952     case glslang::EOpAtomicCounterExchange:
7953         if ((typeProxy == glslang::EbtFloat16) &&
7954             (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7955                 builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7956                 builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7957         }
7958 
7959         opCode = spv::OpAtomicExchange;
7960         break;
7961     case glslang::EOpAtomicCompSwap:
7962     case glslang::EOpImageAtomicCompSwap:
7963     case glslang::EOpAtomicCounterCompSwap:
7964         opCode = spv::OpAtomicCompareExchange;
7965         break;
7966     case glslang::EOpAtomicCounterIncrement:
7967         opCode = spv::OpAtomicIIncrement;
7968         break;
7969     case glslang::EOpAtomicCounterDecrement:
7970         opCode = spv::OpAtomicIDecrement;
7971         break;
7972     case glslang::EOpAtomicCounter:
7973     case glslang::EOpImageAtomicLoad:
7974     case glslang::EOpAtomicLoad:
7975         opCode = spv::OpAtomicLoad;
7976         break;
7977     case glslang::EOpAtomicStore:
7978     case glslang::EOpImageAtomicStore:
7979         opCode = spv::OpAtomicStore;
7980         break;
7981     default:
7982         assert(0);
7983         break;
7984     }
7985 
7986     if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64)
7987         builder.addCapability(spv::CapabilityInt64Atomics);
7988 
7989     // Sort out the operands
7990     //  - mapping from glslang -> SPV
7991     //  - there are extra SPV operands that are optional in glslang
7992     //  - compare-exchange swaps the value and comparator
7993     //  - compare-exchange has an extra memory semantics
7994     //  - EOpAtomicCounterDecrement needs a post decrement
7995     spv::Id pointerId = 0, compareId = 0, valueId = 0;
7996     // scope defaults to Device in the old model, QueueFamilyKHR in the new model
7997     spv::Id scopeId;
7998     if (glslangIntermediate->usingVulkanMemoryModel()) {
7999         scopeId = builder.makeUintConstant(spv::ScopeQueueFamilyKHR);
8000     } else {
8001         scopeId = builder.makeUintConstant(spv::ScopeDevice);
8002     }
8003     // semantics default to relaxed
8004     spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() &&
8005         glslangIntermediate->usingVulkanMemoryModel() ?
8006                                                     spv::MemorySemanticsVolatileMask :
8007                                                     spv::MemorySemanticsMaskNone);
8008     spv::Id semanticsId2 = semanticsId;
8009 
8010     pointerId = operands[0];
8011     if (opCode == spv::OpAtomicIIncrement || opCode == spv::OpAtomicIDecrement) {
8012         // no additional operands
8013     } else if (opCode == spv::OpAtomicCompareExchange) {
8014         compareId = operands[1];
8015         valueId = operands[2];
8016         if (operands.size() > 3) {
8017             scopeId = operands[3];
8018             semanticsId = builder.makeUintConstant(
8019                 builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5]));
8020             semanticsId2 = builder.makeUintConstant(
8021                 builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7]));
8022         }
8023     } else if (opCode == spv::OpAtomicLoad) {
8024         if (operands.size() > 1) {
8025             scopeId = operands[1];
8026             semanticsId = builder.makeUintConstant(
8027                 builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));
8028         }
8029     } else {
8030         // atomic store or RMW
8031         valueId = operands[1];
8032         if (operands.size() > 2) {
8033             scopeId = operands[2];
8034             semanticsId = builder.makeUintConstant
8035                 (builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4]));
8036         }
8037     }
8038 
8039     // Check for capabilities
8040     unsigned semanticsImmediate = builder.getConstantScalar(semanticsId) | builder.getConstantScalar(semanticsId2);
8041     if (semanticsImmediate & (spv::MemorySemanticsMakeAvailableKHRMask |
8042                               spv::MemorySemanticsMakeVisibleKHRMask |
8043                               spv::MemorySemanticsOutputMemoryKHRMask |
8044                               spv::MemorySemanticsVolatileMask)) {
8045         builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8046     }
8047 
8048     if (builder.getConstantScalar(scopeId) == spv::ScopeQueueFamily) {
8049         builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8050     }
8051 
8052     if (glslangIntermediate->usingVulkanMemoryModel() && builder.getConstantScalar(scopeId) == spv::ScopeDevice) {
8053         builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
8054     }
8055 
8056     std::vector<spv::Id> spvAtomicOperands;  // hold the spv operands
8057     spvAtomicOperands.reserve(6);
8058     spvAtomicOperands.push_back(pointerId);
8059     spvAtomicOperands.push_back(scopeId);
8060     spvAtomicOperands.push_back(semanticsId);
8061     if (opCode == spv::OpAtomicCompareExchange) {
8062         spvAtomicOperands.push_back(semanticsId2);
8063         spvAtomicOperands.push_back(valueId);
8064         spvAtomicOperands.push_back(compareId);
8065     } else if (opCode != spv::OpAtomicLoad && opCode != spv::OpAtomicIIncrement && opCode != spv::OpAtomicIDecrement) {
8066         spvAtomicOperands.push_back(valueId);
8067     }
8068 
8069     if (opCode == spv::OpAtomicStore) {
8070         builder.createNoResultOp(opCode, spvAtomicOperands);
8071         return 0;
8072     } else {
8073         spv::Id resultId = builder.createOp(opCode, typeId, spvAtomicOperands);
8074 
8075         // GLSL and HLSL atomic-counter decrement return post-decrement value,
8076         // while SPIR-V returns pre-decrement value. Translate between these semantics.
8077         if (op == glslang::EOpAtomicCounterDecrement)
8078             resultId = builder.createBinOp(spv::OpISub, typeId, resultId, builder.makeIntConstant(1));
8079 
8080         return resultId;
8081     }
8082 }
8083 
8084 // Create group invocation operations.
createInvocationsOperation(glslang::TOperator op,spv::Id typeId,std::vector<spv::Id> & operands,glslang::TBasicType typeProxy)8085 spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId,
8086     std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8087 {
8088     bool isUnsigned = isTypeUnsignedInt(typeProxy);
8089     bool isFloat = isTypeFloat(typeProxy);
8090 
8091     spv::Op opCode = spv::OpNop;
8092     std::vector<spv::IdImmediate> spvGroupOperands;
8093     spv::GroupOperation groupOperation = spv::GroupOperationMax;
8094 
8095     if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation ||
8096         op == glslang::EOpReadInvocation) {
8097         builder.addExtension(spv::E_SPV_KHR_shader_ballot);
8098         builder.addCapability(spv::CapabilitySubgroupBallotKHR);
8099     } else if (op == glslang::EOpAnyInvocation ||
8100         op == glslang::EOpAllInvocations ||
8101         op == glslang::EOpAllInvocationsEqual) {
8102         builder.addExtension(spv::E_SPV_KHR_subgroup_vote);
8103         builder.addCapability(spv::CapabilitySubgroupVoteKHR);
8104     } else {
8105         builder.addCapability(spv::CapabilityGroups);
8106         if (op == glslang::EOpMinInvocationsNonUniform ||
8107             op == glslang::EOpMaxInvocationsNonUniform ||
8108             op == glslang::EOpAddInvocationsNonUniform ||
8109             op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
8110             op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
8111             op == glslang::EOpAddInvocationsInclusiveScanNonUniform ||
8112             op == glslang::EOpMinInvocationsExclusiveScanNonUniform ||
8113             op == glslang::EOpMaxInvocationsExclusiveScanNonUniform ||
8114             op == glslang::EOpAddInvocationsExclusiveScanNonUniform)
8115             builder.addExtension(spv::E_SPV_AMD_shader_ballot);
8116 
8117         switch (op) {
8118         case glslang::EOpMinInvocations:
8119         case glslang::EOpMaxInvocations:
8120         case glslang::EOpAddInvocations:
8121         case glslang::EOpMinInvocationsNonUniform:
8122         case glslang::EOpMaxInvocationsNonUniform:
8123         case glslang::EOpAddInvocationsNonUniform:
8124             groupOperation = spv::GroupOperationReduce;
8125             break;
8126         case glslang::EOpMinInvocationsInclusiveScan:
8127         case glslang::EOpMaxInvocationsInclusiveScan:
8128         case glslang::EOpAddInvocationsInclusiveScan:
8129         case glslang::EOpMinInvocationsInclusiveScanNonUniform:
8130         case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
8131         case glslang::EOpAddInvocationsInclusiveScanNonUniform:
8132             groupOperation = spv::GroupOperationInclusiveScan;
8133             break;
8134         case glslang::EOpMinInvocationsExclusiveScan:
8135         case glslang::EOpMaxInvocationsExclusiveScan:
8136         case glslang::EOpAddInvocationsExclusiveScan:
8137         case glslang::EOpMinInvocationsExclusiveScanNonUniform:
8138         case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
8139         case glslang::EOpAddInvocationsExclusiveScanNonUniform:
8140             groupOperation = spv::GroupOperationExclusiveScan;
8141             break;
8142         default:
8143             break;
8144         }
8145         spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8146         spvGroupOperands.push_back(scope);
8147         if (groupOperation != spv::GroupOperationMax) {
8148             spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
8149             spvGroupOperands.push_back(groupOp);
8150         }
8151     }
8152 
8153     for (auto opIt = operands.begin(); opIt != operands.end(); ++opIt) {
8154         spv::IdImmediate op = { true, *opIt };
8155         spvGroupOperands.push_back(op);
8156     }
8157 
8158     switch (op) {
8159     case glslang::EOpAnyInvocation:
8160         opCode = spv::OpSubgroupAnyKHR;
8161         break;
8162     case glslang::EOpAllInvocations:
8163         opCode = spv::OpSubgroupAllKHR;
8164         break;
8165     case glslang::EOpAllInvocationsEqual:
8166         opCode = spv::OpSubgroupAllEqualKHR;
8167         break;
8168     case glslang::EOpReadInvocation:
8169         opCode = spv::OpSubgroupReadInvocationKHR;
8170         if (builder.isVectorType(typeId))
8171             return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8172         break;
8173     case glslang::EOpReadFirstInvocation:
8174         opCode = spv::OpSubgroupFirstInvocationKHR;
8175         if (builder.isVectorType(typeId))
8176             return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8177         break;
8178     case glslang::EOpBallot:
8179     {
8180         // NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32
8181         // bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in
8182         // a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow:
8183         //
8184         //     result = Bitcast(SubgroupBallotKHR(Predicate).xy)
8185         //
8186         spv::Id uintType  = builder.makeUintType(32);
8187         spv::Id uvec4Type = builder.makeVectorType(uintType, 4);
8188         spv::Id result = builder.createOp(spv::OpSubgroupBallotKHR, uvec4Type, spvGroupOperands);
8189 
8190         std::vector<spv::Id> components;
8191         components.push_back(builder.createCompositeExtract(result, uintType, 0));
8192         components.push_back(builder.createCompositeExtract(result, uintType, 1));
8193 
8194         spv::Id uvec2Type = builder.makeVectorType(uintType, 2);
8195         return builder.createUnaryOp(spv::OpBitcast, typeId,
8196                                      builder.createCompositeConstruct(uvec2Type, components));
8197     }
8198 
8199     case glslang::EOpMinInvocations:
8200     case glslang::EOpMaxInvocations:
8201     case glslang::EOpAddInvocations:
8202     case glslang::EOpMinInvocationsInclusiveScan:
8203     case glslang::EOpMaxInvocationsInclusiveScan:
8204     case glslang::EOpAddInvocationsInclusiveScan:
8205     case glslang::EOpMinInvocationsExclusiveScan:
8206     case glslang::EOpMaxInvocationsExclusiveScan:
8207     case glslang::EOpAddInvocationsExclusiveScan:
8208         if (op == glslang::EOpMinInvocations ||
8209             op == glslang::EOpMinInvocationsInclusiveScan ||
8210             op == glslang::EOpMinInvocationsExclusiveScan) {
8211             if (isFloat)
8212                 opCode = spv::OpGroupFMin;
8213             else {
8214                 if (isUnsigned)
8215                     opCode = spv::OpGroupUMin;
8216                 else
8217                     opCode = spv::OpGroupSMin;
8218             }
8219         } else if (op == glslang::EOpMaxInvocations ||
8220                    op == glslang::EOpMaxInvocationsInclusiveScan ||
8221                    op == glslang::EOpMaxInvocationsExclusiveScan) {
8222             if (isFloat)
8223                 opCode = spv::OpGroupFMax;
8224             else {
8225                 if (isUnsigned)
8226                     opCode = spv::OpGroupUMax;
8227                 else
8228                     opCode = spv::OpGroupSMax;
8229             }
8230         } else {
8231             if (isFloat)
8232                 opCode = spv::OpGroupFAdd;
8233             else
8234                 opCode = spv::OpGroupIAdd;
8235         }
8236 
8237         if (builder.isVectorType(typeId))
8238             return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8239 
8240         break;
8241     case glslang::EOpMinInvocationsNonUniform:
8242     case glslang::EOpMaxInvocationsNonUniform:
8243     case glslang::EOpAddInvocationsNonUniform:
8244     case glslang::EOpMinInvocationsInclusiveScanNonUniform:
8245     case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
8246     case glslang::EOpAddInvocationsInclusiveScanNonUniform:
8247     case glslang::EOpMinInvocationsExclusiveScanNonUniform:
8248     case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
8249     case glslang::EOpAddInvocationsExclusiveScanNonUniform:
8250         if (op == glslang::EOpMinInvocationsNonUniform ||
8251             op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
8252             op == glslang::EOpMinInvocationsExclusiveScanNonUniform) {
8253             if (isFloat)
8254                 opCode = spv::OpGroupFMinNonUniformAMD;
8255             else {
8256                 if (isUnsigned)
8257                     opCode = spv::OpGroupUMinNonUniformAMD;
8258                 else
8259                     opCode = spv::OpGroupSMinNonUniformAMD;
8260             }
8261         }
8262         else if (op == glslang::EOpMaxInvocationsNonUniform ||
8263                  op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
8264                  op == glslang::EOpMaxInvocationsExclusiveScanNonUniform) {
8265             if (isFloat)
8266                 opCode = spv::OpGroupFMaxNonUniformAMD;
8267             else {
8268                 if (isUnsigned)
8269                     opCode = spv::OpGroupUMaxNonUniformAMD;
8270                 else
8271                     opCode = spv::OpGroupSMaxNonUniformAMD;
8272             }
8273         }
8274         else {
8275             if (isFloat)
8276                 opCode = spv::OpGroupFAddNonUniformAMD;
8277             else
8278                 opCode = spv::OpGroupIAddNonUniformAMD;
8279         }
8280 
8281         if (builder.isVectorType(typeId))
8282             return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8283 
8284         break;
8285     default:
8286         logger->missingFunctionality("invocation operation");
8287         return spv::NoResult;
8288     }
8289 
8290     assert(opCode != spv::OpNop);
8291     return builder.createOp(opCode, typeId, spvGroupOperands);
8292 }
8293 
8294 // Create group invocation operations on a vector
CreateInvocationsVectorOperation(spv::Op op,spv::GroupOperation groupOperation,spv::Id typeId,std::vector<spv::Id> & operands)8295 spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
8296     spv::Id typeId, std::vector<spv::Id>& operands)
8297 {
8298     assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin ||
8299            op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||
8300            op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||
8301            op == spv::OpSubgroupReadInvocationKHR || op == spv::OpSubgroupFirstInvocationKHR ||
8302            op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD ||
8303            op == spv::OpGroupSMinNonUniformAMD ||
8304            op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD ||
8305            op == spv::OpGroupSMaxNonUniformAMD ||
8306            op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD);
8307 
8308     // Handle group invocation operations scalar by scalar.
8309     // The result type is the same type as the original type.
8310     // The algorithm is to:
8311     //   - break the vector into scalars
8312     //   - apply the operation to each scalar
8313     //   - make a vector out the scalar results
8314 
8315     // get the types sorted out
8316     int numComponents = builder.getNumComponents(operands[0]);
8317     spv::Id scalarType = builder.getScalarTypeId(builder.getTypeId(operands[0]));
8318     std::vector<spv::Id> results;
8319 
8320     // do each scalar op
8321     for (int comp = 0; comp < numComponents; ++comp) {
8322         std::vector<unsigned int> indexes;
8323         indexes.push_back(comp);
8324         spv::IdImmediate scalar = { true, builder.createCompositeExtract(operands[0], scalarType, indexes) };
8325         std::vector<spv::IdImmediate> spvGroupOperands;
8326         if (op == spv::OpSubgroupReadInvocationKHR) {
8327             spvGroupOperands.push_back(scalar);
8328             spv::IdImmediate operand = { true, operands[1] };
8329             spvGroupOperands.push_back(operand);
8330         } else if (op == spv::OpSubgroupFirstInvocationKHR) {
8331             spvGroupOperands.push_back(scalar);
8332         } else if (op == spv::OpGroupBroadcast) {
8333             spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8334             spvGroupOperands.push_back(scope);
8335             spvGroupOperands.push_back(scalar);
8336             spv::IdImmediate operand = { true, operands[1] };
8337             spvGroupOperands.push_back(operand);
8338         } else {
8339             spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8340             spvGroupOperands.push_back(scope);
8341             spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
8342             spvGroupOperands.push_back(groupOp);
8343             spvGroupOperands.push_back(scalar);
8344         }
8345 
8346         results.push_back(builder.createOp(op, scalarType, spvGroupOperands));
8347     }
8348 
8349     // put the pieces together
8350     return builder.createCompositeConstruct(typeId, results);
8351 }
8352 
8353 // Create subgroup invocation operations.
createSubgroupOperation(glslang::TOperator op,spv::Id typeId,std::vector<spv::Id> & operands,glslang::TBasicType typeProxy)8354 spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, spv::Id typeId,
8355     std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8356 {
8357     // Add the required capabilities.
8358     switch (op) {
8359     case glslang::EOpSubgroupElect:
8360         builder.addCapability(spv::CapabilityGroupNonUniform);
8361         break;
8362     case glslang::EOpSubgroupQuadAll:
8363     case glslang::EOpSubgroupQuadAny:
8364         builder.addExtension(spv::E_SPV_KHR_quad_control);
8365         builder.addCapability(spv::CapabilityQuadControlKHR);
8366         [[fallthrough]];
8367     case glslang::EOpSubgroupAll:
8368     case glslang::EOpSubgroupAny:
8369     case glslang::EOpSubgroupAllEqual:
8370         builder.addCapability(spv::CapabilityGroupNonUniform);
8371         builder.addCapability(spv::CapabilityGroupNonUniformVote);
8372         break;
8373     case glslang::EOpSubgroupBroadcast:
8374     case glslang::EOpSubgroupBroadcastFirst:
8375     case glslang::EOpSubgroupBallot:
8376     case glslang::EOpSubgroupInverseBallot:
8377     case glslang::EOpSubgroupBallotBitExtract:
8378     case glslang::EOpSubgroupBallotBitCount:
8379     case glslang::EOpSubgroupBallotInclusiveBitCount:
8380     case glslang::EOpSubgroupBallotExclusiveBitCount:
8381     case glslang::EOpSubgroupBallotFindLSB:
8382     case glslang::EOpSubgroupBallotFindMSB:
8383         builder.addCapability(spv::CapabilityGroupNonUniform);
8384         builder.addCapability(spv::CapabilityGroupNonUniformBallot);
8385         break;
8386     case glslang::EOpSubgroupRotate:
8387     case glslang::EOpSubgroupClusteredRotate:
8388         builder.addExtension(spv::E_SPV_KHR_subgroup_rotate);
8389         builder.addCapability(spv::CapabilityGroupNonUniformRotateKHR);
8390         break;
8391     case glslang::EOpSubgroupShuffle:
8392     case glslang::EOpSubgroupShuffleXor:
8393         builder.addCapability(spv::CapabilityGroupNonUniform);
8394         builder.addCapability(spv::CapabilityGroupNonUniformShuffle);
8395         break;
8396     case glslang::EOpSubgroupShuffleUp:
8397     case glslang::EOpSubgroupShuffleDown:
8398         builder.addCapability(spv::CapabilityGroupNonUniform);
8399         builder.addCapability(spv::CapabilityGroupNonUniformShuffleRelative);
8400         break;
8401     case glslang::EOpSubgroupAdd:
8402     case glslang::EOpSubgroupMul:
8403     case glslang::EOpSubgroupMin:
8404     case glslang::EOpSubgroupMax:
8405     case glslang::EOpSubgroupAnd:
8406     case glslang::EOpSubgroupOr:
8407     case glslang::EOpSubgroupXor:
8408     case glslang::EOpSubgroupInclusiveAdd:
8409     case glslang::EOpSubgroupInclusiveMul:
8410     case glslang::EOpSubgroupInclusiveMin:
8411     case glslang::EOpSubgroupInclusiveMax:
8412     case glslang::EOpSubgroupInclusiveAnd:
8413     case glslang::EOpSubgroupInclusiveOr:
8414     case glslang::EOpSubgroupInclusiveXor:
8415     case glslang::EOpSubgroupExclusiveAdd:
8416     case glslang::EOpSubgroupExclusiveMul:
8417     case glslang::EOpSubgroupExclusiveMin:
8418     case glslang::EOpSubgroupExclusiveMax:
8419     case glslang::EOpSubgroupExclusiveAnd:
8420     case glslang::EOpSubgroupExclusiveOr:
8421     case glslang::EOpSubgroupExclusiveXor:
8422         builder.addCapability(spv::CapabilityGroupNonUniform);
8423         builder.addCapability(spv::CapabilityGroupNonUniformArithmetic);
8424         break;
8425     case glslang::EOpSubgroupClusteredAdd:
8426     case glslang::EOpSubgroupClusteredMul:
8427     case glslang::EOpSubgroupClusteredMin:
8428     case glslang::EOpSubgroupClusteredMax:
8429     case glslang::EOpSubgroupClusteredAnd:
8430     case glslang::EOpSubgroupClusteredOr:
8431     case glslang::EOpSubgroupClusteredXor:
8432         builder.addCapability(spv::CapabilityGroupNonUniform);
8433         builder.addCapability(spv::CapabilityGroupNonUniformClustered);
8434         break;
8435     case glslang::EOpSubgroupQuadBroadcast:
8436     case glslang::EOpSubgroupQuadSwapHorizontal:
8437     case glslang::EOpSubgroupQuadSwapVertical:
8438     case glslang::EOpSubgroupQuadSwapDiagonal:
8439         builder.addCapability(spv::CapabilityGroupNonUniform);
8440         builder.addCapability(spv::CapabilityGroupNonUniformQuad);
8441         break;
8442     case glslang::EOpSubgroupPartitionedAdd:
8443     case glslang::EOpSubgroupPartitionedMul:
8444     case glslang::EOpSubgroupPartitionedMin:
8445     case glslang::EOpSubgroupPartitionedMax:
8446     case glslang::EOpSubgroupPartitionedAnd:
8447     case glslang::EOpSubgroupPartitionedOr:
8448     case glslang::EOpSubgroupPartitionedXor:
8449     case glslang::EOpSubgroupPartitionedInclusiveAdd:
8450     case glslang::EOpSubgroupPartitionedInclusiveMul:
8451     case glslang::EOpSubgroupPartitionedInclusiveMin:
8452     case glslang::EOpSubgroupPartitionedInclusiveMax:
8453     case glslang::EOpSubgroupPartitionedInclusiveAnd:
8454     case glslang::EOpSubgroupPartitionedInclusiveOr:
8455     case glslang::EOpSubgroupPartitionedInclusiveXor:
8456     case glslang::EOpSubgroupPartitionedExclusiveAdd:
8457     case glslang::EOpSubgroupPartitionedExclusiveMul:
8458     case glslang::EOpSubgroupPartitionedExclusiveMin:
8459     case glslang::EOpSubgroupPartitionedExclusiveMax:
8460     case glslang::EOpSubgroupPartitionedExclusiveAnd:
8461     case glslang::EOpSubgroupPartitionedExclusiveOr:
8462     case glslang::EOpSubgroupPartitionedExclusiveXor:
8463         builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);
8464         builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV);
8465         break;
8466     default: assert(0 && "Unhandled subgroup operation!");
8467     }
8468 
8469 
8470     const bool isUnsigned = isTypeUnsignedInt(typeProxy);
8471     const bool isFloat = isTypeFloat(typeProxy);
8472     const bool isBool = typeProxy == glslang::EbtBool;
8473 
8474     spv::Op opCode = spv::OpNop;
8475 
8476     // Figure out which opcode to use.
8477     switch (op) {
8478     case glslang::EOpSubgroupElect:                   opCode = spv::OpGroupNonUniformElect; break;
8479     case glslang::EOpSubgroupQuadAll:                 opCode = spv::OpGroupNonUniformQuadAllKHR; break;
8480     case glslang::EOpSubgroupAll:                     opCode = spv::OpGroupNonUniformAll; break;
8481     case glslang::EOpSubgroupQuadAny:                 opCode = spv::OpGroupNonUniformQuadAnyKHR; break;
8482     case glslang::EOpSubgroupAny:                     opCode = spv::OpGroupNonUniformAny; break;
8483     case glslang::EOpSubgroupAllEqual:                opCode = spv::OpGroupNonUniformAllEqual; break;
8484     case glslang::EOpSubgroupBroadcast:               opCode = spv::OpGroupNonUniformBroadcast; break;
8485     case glslang::EOpSubgroupBroadcastFirst:          opCode = spv::OpGroupNonUniformBroadcastFirst; break;
8486     case glslang::EOpSubgroupBallot:                  opCode = spv::OpGroupNonUniformBallot; break;
8487     case glslang::EOpSubgroupInverseBallot:           opCode = spv::OpGroupNonUniformInverseBallot; break;
8488     case glslang::EOpSubgroupBallotBitExtract:        opCode = spv::OpGroupNonUniformBallotBitExtract; break;
8489     case glslang::EOpSubgroupBallotBitCount:
8490     case glslang::EOpSubgroupBallotInclusiveBitCount:
8491     case glslang::EOpSubgroupBallotExclusiveBitCount: opCode = spv::OpGroupNonUniformBallotBitCount; break;
8492     case glslang::EOpSubgroupBallotFindLSB:           opCode = spv::OpGroupNonUniformBallotFindLSB; break;
8493     case glslang::EOpSubgroupBallotFindMSB:           opCode = spv::OpGroupNonUniformBallotFindMSB; break;
8494     case glslang::EOpSubgroupShuffle:                 opCode = spv::OpGroupNonUniformShuffle; break;
8495     case glslang::EOpSubgroupShuffleXor:              opCode = spv::OpGroupNonUniformShuffleXor; break;
8496     case glslang::EOpSubgroupShuffleUp:               opCode = spv::OpGroupNonUniformShuffleUp; break;
8497     case glslang::EOpSubgroupShuffleDown:             opCode = spv::OpGroupNonUniformShuffleDown; break;
8498     case glslang::EOpSubgroupRotate:
8499     case glslang::EOpSubgroupClusteredRotate:         opCode = spv::OpGroupNonUniformRotateKHR; break;
8500     case glslang::EOpSubgroupAdd:
8501     case glslang::EOpSubgroupInclusiveAdd:
8502     case glslang::EOpSubgroupExclusiveAdd:
8503     case glslang::EOpSubgroupClusteredAdd:
8504     case glslang::EOpSubgroupPartitionedAdd:
8505     case glslang::EOpSubgroupPartitionedInclusiveAdd:
8506     case glslang::EOpSubgroupPartitionedExclusiveAdd:
8507         if (isFloat) {
8508             opCode = spv::OpGroupNonUniformFAdd;
8509         } else {
8510             opCode = spv::OpGroupNonUniformIAdd;
8511         }
8512         break;
8513     case glslang::EOpSubgroupMul:
8514     case glslang::EOpSubgroupInclusiveMul:
8515     case glslang::EOpSubgroupExclusiveMul:
8516     case glslang::EOpSubgroupClusteredMul:
8517     case glslang::EOpSubgroupPartitionedMul:
8518     case glslang::EOpSubgroupPartitionedInclusiveMul:
8519     case glslang::EOpSubgroupPartitionedExclusiveMul:
8520         if (isFloat) {
8521             opCode = spv::OpGroupNonUniformFMul;
8522         } else {
8523             opCode = spv::OpGroupNonUniformIMul;
8524         }
8525         break;
8526     case glslang::EOpSubgroupMin:
8527     case glslang::EOpSubgroupInclusiveMin:
8528     case glslang::EOpSubgroupExclusiveMin:
8529     case glslang::EOpSubgroupClusteredMin:
8530     case glslang::EOpSubgroupPartitionedMin:
8531     case glslang::EOpSubgroupPartitionedInclusiveMin:
8532     case glslang::EOpSubgroupPartitionedExclusiveMin:
8533         if (isFloat) {
8534             opCode = spv::OpGroupNonUniformFMin;
8535         } else if (isUnsigned) {
8536             opCode = spv::OpGroupNonUniformUMin;
8537         } else {
8538             opCode = spv::OpGroupNonUniformSMin;
8539         }
8540         break;
8541     case glslang::EOpSubgroupMax:
8542     case glslang::EOpSubgroupInclusiveMax:
8543     case glslang::EOpSubgroupExclusiveMax:
8544     case glslang::EOpSubgroupClusteredMax:
8545     case glslang::EOpSubgroupPartitionedMax:
8546     case glslang::EOpSubgroupPartitionedInclusiveMax:
8547     case glslang::EOpSubgroupPartitionedExclusiveMax:
8548         if (isFloat) {
8549             opCode = spv::OpGroupNonUniformFMax;
8550         } else if (isUnsigned) {
8551             opCode = spv::OpGroupNonUniformUMax;
8552         } else {
8553             opCode = spv::OpGroupNonUniformSMax;
8554         }
8555         break;
8556     case glslang::EOpSubgroupAnd:
8557     case glslang::EOpSubgroupInclusiveAnd:
8558     case glslang::EOpSubgroupExclusiveAnd:
8559     case glslang::EOpSubgroupClusteredAnd:
8560     case glslang::EOpSubgroupPartitionedAnd:
8561     case glslang::EOpSubgroupPartitionedInclusiveAnd:
8562     case glslang::EOpSubgroupPartitionedExclusiveAnd:
8563         if (isBool) {
8564             opCode = spv::OpGroupNonUniformLogicalAnd;
8565         } else {
8566             opCode = spv::OpGroupNonUniformBitwiseAnd;
8567         }
8568         break;
8569     case glslang::EOpSubgroupOr:
8570     case glslang::EOpSubgroupInclusiveOr:
8571     case glslang::EOpSubgroupExclusiveOr:
8572     case glslang::EOpSubgroupClusteredOr:
8573     case glslang::EOpSubgroupPartitionedOr:
8574     case glslang::EOpSubgroupPartitionedInclusiveOr:
8575     case glslang::EOpSubgroupPartitionedExclusiveOr:
8576         if (isBool) {
8577             opCode = spv::OpGroupNonUniformLogicalOr;
8578         } else {
8579             opCode = spv::OpGroupNonUniformBitwiseOr;
8580         }
8581         break;
8582     case glslang::EOpSubgroupXor:
8583     case glslang::EOpSubgroupInclusiveXor:
8584     case glslang::EOpSubgroupExclusiveXor:
8585     case glslang::EOpSubgroupClusteredXor:
8586     case glslang::EOpSubgroupPartitionedXor:
8587     case glslang::EOpSubgroupPartitionedInclusiveXor:
8588     case glslang::EOpSubgroupPartitionedExclusiveXor:
8589         if (isBool) {
8590             opCode = spv::OpGroupNonUniformLogicalXor;
8591         } else {
8592             opCode = spv::OpGroupNonUniformBitwiseXor;
8593         }
8594         break;
8595     case glslang::EOpSubgroupQuadBroadcast:      opCode = spv::OpGroupNonUniformQuadBroadcast; break;
8596     case glslang::EOpSubgroupQuadSwapHorizontal:
8597     case glslang::EOpSubgroupQuadSwapVertical:
8598     case glslang::EOpSubgroupQuadSwapDiagonal:   opCode = spv::OpGroupNonUniformQuadSwap; break;
8599     default: assert(0 && "Unhandled subgroup operation!");
8600     }
8601 
8602     // get the right Group Operation
8603     spv::GroupOperation groupOperation = spv::GroupOperationMax;
8604     switch (op) {
8605     default:
8606         break;
8607     case glslang::EOpSubgroupBallotBitCount:
8608     case glslang::EOpSubgroupAdd:
8609     case glslang::EOpSubgroupMul:
8610     case glslang::EOpSubgroupMin:
8611     case glslang::EOpSubgroupMax:
8612     case glslang::EOpSubgroupAnd:
8613     case glslang::EOpSubgroupOr:
8614     case glslang::EOpSubgroupXor:
8615         groupOperation = spv::GroupOperationReduce;
8616         break;
8617     case glslang::EOpSubgroupBallotInclusiveBitCount:
8618     case glslang::EOpSubgroupInclusiveAdd:
8619     case glslang::EOpSubgroupInclusiveMul:
8620     case glslang::EOpSubgroupInclusiveMin:
8621     case glslang::EOpSubgroupInclusiveMax:
8622     case glslang::EOpSubgroupInclusiveAnd:
8623     case glslang::EOpSubgroupInclusiveOr:
8624     case glslang::EOpSubgroupInclusiveXor:
8625         groupOperation = spv::GroupOperationInclusiveScan;
8626         break;
8627     case glslang::EOpSubgroupBallotExclusiveBitCount:
8628     case glslang::EOpSubgroupExclusiveAdd:
8629     case glslang::EOpSubgroupExclusiveMul:
8630     case glslang::EOpSubgroupExclusiveMin:
8631     case glslang::EOpSubgroupExclusiveMax:
8632     case glslang::EOpSubgroupExclusiveAnd:
8633     case glslang::EOpSubgroupExclusiveOr:
8634     case glslang::EOpSubgroupExclusiveXor:
8635         groupOperation = spv::GroupOperationExclusiveScan;
8636         break;
8637     case glslang::EOpSubgroupClusteredAdd:
8638     case glslang::EOpSubgroupClusteredMul:
8639     case glslang::EOpSubgroupClusteredMin:
8640     case glslang::EOpSubgroupClusteredMax:
8641     case glslang::EOpSubgroupClusteredAnd:
8642     case glslang::EOpSubgroupClusteredOr:
8643     case glslang::EOpSubgroupClusteredXor:
8644         groupOperation = spv::GroupOperationClusteredReduce;
8645         break;
8646     case glslang::EOpSubgroupPartitionedAdd:
8647     case glslang::EOpSubgroupPartitionedMul:
8648     case glslang::EOpSubgroupPartitionedMin:
8649     case glslang::EOpSubgroupPartitionedMax:
8650     case glslang::EOpSubgroupPartitionedAnd:
8651     case glslang::EOpSubgroupPartitionedOr:
8652     case glslang::EOpSubgroupPartitionedXor:
8653         groupOperation = spv::GroupOperationPartitionedReduceNV;
8654         break;
8655     case glslang::EOpSubgroupPartitionedInclusiveAdd:
8656     case glslang::EOpSubgroupPartitionedInclusiveMul:
8657     case glslang::EOpSubgroupPartitionedInclusiveMin:
8658     case glslang::EOpSubgroupPartitionedInclusiveMax:
8659     case glslang::EOpSubgroupPartitionedInclusiveAnd:
8660     case glslang::EOpSubgroupPartitionedInclusiveOr:
8661     case glslang::EOpSubgroupPartitionedInclusiveXor:
8662         groupOperation = spv::GroupOperationPartitionedInclusiveScanNV;
8663         break;
8664     case glslang::EOpSubgroupPartitionedExclusiveAdd:
8665     case glslang::EOpSubgroupPartitionedExclusiveMul:
8666     case glslang::EOpSubgroupPartitionedExclusiveMin:
8667     case glslang::EOpSubgroupPartitionedExclusiveMax:
8668     case glslang::EOpSubgroupPartitionedExclusiveAnd:
8669     case glslang::EOpSubgroupPartitionedExclusiveOr:
8670     case glslang::EOpSubgroupPartitionedExclusiveXor:
8671         groupOperation = spv::GroupOperationPartitionedExclusiveScanNV;
8672         break;
8673     }
8674 
8675     // build the instruction
8676     std::vector<spv::IdImmediate> spvGroupOperands;
8677 
8678     // Every operation begins with the Execution Scope operand.
8679     spv::IdImmediate executionScope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8680     // All other ops need the execution scope. Quad Control Ops don't need scope, it's always Quad.
8681     if (opCode != spv::OpGroupNonUniformQuadAllKHR && opCode != spv::OpGroupNonUniformQuadAnyKHR) {
8682         spvGroupOperands.push_back(executionScope);
8683     }
8684 
8685     // Next, for all operations that use a Group Operation, push that as an operand.
8686     if (groupOperation != spv::GroupOperationMax) {
8687         spv::IdImmediate groupOperand = { false, (unsigned)groupOperation };
8688         spvGroupOperands.push_back(groupOperand);
8689     }
8690 
8691     // Push back the operands next.
8692     for (auto opIt = operands.cbegin(); opIt != operands.cend(); ++opIt) {
8693         spv::IdImmediate operand = { true, *opIt };
8694         spvGroupOperands.push_back(operand);
8695     }
8696 
8697     // Some opcodes have additional operands.
8698     spv::Id directionId = spv::NoResult;
8699     switch (op) {
8700     default: break;
8701     case glslang::EOpSubgroupQuadSwapHorizontal: directionId = builder.makeUintConstant(0); break;
8702     case glslang::EOpSubgroupQuadSwapVertical:   directionId = builder.makeUintConstant(1); break;
8703     case glslang::EOpSubgroupQuadSwapDiagonal:   directionId = builder.makeUintConstant(2); break;
8704     }
8705     if (directionId != spv::NoResult) {
8706         spv::IdImmediate direction = { true, directionId };
8707         spvGroupOperands.push_back(direction);
8708     }
8709 
8710     return builder.createOp(opCode, typeId, spvGroupOperands);
8711 }
8712 
createMiscOperation(glslang::TOperator op,spv::Decoration precision,spv::Id typeId,std::vector<spv::Id> & operands,glslang::TBasicType typeProxy)8713 spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision,
8714     spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8715 {
8716     bool isUnsigned = isTypeUnsignedInt(typeProxy);
8717     bool isFloat = isTypeFloat(typeProxy);
8718 
8719     spv::Op opCode = spv::OpNop;
8720     int extBuiltins = -1;
8721     int libCall = -1;
8722     size_t consumedOperands = operands.size();
8723     spv::Id typeId0 = 0;
8724     if (consumedOperands > 0)
8725         typeId0 = builder.getTypeId(operands[0]);
8726     spv::Id typeId1 = 0;
8727     if (consumedOperands > 1)
8728         typeId1 = builder.getTypeId(operands[1]);
8729     spv::Id frexpIntType = 0;
8730 
8731     switch (op) {
8732     case glslang::EOpMin:
8733         if (isFloat)
8734             libCall = nanMinMaxClamp ? spv::GLSLstd450NMin : spv::GLSLstd450FMin;
8735         else if (isUnsigned)
8736             libCall = spv::GLSLstd450UMin;
8737         else
8738             libCall = spv::GLSLstd450SMin;
8739         builder.promoteScalar(precision, operands.front(), operands.back());
8740         break;
8741     case glslang::EOpModf:
8742         {
8743             libCall = spv::GLSLstd450ModfStruct;
8744             assert(builder.isFloatType(builder.getScalarTypeId(typeId0)));
8745             int width = builder.getScalarTypeWidth(typeId0);
8746             if (width == 16)
8747                 builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
8748             // The returned struct has two members of the same type as the first argument
8749             typeId = builder.makeStructResultType(typeId0, typeId0);
8750             consumedOperands = 1;
8751         }
8752         break;
8753     case glslang::EOpMax:
8754         if (isFloat)
8755             libCall = nanMinMaxClamp ? spv::GLSLstd450NMax : spv::GLSLstd450FMax;
8756         else if (isUnsigned)
8757             libCall = spv::GLSLstd450UMax;
8758         else
8759             libCall = spv::GLSLstd450SMax;
8760         builder.promoteScalar(precision, operands.front(), operands.back());
8761         break;
8762     case glslang::EOpPow:
8763         libCall = spv::GLSLstd450Pow;
8764         break;
8765     case glslang::EOpDot:
8766         opCode = spv::OpDot;
8767         break;
8768     case glslang::EOpAtan:
8769         libCall = spv::GLSLstd450Atan2;
8770         break;
8771 
8772     case glslang::EOpClamp:
8773         if (isFloat)
8774             libCall = nanMinMaxClamp ? spv::GLSLstd450NClamp : spv::GLSLstd450FClamp;
8775         else if (isUnsigned)
8776             libCall = spv::GLSLstd450UClamp;
8777         else
8778             libCall = spv::GLSLstd450SClamp;
8779         builder.promoteScalar(precision, operands.front(), operands[1]);
8780         builder.promoteScalar(precision, operands.front(), operands[2]);
8781         break;
8782     case glslang::EOpMix:
8783         if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
8784             assert(isFloat);
8785             libCall = spv::GLSLstd450FMix;
8786         } else {
8787             opCode = spv::OpSelect;
8788             std::swap(operands.front(), operands.back());
8789         }
8790         builder.promoteScalar(precision, operands.front(), operands.back());
8791         break;
8792     case glslang::EOpStep:
8793         libCall = spv::GLSLstd450Step;
8794         builder.promoteScalar(precision, operands.front(), operands.back());
8795         break;
8796     case glslang::EOpSmoothStep:
8797         libCall = spv::GLSLstd450SmoothStep;
8798         builder.promoteScalar(precision, operands[0], operands[2]);
8799         builder.promoteScalar(precision, operands[1], operands[2]);
8800         break;
8801 
8802     case glslang::EOpDistance:
8803         libCall = spv::GLSLstd450Distance;
8804         break;
8805     case glslang::EOpCross:
8806         libCall = spv::GLSLstd450Cross;
8807         break;
8808     case glslang::EOpFaceForward:
8809         libCall = spv::GLSLstd450FaceForward;
8810         break;
8811     case glslang::EOpReflect:
8812         libCall = spv::GLSLstd450Reflect;
8813         break;
8814     case glslang::EOpRefract:
8815         libCall = spv::GLSLstd450Refract;
8816         break;
8817     case glslang::EOpBarrier:
8818         {
8819             // This is for the extended controlBarrier function, with four operands.
8820             // The unextended barrier() goes through createNoArgOperation.
8821             assert(operands.size() == 4);
8822             unsigned int executionScope = builder.getConstantScalar(operands[0]);
8823             unsigned int memoryScope = builder.getConstantScalar(operands[1]);
8824             unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]);
8825             builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope,
8826                 (spv::MemorySemanticsMask)semantics);
8827             if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
8828                              spv::MemorySemanticsMakeVisibleKHRMask |
8829                              spv::MemorySemanticsOutputMemoryKHRMask |
8830                              spv::MemorySemanticsVolatileMask)) {
8831                 builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8832             }
8833             if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice ||
8834                 memoryScope == spv::ScopeDevice)) {
8835                 builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
8836             }
8837             return 0;
8838         }
8839         break;
8840     case glslang::EOpMemoryBarrier:
8841         {
8842             // This is for the extended memoryBarrier function, with three operands.
8843             // The unextended memoryBarrier() goes through createNoArgOperation.
8844             assert(operands.size() == 3);
8845             unsigned int memoryScope = builder.getConstantScalar(operands[0]);
8846             unsigned int semantics = builder.getConstantScalar(operands[1]) | builder.getConstantScalar(operands[2]);
8847             builder.createMemoryBarrier((spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics);
8848             if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
8849                              spv::MemorySemanticsMakeVisibleKHRMask |
8850                              spv::MemorySemanticsOutputMemoryKHRMask |
8851                              spv::MemorySemanticsVolatileMask)) {
8852                 builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8853             }
8854             if (glslangIntermediate->usingVulkanMemoryModel() && memoryScope == spv::ScopeDevice) {
8855                 builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
8856             }
8857             return 0;
8858         }
8859         break;
8860 
8861     case glslang::EOpInterpolateAtSample:
8862         if (typeProxy == glslang::EbtFloat16)
8863             builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
8864         libCall = spv::GLSLstd450InterpolateAtSample;
8865         break;
8866     case glslang::EOpInterpolateAtOffset:
8867         if (typeProxy == glslang::EbtFloat16)
8868             builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
8869         libCall = spv::GLSLstd450InterpolateAtOffset;
8870         break;
8871     case glslang::EOpAddCarry:
8872         opCode = spv::OpIAddCarry;
8873         typeId = builder.makeStructResultType(typeId0, typeId0);
8874         consumedOperands = 2;
8875         break;
8876     case glslang::EOpSubBorrow:
8877         opCode = spv::OpISubBorrow;
8878         typeId = builder.makeStructResultType(typeId0, typeId0);
8879         consumedOperands = 2;
8880         break;
8881     case glslang::EOpUMulExtended:
8882         opCode = spv::OpUMulExtended;
8883         typeId = builder.makeStructResultType(typeId0, typeId0);
8884         consumedOperands = 2;
8885         break;
8886     case glslang::EOpIMulExtended:
8887         opCode = spv::OpSMulExtended;
8888         typeId = builder.makeStructResultType(typeId0, typeId0);
8889         consumedOperands = 2;
8890         break;
8891     case glslang::EOpBitfieldExtract:
8892         if (isUnsigned)
8893             opCode = spv::OpBitFieldUExtract;
8894         else
8895             opCode = spv::OpBitFieldSExtract;
8896         break;
8897     case glslang::EOpBitfieldInsert:
8898         opCode = spv::OpBitFieldInsert;
8899         break;
8900 
8901     case glslang::EOpFma:
8902         libCall = spv::GLSLstd450Fma;
8903         break;
8904     case glslang::EOpFrexp:
8905         {
8906             libCall = spv::GLSLstd450FrexpStruct;
8907             assert(builder.isPointerType(typeId1));
8908             typeId1 = builder.getContainedTypeId(typeId1);
8909             int width = builder.getScalarTypeWidth(typeId1);
8910             if (width == 16)
8911                 // Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int16
8912                 builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
8913             if (builder.getNumComponents(operands[0]) == 1)
8914                 frexpIntType = builder.makeIntegerType(width, true);
8915             else
8916                 frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true),
8917                     builder.getNumComponents(operands[0]));
8918             typeId = builder.makeStructResultType(typeId0, frexpIntType);
8919             consumedOperands = 1;
8920         }
8921         break;
8922     case glslang::EOpLdexp:
8923         libCall = spv::GLSLstd450Ldexp;
8924         break;
8925 
8926     case glslang::EOpReadInvocation:
8927         return createInvocationsOperation(op, typeId, operands, typeProxy);
8928 
8929     case glslang::EOpSubgroupBroadcast:
8930     case glslang::EOpSubgroupBallotBitExtract:
8931     case glslang::EOpSubgroupShuffle:
8932     case glslang::EOpSubgroupShuffleXor:
8933     case glslang::EOpSubgroupShuffleUp:
8934     case glslang::EOpSubgroupShuffleDown:
8935     case glslang::EOpSubgroupRotate:
8936     case glslang::EOpSubgroupClusteredRotate:
8937     case glslang::EOpSubgroupClusteredAdd:
8938     case glslang::EOpSubgroupClusteredMul:
8939     case glslang::EOpSubgroupClusteredMin:
8940     case glslang::EOpSubgroupClusteredMax:
8941     case glslang::EOpSubgroupClusteredAnd:
8942     case glslang::EOpSubgroupClusteredOr:
8943     case glslang::EOpSubgroupClusteredXor:
8944     case glslang::EOpSubgroupQuadBroadcast:
8945     case glslang::EOpSubgroupPartitionedAdd:
8946     case glslang::EOpSubgroupPartitionedMul:
8947     case glslang::EOpSubgroupPartitionedMin:
8948     case glslang::EOpSubgroupPartitionedMax:
8949     case glslang::EOpSubgroupPartitionedAnd:
8950     case glslang::EOpSubgroupPartitionedOr:
8951     case glslang::EOpSubgroupPartitionedXor:
8952     case glslang::EOpSubgroupPartitionedInclusiveAdd:
8953     case glslang::EOpSubgroupPartitionedInclusiveMul:
8954     case glslang::EOpSubgroupPartitionedInclusiveMin:
8955     case glslang::EOpSubgroupPartitionedInclusiveMax:
8956     case glslang::EOpSubgroupPartitionedInclusiveAnd:
8957     case glslang::EOpSubgroupPartitionedInclusiveOr:
8958     case glslang::EOpSubgroupPartitionedInclusiveXor:
8959     case glslang::EOpSubgroupPartitionedExclusiveAdd:
8960     case glslang::EOpSubgroupPartitionedExclusiveMul:
8961     case glslang::EOpSubgroupPartitionedExclusiveMin:
8962     case glslang::EOpSubgroupPartitionedExclusiveMax:
8963     case glslang::EOpSubgroupPartitionedExclusiveAnd:
8964     case glslang::EOpSubgroupPartitionedExclusiveOr:
8965     case glslang::EOpSubgroupPartitionedExclusiveXor:
8966         return createSubgroupOperation(op, typeId, operands, typeProxy);
8967 
8968     case glslang::EOpSwizzleInvocations:
8969         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8970         libCall = spv::SwizzleInvocationsAMD;
8971         break;
8972     case glslang::EOpSwizzleInvocationsMasked:
8973         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8974         libCall = spv::SwizzleInvocationsMaskedAMD;
8975         break;
8976     case glslang::EOpWriteInvocation:
8977         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8978         libCall = spv::WriteInvocationAMD;
8979         break;
8980 
8981     case glslang::EOpMin3:
8982         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
8983         if (isFloat)
8984             libCall = spv::FMin3AMD;
8985         else {
8986             if (isUnsigned)
8987                 libCall = spv::UMin3AMD;
8988             else
8989                 libCall = spv::SMin3AMD;
8990         }
8991         break;
8992     case glslang::EOpMax3:
8993         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
8994         if (isFloat)
8995             libCall = spv::FMax3AMD;
8996         else {
8997             if (isUnsigned)
8998                 libCall = spv::UMax3AMD;
8999             else
9000                 libCall = spv::SMax3AMD;
9001         }
9002         break;
9003     case glslang::EOpMid3:
9004         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
9005         if (isFloat)
9006             libCall = spv::FMid3AMD;
9007         else {
9008             if (isUnsigned)
9009                 libCall = spv::UMid3AMD;
9010             else
9011                 libCall = spv::SMid3AMD;
9012         }
9013         break;
9014 
9015     case glslang::EOpInterpolateAtVertex:
9016         if (typeProxy == glslang::EbtFloat16)
9017             builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
9018         extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
9019         libCall = spv::InterpolateAtVertexAMD;
9020         break;
9021 
9022     case glslang::EOpReportIntersection:
9023         typeId = builder.makeBoolType();
9024         opCode = spv::OpReportIntersectionKHR;
9025         break;
9026     case glslang::EOpTraceNV:
9027         builder.createNoResultOp(spv::OpTraceNV, operands);
9028         return 0;
9029     case glslang::EOpTraceRayMotionNV:
9030         builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);
9031         builder.addCapability(spv::CapabilityRayTracingMotionBlurNV);
9032         builder.createNoResultOp(spv::OpTraceRayMotionNV, operands);
9033         return 0;
9034     case glslang::EOpTraceKHR:
9035         builder.createNoResultOp(spv::OpTraceRayKHR, operands);
9036         return 0;
9037     case glslang::EOpExecuteCallableNV:
9038         builder.createNoResultOp(spv::OpExecuteCallableNV, operands);
9039         return 0;
9040     case glslang::EOpExecuteCallableKHR:
9041         builder.createNoResultOp(spv::OpExecuteCallableKHR, operands);
9042         return 0;
9043 
9044     case glslang::EOpRayQueryInitialize:
9045         builder.createNoResultOp(spv::OpRayQueryInitializeKHR, operands);
9046         return 0;
9047     case glslang::EOpRayQueryTerminate:
9048         builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operands);
9049         return 0;
9050     case glslang::EOpRayQueryGenerateIntersection:
9051         builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR, operands);
9052         return 0;
9053     case glslang::EOpRayQueryConfirmIntersection:
9054         builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operands);
9055         return 0;
9056     case glslang::EOpRayQueryProceed:
9057         typeId = builder.makeBoolType();
9058         opCode = spv::OpRayQueryProceedKHR;
9059         break;
9060     case glslang::EOpRayQueryGetIntersectionType:
9061         typeId = builder.makeUintType(32);
9062         opCode = spv::OpRayQueryGetIntersectionTypeKHR;
9063         break;
9064     case glslang::EOpRayQueryGetRayTMin:
9065         typeId = builder.makeFloatType(32);
9066         opCode = spv::OpRayQueryGetRayTMinKHR;
9067         break;
9068     case glslang::EOpRayQueryGetRayFlags:
9069         typeId = builder.makeIntType(32);
9070         opCode = spv::OpRayQueryGetRayFlagsKHR;
9071         break;
9072     case glslang::EOpRayQueryGetIntersectionT:
9073         typeId = builder.makeFloatType(32);
9074         opCode = spv::OpRayQueryGetIntersectionTKHR;
9075         break;
9076     case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
9077         typeId = builder.makeIntType(32);
9078         opCode = spv::OpRayQueryGetIntersectionInstanceCustomIndexKHR;
9079         break;
9080     case glslang::EOpRayQueryGetIntersectionInstanceId:
9081         typeId = builder.makeIntType(32);
9082         opCode = spv::OpRayQueryGetIntersectionInstanceIdKHR;
9083         break;
9084     case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
9085         typeId = builder.makeUintType(32);
9086         opCode = spv::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR;
9087         break;
9088     case glslang::EOpRayQueryGetIntersectionGeometryIndex:
9089         typeId = builder.makeIntType(32);
9090         opCode = spv::OpRayQueryGetIntersectionGeometryIndexKHR;
9091         break;
9092     case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
9093         typeId = builder.makeIntType(32);
9094         opCode = spv::OpRayQueryGetIntersectionPrimitiveIndexKHR;
9095         break;
9096     case glslang::EOpRayQueryGetIntersectionBarycentrics:
9097         typeId = builder.makeVectorType(builder.makeFloatType(32), 2);
9098         opCode = spv::OpRayQueryGetIntersectionBarycentricsKHR;
9099         break;
9100     case glslang::EOpRayQueryGetIntersectionFrontFace:
9101         typeId = builder.makeBoolType();
9102         opCode = spv::OpRayQueryGetIntersectionFrontFaceKHR;
9103         break;
9104     case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
9105         typeId = builder.makeBoolType();
9106         opCode = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;
9107         break;
9108     case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
9109         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9110         opCode = spv::OpRayQueryGetIntersectionObjectRayDirectionKHR;
9111         break;
9112     case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
9113         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9114         opCode = spv::OpRayQueryGetIntersectionObjectRayOriginKHR;
9115         break;
9116     case glslang::EOpRayQueryGetWorldRayDirection:
9117         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9118         opCode = spv::OpRayQueryGetWorldRayDirectionKHR;
9119         break;
9120     case glslang::EOpRayQueryGetWorldRayOrigin:
9121         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9122         opCode = spv::OpRayQueryGetWorldRayOriginKHR;
9123         break;
9124     case glslang::EOpRayQueryGetIntersectionObjectToWorld:
9125         typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9126         opCode = spv::OpRayQueryGetIntersectionObjectToWorldKHR;
9127         break;
9128     case glslang::EOpRayQueryGetIntersectionWorldToObject:
9129         typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9130         opCode = spv::OpRayQueryGetIntersectionWorldToObjectKHR;
9131         break;
9132     case glslang::EOpWritePackedPrimitiveIndices4x8NV:
9133         builder.createNoResultOp(spv::OpWritePackedPrimitiveIndices4x8NV, operands);
9134         return 0;
9135     case glslang::EOpEmitMeshTasksEXT:
9136         if (taskPayloadID)
9137             operands.push_back(taskPayloadID);
9138         // As per SPV_EXT_mesh_shader make it a terminating instruction in the current block
9139         builder.makeStatementTerminator(spv::OpEmitMeshTasksEXT, operands, "post-OpEmitMeshTasksEXT");
9140         return 0;
9141     case glslang::EOpSetMeshOutputsEXT:
9142         builder.createNoResultOp(spv::OpSetMeshOutputsEXT, operands);
9143         return 0;
9144     case glslang::EOpCooperativeMatrixMulAddNV:
9145         opCode = spv::OpCooperativeMatrixMulAddNV;
9146         break;
9147     case glslang::EOpHitObjectTraceRayNV:
9148         builder.createNoResultOp(spv::OpHitObjectTraceRayNV, operands);
9149         return 0;
9150     case glslang::EOpHitObjectTraceRayMotionNV:
9151         builder.createNoResultOp(spv::OpHitObjectTraceRayMotionNV, operands);
9152         return 0;
9153     case glslang::EOpHitObjectRecordHitNV:
9154         builder.createNoResultOp(spv::OpHitObjectRecordHitNV, operands);
9155         return 0;
9156     case glslang::EOpHitObjectRecordHitMotionNV:
9157         builder.createNoResultOp(spv::OpHitObjectRecordHitMotionNV, operands);
9158         return 0;
9159     case glslang::EOpHitObjectRecordHitWithIndexNV:
9160         builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexNV, operands);
9161         return 0;
9162     case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
9163         builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexMotionNV, operands);
9164         return 0;
9165     case glslang::EOpHitObjectRecordMissNV:
9166         builder.createNoResultOp(spv::OpHitObjectRecordMissNV, operands);
9167         return 0;
9168     case glslang::EOpHitObjectRecordMissMotionNV:
9169         builder.createNoResultOp(spv::OpHitObjectRecordMissMotionNV, operands);
9170         return 0;
9171     case glslang::EOpHitObjectExecuteShaderNV:
9172         builder.createNoResultOp(spv::OpHitObjectExecuteShaderNV, operands);
9173         return 0;
9174     case glslang::EOpHitObjectIsEmptyNV:
9175         typeId = builder.makeBoolType();
9176         opCode = spv::OpHitObjectIsEmptyNV;
9177         break;
9178     case glslang::EOpHitObjectIsMissNV:
9179         typeId = builder.makeBoolType();
9180         opCode = spv::OpHitObjectIsMissNV;
9181         break;
9182     case glslang::EOpHitObjectIsHitNV:
9183         typeId = builder.makeBoolType();
9184         opCode = spv::OpHitObjectIsHitNV;
9185         break;
9186     case glslang::EOpHitObjectGetRayTMinNV:
9187         typeId = builder.makeFloatType(32);
9188         opCode = spv::OpHitObjectGetRayTMinNV;
9189         break;
9190     case glslang::EOpHitObjectGetRayTMaxNV:
9191         typeId = builder.makeFloatType(32);
9192         opCode = spv::OpHitObjectGetRayTMaxNV;
9193         break;
9194     case glslang::EOpHitObjectGetObjectRayOriginNV:
9195         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9196         opCode = spv::OpHitObjectGetObjectRayOriginNV;
9197         break;
9198     case glslang::EOpHitObjectGetObjectRayDirectionNV:
9199         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9200         opCode = spv::OpHitObjectGetObjectRayDirectionNV;
9201         break;
9202     case glslang::EOpHitObjectGetWorldRayOriginNV:
9203         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9204         opCode = spv::OpHitObjectGetWorldRayOriginNV;
9205         break;
9206     case glslang::EOpHitObjectGetWorldRayDirectionNV:
9207         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9208         opCode = spv::OpHitObjectGetWorldRayDirectionNV;
9209         break;
9210     case glslang::EOpHitObjectGetWorldToObjectNV:
9211         typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9212         opCode = spv::OpHitObjectGetWorldToObjectNV;
9213         break;
9214     case glslang::EOpHitObjectGetObjectToWorldNV:
9215         typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9216         opCode = spv::OpHitObjectGetObjectToWorldNV;
9217         break;
9218     case glslang::EOpHitObjectGetInstanceCustomIndexNV:
9219         typeId = builder.makeIntegerType(32, 1);
9220         opCode = spv::OpHitObjectGetInstanceCustomIndexNV;
9221         break;
9222     case glslang::EOpHitObjectGetInstanceIdNV:
9223         typeId = builder.makeIntegerType(32, 1);
9224         opCode = spv::OpHitObjectGetInstanceIdNV;
9225         break;
9226     case glslang::EOpHitObjectGetGeometryIndexNV:
9227         typeId = builder.makeIntegerType(32, 1);
9228         opCode = spv::OpHitObjectGetGeometryIndexNV;
9229         break;
9230     case glslang::EOpHitObjectGetPrimitiveIndexNV:
9231         typeId = builder.makeIntegerType(32, 1);
9232         opCode = spv::OpHitObjectGetPrimitiveIndexNV;
9233         break;
9234     case glslang::EOpHitObjectGetHitKindNV:
9235         typeId = builder.makeIntegerType(32, 0);
9236         opCode = spv::OpHitObjectGetHitKindNV;
9237         break;
9238     case glslang::EOpHitObjectGetCurrentTimeNV:
9239         typeId = builder.makeFloatType(32);
9240         opCode = spv::OpHitObjectGetCurrentTimeNV;
9241         break;
9242     case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
9243         typeId = builder.makeIntegerType(32, 0);
9244         opCode = spv::OpHitObjectGetShaderBindingTableRecordIndexNV;
9245         return 0;
9246     case glslang::EOpHitObjectGetAttributesNV:
9247         builder.createNoResultOp(spv::OpHitObjectGetAttributesNV, operands);
9248         return 0;
9249     case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
9250         typeId = builder.makeVectorType(builder.makeUintType(32), 2);
9251         opCode = spv::OpHitObjectGetShaderRecordBufferHandleNV;
9252         break;
9253     case glslang::EOpReorderThreadNV: {
9254         if (operands.size() == 2) {
9255             builder.createNoResultOp(spv::OpReorderThreadWithHintNV, operands);
9256         } else {
9257             builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operands);
9258         }
9259         return 0;
9260 
9261     }
9262 
9263     case glslang::EOpImageSampleWeightedQCOM:
9264         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9265         opCode = spv::OpImageSampleWeightedQCOM;
9266         addImageProcessingQCOMDecoration(operands[2], spv::DecorationWeightTextureQCOM);
9267         break;
9268     case glslang::EOpImageBoxFilterQCOM:
9269         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9270         opCode = spv::OpImageBoxFilterQCOM;
9271         break;
9272     case glslang::EOpImageBlockMatchSADQCOM:
9273         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9274         opCode = spv::OpImageBlockMatchSADQCOM;
9275         addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM);
9276         addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM);
9277         break;
9278     case glslang::EOpImageBlockMatchSSDQCOM:
9279         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9280         opCode = spv::OpImageBlockMatchSSDQCOM;
9281         addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM);
9282         addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM);
9283         break;
9284 
9285     case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
9286         typeId = builder.makeVectorType(builder.makeFloatType(32), 2);
9287         opCode = spv::OpFetchMicroTriangleVertexBarycentricNV;
9288         break;
9289 
9290     case glslang::EOpFetchMicroTriangleVertexPositionNV:
9291         typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9292         opCode = spv::OpFetchMicroTriangleVertexPositionNV;
9293         break;
9294 
9295     case glslang::EOpImageBlockMatchWindowSSDQCOM:
9296         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9297         opCode = spv::OpImageBlockMatchWindowSSDQCOM;
9298         addImageProcessing2QCOMDecoration(operands[0], false);
9299         addImageProcessing2QCOMDecoration(operands[2], false);
9300         break;
9301     case glslang::EOpImageBlockMatchWindowSADQCOM:
9302         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9303         opCode = spv::OpImageBlockMatchWindowSADQCOM;
9304         addImageProcessing2QCOMDecoration(operands[0], false);
9305         addImageProcessing2QCOMDecoration(operands[2], false);
9306         break;
9307     case glslang::EOpImageBlockMatchGatherSSDQCOM:
9308         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9309         opCode = spv::OpImageBlockMatchGatherSSDQCOM;
9310         addImageProcessing2QCOMDecoration(operands[0], true);
9311         addImageProcessing2QCOMDecoration(operands[2], true);
9312         break;
9313     case glslang::EOpImageBlockMatchGatherSADQCOM:
9314         typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9315         opCode = spv::OpImageBlockMatchGatherSADQCOM;
9316         addImageProcessing2QCOMDecoration(operands[0], true);
9317         addImageProcessing2QCOMDecoration(operands[2], true);
9318         break;
9319     case glslang::EOpCreateTensorLayoutNV:
9320         return builder.createOp(spv::OpCreateTensorLayoutNV, typeId, std::vector<spv::Id>{});
9321     case glslang::EOpCreateTensorViewNV:
9322         return builder.createOp(spv::OpCreateTensorViewNV, typeId, std::vector<spv::Id>{});
9323     case glslang::EOpTensorLayoutSetBlockSizeNV:
9324         opCode = spv::OpTensorLayoutSetBlockSizeNV;
9325         break;
9326     case glslang::EOpTensorLayoutSetDimensionNV:
9327         opCode = spv::OpTensorLayoutSetDimensionNV;
9328         break;
9329     case glslang::EOpTensorLayoutSetStrideNV:
9330         opCode = spv::OpTensorLayoutSetStrideNV;
9331         break;
9332     case glslang::EOpTensorLayoutSliceNV:
9333         opCode = spv::OpTensorLayoutSliceNV;
9334         break;
9335     case glslang::EOpTensorLayoutSetClampValueNV:
9336         opCode = spv::OpTensorLayoutSetClampValueNV;
9337         break;
9338     case glslang::EOpTensorViewSetDimensionNV:
9339         opCode = spv::OpTensorViewSetDimensionNV;
9340         break;
9341     case glslang::EOpTensorViewSetStrideNV:
9342         opCode = spv::OpTensorViewSetStrideNV;
9343         break;
9344     case glslang::EOpTensorViewSetClipNV:
9345         opCode = spv::OpTensorViewSetClipNV;
9346         break;
9347     default:
9348         return 0;
9349     }
9350 
9351     spv::Id id = 0;
9352     if (libCall >= 0) {
9353         // Use an extended instruction from the standard library.
9354         // Construct the call arguments, without modifying the original operands vector.
9355         // We might need the remaining arguments, e.g. in the EOpFrexp case.
9356         std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
9357         id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments);
9358     } else if (opCode == spv::OpDot && !isFloat) {
9359         // int dot(int, int)
9360         // NOTE: never called for scalar/vector1, this is turned into simple mul before this can be reached
9361         const int componentCount = builder.getNumComponents(operands[0]);
9362         spv::Id mulOp = builder.createBinOp(spv::OpIMul, builder.getTypeId(operands[0]), operands[0], operands[1]);
9363         builder.setPrecision(mulOp, precision);
9364         id = builder.createCompositeExtract(mulOp, typeId, 0);
9365         for (int i = 1; i < componentCount; ++i) {
9366             builder.setPrecision(id, precision);
9367             id = builder.createBinOp(spv::OpIAdd, typeId, id, builder.createCompositeExtract(mulOp, typeId, i));
9368         }
9369     } else {
9370         switch (consumedOperands) {
9371         case 0:
9372             // should all be handled by visitAggregate and createNoArgOperation
9373             assert(0);
9374             return 0;
9375         case 1:
9376             // should all be handled by createUnaryOperation
9377             assert(0);
9378             return 0;
9379         case 2:
9380             id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
9381             break;
9382         default:
9383             // anything 3 or over doesn't have l-value operands, so all should be consumed
9384             assert(consumedOperands == operands.size());
9385             id = builder.createOp(opCode, typeId, operands);
9386             break;
9387         }
9388     }
9389 
9390     // Decode the return types that were structures
9391     switch (op) {
9392     case glslang::EOpAddCarry:
9393     case glslang::EOpSubBorrow:
9394         builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
9395         id = builder.createCompositeExtract(id, typeId0, 0);
9396         break;
9397     case glslang::EOpUMulExtended:
9398     case glslang::EOpIMulExtended:
9399         builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
9400         builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
9401         break;
9402     case glslang::EOpModf:
9403         {
9404             assert(operands.size() == 2);
9405             builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[1]);
9406             id = builder.createCompositeExtract(id, typeId0, 0);
9407         }
9408         break;
9409     case glslang::EOpFrexp:
9410         {
9411             assert(operands.size() == 2);
9412             if (builder.isFloatType(builder.getScalarTypeId(typeId1))) {
9413                 // "exp" is floating-point type (from HLSL intrinsic)
9414                 spv::Id member1 = builder.createCompositeExtract(id, frexpIntType, 1);
9415                 member1 = builder.createUnaryOp(spv::OpConvertSToF, typeId1, member1);
9416                 builder.createStore(member1, operands[1]);
9417             } else
9418                 // "exp" is integer type (from GLSL built-in function)
9419                 builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
9420             id = builder.createCompositeExtract(id, typeId0, 0);
9421         }
9422         break;
9423     default:
9424         break;
9425     }
9426 
9427     return builder.setPrecision(id, precision);
9428 }
9429 
9430 // Intrinsics with no arguments (or no return value, and no precision).
createNoArgOperation(glslang::TOperator op,spv::Decoration precision,spv::Id typeId)9431 spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)
9432 {
9433     // GLSL memory barriers use queuefamily scope in new model, device scope in old model
9434     spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ?
9435         spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
9436 
9437     switch (op) {
9438     case glslang::EOpBarrier:
9439         if (glslangIntermediate->getStage() == EShLangTessControl) {
9440             if (glslangIntermediate->usingVulkanMemoryModel()) {
9441                 builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
9442                                              spv::MemorySemanticsOutputMemoryKHRMask |
9443                                              spv::MemorySemanticsAcquireReleaseMask);
9444                 builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
9445             } else {
9446                 builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeInvocation, spv::MemorySemanticsMaskNone);
9447             }
9448         } else {
9449             builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
9450                                             spv::MemorySemanticsWorkgroupMemoryMask |
9451                                             spv::MemorySemanticsAcquireReleaseMask);
9452         }
9453         return 0;
9454     case glslang::EOpMemoryBarrier:
9455         builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAllMemory |
9456                                                         spv::MemorySemanticsAcquireReleaseMask);
9457         return 0;
9458     case glslang::EOpMemoryBarrierBuffer:
9459         builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsUniformMemoryMask |
9460                                                         spv::MemorySemanticsAcquireReleaseMask);
9461         return 0;
9462     case glslang::EOpMemoryBarrierShared:
9463         builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsWorkgroupMemoryMask |
9464                                                         spv::MemorySemanticsAcquireReleaseMask);
9465         return 0;
9466     case glslang::EOpGroupMemoryBarrier:
9467         builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsAllMemory |
9468                                                          spv::MemorySemanticsAcquireReleaseMask);
9469         return 0;
9470     case glslang::EOpMemoryBarrierAtomicCounter:
9471         builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAtomicCounterMemoryMask |
9472                                                         spv::MemorySemanticsAcquireReleaseMask);
9473         return 0;
9474     case glslang::EOpMemoryBarrierImage:
9475         builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsImageMemoryMask |
9476                                                         spv::MemorySemanticsAcquireReleaseMask);
9477         return 0;
9478     case glslang::EOpAllMemoryBarrierWithGroupSync:
9479         builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice,
9480                                         spv::MemorySemanticsAllMemory |
9481                                         spv::MemorySemanticsAcquireReleaseMask);
9482         return 0;
9483     case glslang::EOpDeviceMemoryBarrier:
9484         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |
9485                                                       spv::MemorySemanticsImageMemoryMask |
9486                                                       spv::MemorySemanticsAcquireReleaseMask);
9487         return 0;
9488     case glslang::EOpDeviceMemoryBarrierWithGroupSync:
9489         builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |
9490                                                                             spv::MemorySemanticsImageMemoryMask |
9491                                                                             spv::MemorySemanticsAcquireReleaseMask);
9492         return 0;
9493     case glslang::EOpWorkgroupMemoryBarrier:
9494         builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask |
9495                                                          spv::MemorySemanticsAcquireReleaseMask);
9496         return 0;
9497     case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
9498         builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
9499                                         spv::MemorySemanticsWorkgroupMemoryMask |
9500                                         spv::MemorySemanticsAcquireReleaseMask);
9501         return 0;
9502     case glslang::EOpSubgroupBarrier:
9503         builder.createControlBarrier(spv::ScopeSubgroup, spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |
9504                                                                              spv::MemorySemanticsAcquireReleaseMask);
9505         return spv::NoResult;
9506     case glslang::EOpSubgroupMemoryBarrier:
9507         builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |
9508                                                         spv::MemorySemanticsAcquireReleaseMask);
9509         return spv::NoResult;
9510     case glslang::EOpSubgroupMemoryBarrierBuffer:
9511         builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsUniformMemoryMask |
9512                                                         spv::MemorySemanticsAcquireReleaseMask);
9513         return spv::NoResult;
9514     case glslang::EOpSubgroupMemoryBarrierImage:
9515         builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsImageMemoryMask |
9516                                                         spv::MemorySemanticsAcquireReleaseMask);
9517         return spv::NoResult;
9518     case glslang::EOpSubgroupMemoryBarrierShared:
9519         builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsWorkgroupMemoryMask |
9520                                                         spv::MemorySemanticsAcquireReleaseMask);
9521         return spv::NoResult;
9522 
9523     case glslang::EOpEmitVertex:
9524         builder.createNoResultOp(spv::OpEmitVertex);
9525         return 0;
9526     case glslang::EOpEndPrimitive:
9527         builder.createNoResultOp(spv::OpEndPrimitive);
9528         return 0;
9529 
9530     case glslang::EOpSubgroupElect: {
9531         std::vector<spv::Id> operands;
9532         return createSubgroupOperation(op, typeId, operands, glslang::EbtVoid);
9533     }
9534     case glslang::EOpTime:
9535     {
9536         std::vector<spv::Id> args; // Dummy arguments
9537         spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args);
9538         return builder.setPrecision(id, precision);
9539     }
9540     case glslang::EOpIgnoreIntersectionNV:
9541         builder.createNoResultOp(spv::OpIgnoreIntersectionNV);
9542         return 0;
9543     case glslang::EOpTerminateRayNV:
9544         builder.createNoResultOp(spv::OpTerminateRayNV);
9545         return 0;
9546     case glslang::EOpRayQueryInitialize:
9547         builder.createNoResultOp(spv::OpRayQueryInitializeKHR);
9548         return 0;
9549     case glslang::EOpRayQueryTerminate:
9550         builder.createNoResultOp(spv::OpRayQueryTerminateKHR);
9551         return 0;
9552     case glslang::EOpRayQueryGenerateIntersection:
9553         builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR);
9554         return 0;
9555     case glslang::EOpRayQueryConfirmIntersection:
9556         builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR);
9557         return 0;
9558     case glslang::EOpBeginInvocationInterlock:
9559         builder.createNoResultOp(spv::OpBeginInvocationInterlockEXT);
9560         return 0;
9561     case glslang::EOpEndInvocationInterlock:
9562         builder.createNoResultOp(spv::OpEndInvocationInterlockEXT);
9563         return 0;
9564 
9565     case glslang::EOpIsHelperInvocation:
9566     {
9567         std::vector<spv::Id> args; // Dummy arguments
9568         builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
9569         builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);
9570         return builder.createOp(spv::OpIsHelperInvocationEXT, typeId, args);
9571     }
9572 
9573     case glslang::EOpReadClockSubgroupKHR: {
9574         std::vector<spv::Id> args;
9575         args.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
9576         builder.addExtension(spv::E_SPV_KHR_shader_clock);
9577         builder.addCapability(spv::CapabilityShaderClockKHR);
9578         return builder.createOp(spv::OpReadClockKHR, typeId, args);
9579     }
9580 
9581     case glslang::EOpReadClockDeviceKHR: {
9582         std::vector<spv::Id> args;
9583         args.push_back(builder.makeUintConstant(spv::ScopeDevice));
9584         builder.addExtension(spv::E_SPV_KHR_shader_clock);
9585         builder.addCapability(spv::CapabilityShaderClockKHR);
9586         return builder.createOp(spv::OpReadClockKHR, typeId, args);
9587     }
9588     case glslang::EOpStencilAttachmentReadEXT:
9589     case glslang::EOpDepthAttachmentReadEXT:
9590     {
9591         builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
9592 
9593         spv::Decoration precision;
9594         spv::Op spv_op;
9595         if (op == glslang::EOpStencilAttachmentReadEXT)
9596         {
9597             precision = spv::DecorationRelaxedPrecision;
9598             spv_op = spv::OpStencilAttachmentReadEXT;
9599             builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);
9600         }
9601         else
9602         {
9603             precision = spv::NoPrecision;
9604             spv_op = spv::OpDepthAttachmentReadEXT;
9605             builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);
9606         }
9607 
9608         std::vector<spv::Id> args; // Dummy args
9609         spv::Id result = builder.createOp(spv_op, typeId, args);
9610         return builder.setPrecision(result, precision);
9611     }
9612     default:
9613         break;
9614     }
9615 
9616     logger->missingFunctionality("unknown operation with no arguments");
9617 
9618     return 0;
9619 }
9620 
getSymbolId(const glslang::TIntermSymbol * symbol)9621 spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
9622 {
9623     auto iter = symbolValues.find(symbol->getId());
9624     spv::Id id;
9625     if (symbolValues.end() != iter) {
9626         id = iter->second;
9627         return id;
9628     }
9629 
9630     // it was not found, create it
9631     spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false);
9632     auto forcedType = getForcedType(symbol->getQualifier().builtIn, symbol->getType());
9633 
9634     // There are pairs of symbols that map to the same SPIR-V built-in:
9635     // gl_ObjectToWorldEXT and gl_ObjectToWorld3x4EXT, and gl_WorldToObjectEXT
9636     // and gl_WorldToObject3x4EXT. SPIR-V forbids having two OpVariables
9637     // with the same BuiltIn in the same storage class, so we must re-use one.
9638     const bool mayNeedToReuseBuiltIn =
9639         builtIn == spv::BuiltInObjectToWorldKHR ||
9640         builtIn == spv::BuiltInWorldToObjectKHR;
9641 
9642     if (mayNeedToReuseBuiltIn) {
9643         auto iter = builtInVariableIds.find(uint32_t(builtIn));
9644         if (builtInVariableIds.end() != iter) {
9645             id = iter->second;
9646             symbolValues[symbol->getId()] = id;
9647             if (forcedType.second != spv::NoType)
9648                 forceType[id] = forcedType.second;
9649             return id;
9650         }
9651     }
9652 
9653     if (symbol->getBasicType() == glslang::EbtFunction) {
9654         return 0;
9655     }
9656 
9657     id = createSpvVariable(symbol, forcedType.first);
9658 
9659     if (mayNeedToReuseBuiltIn) {
9660         builtInVariableIds.insert({uint32_t(builtIn), id});
9661     }
9662 
9663     symbolValues[symbol->getId()] = id;
9664     if (forcedType.second != spv::NoType)
9665         forceType[id] = forcedType.second;
9666 
9667     if (symbol->getBasicType() != glslang::EbtBlock) {
9668         builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
9669         builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
9670         builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier()));
9671         addMeshNVDecoration(id, /*member*/ -1, symbol->getType().getQualifier());
9672         if (symbol->getQualifier().hasComponent())
9673             builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
9674         if (symbol->getQualifier().hasIndex())
9675             builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
9676         if (symbol->getType().getQualifier().hasSpecConstantId())
9677             builder.addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId);
9678         // atomic counters use this:
9679         if (symbol->getQualifier().hasOffset())
9680             builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset);
9681     }
9682 
9683     if (symbol->getQualifier().hasLocation()) {
9684         if (!(glslangIntermediate->isRayTracingStage() &&
9685               (glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_ray_tracing) ||
9686                glslangIntermediate->IsRequestedExtension(glslang::E_GL_NV_shader_invocation_reorder))
9687               && (builder.getStorageClass(id) == spv::StorageClassRayPayloadKHR ||
9688                   builder.getStorageClass(id) == spv::StorageClassIncomingRayPayloadKHR ||
9689                   builder.getStorageClass(id) == spv::StorageClassCallableDataKHR ||
9690                   builder.getStorageClass(id) == spv::StorageClassIncomingCallableDataKHR ||
9691                   builder.getStorageClass(id) == spv::StorageClassHitObjectAttributeNV))) {
9692             // Location values are used to link TraceRayKHR/ExecuteCallableKHR/HitObjectGetAttributesNV
9693             // to corresponding variables but are not valid in SPIRV since they are supported only
9694             // for Input/Output Storage classes.
9695             builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
9696         }
9697     }
9698 
9699     builder.addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
9700     if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {
9701         builder.addCapability(spv::CapabilityGeometryStreams);
9702         builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
9703     }
9704     if (symbol->getQualifier().hasSet())
9705         builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
9706     else if (IsDescriptorResource(symbol->getType())) {
9707         // default to 0
9708         builder.addDecoration(id, spv::DecorationDescriptorSet, 0);
9709     }
9710     if (symbol->getQualifier().hasBinding())
9711         builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
9712     else if (IsDescriptorResource(symbol->getType())) {
9713         // default to 0
9714         builder.addDecoration(id, spv::DecorationBinding, 0);
9715     }
9716     if (symbol->getQualifier().hasAttachment())
9717         builder.addDecoration(id, spv::DecorationInputAttachmentIndex, symbol->getQualifier().layoutAttachment);
9718     if (glslangIntermediate->getXfbMode()) {
9719         builder.addCapability(spv::CapabilityTransformFeedback);
9720         if (symbol->getQualifier().hasXfbBuffer()) {
9721             builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
9722             unsigned stride = glslangIntermediate->getXfbStride(symbol->getQualifier().layoutXfbBuffer);
9723             if (stride != glslang::TQualifier::layoutXfbStrideEnd)
9724                 builder.addDecoration(id, spv::DecorationXfbStride, stride);
9725         }
9726         if (symbol->getQualifier().hasXfbOffset())
9727             builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
9728     }
9729 
9730     // add built-in variable decoration
9731     if (builtIn != spv::BuiltInMax) {
9732         // WorkgroupSize deprecated in spirv1.6
9733         if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6 ||
9734             builtIn != spv::BuiltInWorkgroupSize)
9735             builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
9736     }
9737 
9738     // Add volatile decoration to HelperInvocation for spirv1.6 and beyond
9739     if (builtIn == spv::BuiltInHelperInvocation &&
9740         !glslangIntermediate->usingVulkanMemoryModel() &&
9741         glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
9742         builder.addDecoration(id, spv::DecorationVolatile);
9743     }
9744 
9745     // Subgroup builtins which have input storage class are volatile for ray tracing stages.
9746     if (symbol->getType().isImage() || symbol->getQualifier().isPipeInput()) {
9747         std::vector<spv::Decoration> memory;
9748         TranslateMemoryDecoration(symbol->getType().getQualifier(), memory,
9749             glslangIntermediate->usingVulkanMemoryModel());
9750         for (unsigned int i = 0; i < memory.size(); ++i)
9751             builder.addDecoration(id, memory[i]);
9752     }
9753 
9754     if (builtIn == spv::BuiltInSampleMask) {
9755           spv::Decoration decoration;
9756           // GL_NV_sample_mask_override_coverage extension
9757           if (glslangIntermediate->getLayoutOverrideCoverage())
9758               decoration = (spv::Decoration)spv::DecorationOverrideCoverageNV;
9759           else
9760               decoration = (spv::Decoration)spv::DecorationMax;
9761         builder.addDecoration(id, decoration);
9762         if (decoration != spv::DecorationMax) {
9763             builder.addCapability(spv::CapabilitySampleMaskOverrideCoverageNV);
9764             builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
9765         }
9766     }
9767     else if (builtIn == spv::BuiltInLayer) {
9768         // SPV_NV_viewport_array2 extension
9769         if (symbol->getQualifier().layoutViewportRelative) {
9770             builder.addDecoration(id, (spv::Decoration)spv::DecorationViewportRelativeNV);
9771             builder.addCapability(spv::CapabilityShaderViewportMaskNV);
9772             builder.addExtension(spv::E_SPV_NV_viewport_array2);
9773         }
9774         if (symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048) {
9775             builder.addDecoration(id, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,
9776                                   symbol->getQualifier().layoutSecondaryViewportRelativeOffset);
9777             builder.addCapability(spv::CapabilityShaderStereoViewNV);
9778             builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
9779         }
9780     }
9781 
9782     if (symbol->getQualifier().layoutPassthrough) {
9783         builder.addDecoration(id, spv::DecorationPassthroughNV);
9784         builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
9785         builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
9786     }
9787     if (symbol->getQualifier().pervertexNV) {
9788         builder.addDecoration(id, spv::DecorationPerVertexNV);
9789         builder.addCapability(spv::CapabilityFragmentBarycentricNV);
9790         builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
9791     }
9792 
9793     if (symbol->getQualifier().pervertexEXT) {
9794         builder.addDecoration(id, spv::DecorationPerVertexKHR);
9795         builder.addCapability(spv::CapabilityFragmentBarycentricKHR);
9796         builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
9797     }
9798 
9799     if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) {
9800         builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
9801         builder.addDecoration(id, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
9802                               symbol->getType().getQualifier().semanticName);
9803     }
9804 
9805     if (symbol->isReference()) {
9806         builder.addDecoration(id, symbol->getType().getQualifier().restrict ?
9807             spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
9808     }
9809 
9810     // Add SPIR-V decorations (GL_EXT_spirv_intrinsics)
9811     if (symbol->getType().getQualifier().hasSpirvDecorate())
9812         applySpirvDecorate(symbol->getType(), id, {});
9813 
9814     return id;
9815 }
9816 
9817 // add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object
addMeshNVDecoration(spv::Id id,int member,const glslang::TQualifier & qualifier)9818 void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier& qualifier)
9819 {
9820     bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=
9821                             glslangIntermediate->getRequestedExtensions().end());
9822 
9823     if (member >= 0) {
9824         if (qualifier.perPrimitiveNV) {
9825             // Need to add capability/extension for fragment shader.
9826             // Mesh shader already adds this by default.
9827             if (glslangIntermediate->getStage() == EShLangFragment) {
9828                 if(isMeshShaderExt) {
9829                     builder.addCapability(spv::CapabilityMeshShadingEXT);
9830                     builder.addExtension(spv::E_SPV_EXT_mesh_shader);
9831                 } else {
9832                     builder.addCapability(spv::CapabilityMeshShadingNV);
9833                     builder.addExtension(spv::E_SPV_NV_mesh_shader);
9834                 }
9835             }
9836             builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerPrimitiveNV);
9837         }
9838         if (qualifier.perViewNV)
9839             builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerViewNV);
9840         if (qualifier.perTaskNV)
9841             builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerTaskNV);
9842     } else {
9843         if (qualifier.perPrimitiveNV) {
9844             // Need to add capability/extension for fragment shader.
9845             // Mesh shader already adds this by default.
9846             if (glslangIntermediate->getStage() == EShLangFragment) {
9847                 if(isMeshShaderExt) {
9848                     builder.addCapability(spv::CapabilityMeshShadingEXT);
9849                     builder.addExtension(spv::E_SPV_EXT_mesh_shader);
9850                 } else {
9851                     builder.addCapability(spv::CapabilityMeshShadingNV);
9852                     builder.addExtension(spv::E_SPV_NV_mesh_shader);
9853                 }
9854             }
9855             builder.addDecoration(id, spv::DecorationPerPrimitiveNV);
9856         }
9857         if (qualifier.perViewNV)
9858             builder.addDecoration(id, spv::DecorationPerViewNV);
9859         if (qualifier.perTaskNV)
9860             builder.addDecoration(id, spv::DecorationPerTaskNV);
9861     }
9862 }
9863 
hasQCOMImageProceessingDecoration(spv::Id id,spv::Decoration decor)9864 bool TGlslangToSpvTraverser::hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor)
9865 {
9866   std::vector<spv::Decoration> &decoVec = idToQCOMDecorations[id];
9867   for ( auto d : decoVec ) {
9868     if ( d == decor )
9869       return true;
9870   }
9871   return false;
9872 }
9873 
addImageProcessingQCOMDecoration(spv::Id id,spv::Decoration decor)9874 void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor)
9875 {
9876   spv::Op opc = builder.getOpCode(id);
9877   if (opc == spv::OpSampledImage) {
9878     id  = builder.getIdOperand(id, 0);
9879     opc = builder.getOpCode(id);
9880   }
9881 
9882   if (opc == spv::OpLoad) {
9883     spv::Id texid = builder.getIdOperand(id, 0);
9884     if (!hasQCOMImageProceessingDecoration(texid, decor)) {//
9885       builder.addDecoration(texid, decor);
9886       idToQCOMDecorations[texid].push_back(decor);
9887     }
9888   }
9889 }
9890 
addImageProcessing2QCOMDecoration(spv::Id id,bool isForGather)9891 void TGlslangToSpvTraverser::addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather)
9892 {
9893   if (isForGather) {
9894     return addImageProcessingQCOMDecoration(id, spv::DecorationBlockMatchTextureQCOM);
9895   }
9896 
9897   auto addDecor =
9898     [this](spv::Id id, spv::Decoration decor) {
9899       spv::Id tsopc = this->builder.getOpCode(id);
9900       if (tsopc == spv::OpLoad) {
9901         spv::Id tsid = this->builder.getIdOperand(id, 0);
9902         if (this->glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
9903           assert(iOSet.count(tsid) > 0);
9904         }
9905         if (!hasQCOMImageProceessingDecoration(tsid, decor)) {
9906           this->builder.addDecoration(tsid, decor);
9907           idToQCOMDecorations[tsid].push_back(decor);
9908         }
9909       }
9910     };
9911 
9912   spv::Id opc = builder.getOpCode(id);
9913   bool isInterfaceObject = (opc != spv::OpSampledImage);
9914 
9915   if (!isInterfaceObject) {
9916     addDecor(builder.getIdOperand(id, 0), spv::DecorationBlockMatchTextureQCOM);
9917     addDecor(builder.getIdOperand(id, 1), spv::DecorationBlockMatchSamplerQCOM);
9918   } else {
9919     addDecor(id, spv::DecorationBlockMatchTextureQCOM);
9920     addDecor(id, spv::DecorationBlockMatchSamplerQCOM);
9921   }
9922 }
9923 
9924 // Make a full tree of instructions to build a SPIR-V specialization constant,
9925 // or regular constant if possible.
9926 //
9927 // TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
9928 //
9929 // Recursively walk the nodes.  The nodes form a tree whose leaves are
9930 // regular constants, which themselves are trees that createSpvConstant()
9931 // recursively walks.  So, this function walks the "top" of the tree:
9932 //  - emit specialization constant-building instructions for specConstant
9933 //  - when running into a non-spec-constant, switch to createSpvConstant()
createSpvConstant(const glslang::TIntermTyped & node)9934 spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
9935 {
9936     assert(node.getQualifier().isConstant());
9937 
9938     // Handle front-end constants first (non-specialization constants).
9939     if (! node.getQualifier().specConstant) {
9940         // hand off to the non-spec-constant path
9941         assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
9942         int nextConst = 0;
9943         return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ?
9944             node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
9945             nextConst, false);
9946     }
9947 
9948     // We now know we have a specialization constant to build
9949 
9950     // Extra capabilities may be needed.
9951     if (node.getType().contains8BitInt())
9952         builder.addCapability(spv::CapabilityInt8);
9953     if (node.getType().contains16BitFloat())
9954         builder.addCapability(spv::CapabilityFloat16);
9955     if (node.getType().contains16BitInt())
9956         builder.addCapability(spv::CapabilityInt16);
9957     if (node.getType().contains64BitInt())
9958         builder.addCapability(spv::CapabilityInt64);
9959     if (node.getType().containsDouble())
9960         builder.addCapability(spv::CapabilityFloat64);
9961 
9962     // gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,
9963     // even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...
9964     if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) {
9965         std::vector<spv::Id> dimConstId;
9966         for (int dim = 0; dim < 3; ++dim) {
9967             bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
9968             dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
9969             if (specConst) {
9970                 builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
9971                                       glslangIntermediate->getLocalSizeSpecId(dim));
9972             }
9973         }
9974         return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
9975     }
9976 
9977     // An AST node labelled as specialization constant should be a symbol node.
9978     // Its initializer should either be a sub tree with constant nodes, or a constant union array.
9979     if (auto* sn = node.getAsSymbolNode()) {
9980         spv::Id result;
9981         if (auto* sub_tree = sn->getConstSubtree()) {
9982             // Traverse the constant constructor sub tree like generating normal run-time instructions.
9983             // During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard
9984             // will set the builder into spec constant op instruction generating mode.
9985             sub_tree->traverse(this);
9986             result = accessChainLoad(sub_tree->getType());
9987         } else if (auto* const_union_array = &sn->getConstArray()) {
9988             int nextConst = 0;
9989             result = createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true);
9990         } else {
9991             logger->missingFunctionality("Invalid initializer for spec onstant.");
9992             return spv::NoResult;
9993         }
9994         builder.addName(result, sn->getName().c_str());
9995         return result;
9996     }
9997 
9998     // Neither a front-end constant node, nor a specialization constant node with constant union array or
9999     // constant sub tree as initializer.
10000     logger->missingFunctionality("Neither a front-end constant nor a spec constant.");
10001     return spv::NoResult;
10002 }
10003 
10004 // Use 'consts' as the flattened glslang source of scalar constants to recursively
10005 // build the aggregate SPIR-V constant.
10006 //
10007 // If there are not enough elements present in 'consts', 0 will be substituted;
10008 // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
10009 //
createSpvConstantFromConstUnionArray(const glslang::TType & glslangType,const glslang::TConstUnionArray & consts,int & nextConst,bool specConstant)10010 spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType,
10011     const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
10012 {
10013     // vector of constants for SPIR-V
10014     std::vector<spv::Id> spvConsts;
10015 
10016     // Type is used for struct and array constants
10017     spv::Id typeId = convertGlslangToSpvType(glslangType);
10018 
10019     if (glslangType.isArray()) {
10020         glslang::TType elementType(glslangType, 0);
10021         for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
10022             spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
10023     } else if (glslangType.isMatrix()) {
10024         glslang::TType vectorType(glslangType, 0);
10025         for (int col = 0; col < glslangType.getMatrixCols(); ++col)
10026             spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
10027     } else if (glslangType.isCoopMat()) {
10028         glslang::TType componentType(glslangType.getBasicType());
10029         spvConsts.push_back(createSpvConstantFromConstUnionArray(componentType, consts, nextConst, false));
10030     } else if (glslangType.isStruct()) {
10031         glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
10032         for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
10033             spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
10034     } else if (glslangType.getVectorSize() > 1) {
10035         for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
10036             bool zero = nextConst >= consts.size();
10037             switch (glslangType.getBasicType()) {
10038             case glslang::EbtInt:
10039                 spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
10040                 break;
10041             case glslang::EbtUint:
10042                 spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
10043                 break;
10044             case glslang::EbtFloat:
10045                 spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
10046                 break;
10047             case glslang::EbtBool:
10048                 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
10049                 break;
10050             case glslang::EbtInt8:
10051                 builder.addCapability(spv::CapabilityInt8);
10052                 spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const()));
10053                 break;
10054             case glslang::EbtUint8:
10055                 builder.addCapability(spv::CapabilityInt8);
10056                 spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const()));
10057                 break;
10058             case glslang::EbtInt16:
10059                 builder.addCapability(spv::CapabilityInt16);
10060                 spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const()));
10061                 break;
10062             case glslang::EbtUint16:
10063                 builder.addCapability(spv::CapabilityInt16);
10064                 spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const()));
10065                 break;
10066             case glslang::EbtInt64:
10067                 spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const()));
10068                 break;
10069             case glslang::EbtUint64:
10070                 spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const()));
10071                 break;
10072             case glslang::EbtDouble:
10073                 spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
10074                 break;
10075             case glslang::EbtFloat16:
10076                 builder.addCapability(spv::CapabilityFloat16);
10077                 spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
10078                 break;
10079             default:
10080                 assert(0);
10081                 break;
10082             }
10083             ++nextConst;
10084         }
10085     } else {
10086         // we have a non-aggregate (scalar) constant
10087         bool zero = nextConst >= consts.size();
10088         spv::Id scalar = 0;
10089         switch (glslangType.getBasicType()) {
10090         case glslang::EbtInt:
10091             scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
10092             break;
10093         case glslang::EbtUint:
10094             scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
10095             break;
10096         case glslang::EbtFloat:
10097             scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
10098             break;
10099         case glslang::EbtBool:
10100             scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
10101             break;
10102         case glslang::EbtInt8:
10103             builder.addCapability(spv::CapabilityInt8);
10104             scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant);
10105             break;
10106         case glslang::EbtUint8:
10107             builder.addCapability(spv::CapabilityInt8);
10108             scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant);
10109             break;
10110         case glslang::EbtInt16:
10111             builder.addCapability(spv::CapabilityInt16);
10112             scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant);
10113             break;
10114         case glslang::EbtUint16:
10115             builder.addCapability(spv::CapabilityInt16);
10116             scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant);
10117             break;
10118         case glslang::EbtInt64:
10119             scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant);
10120             break;
10121         case glslang::EbtUint64:
10122             scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
10123             break;
10124         case glslang::EbtDouble:
10125             scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
10126             break;
10127         case glslang::EbtFloat16:
10128             builder.addCapability(spv::CapabilityFloat16);
10129             scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
10130             break;
10131         case glslang::EbtReference:
10132             scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
10133             scalar = builder.createUnaryOp(spv::OpBitcast, typeId, scalar);
10134             break;
10135         case glslang::EbtString:
10136             scalar = builder.getStringId(consts[nextConst].getSConst()->c_str());
10137             break;
10138         default:
10139             assert(0);
10140             break;
10141         }
10142         ++nextConst;
10143         return scalar;
10144     }
10145 
10146     return builder.makeCompositeConstant(typeId, spvConsts);
10147 }
10148 
10149 // Return true if the node is a constant or symbol whose reading has no
10150 // non-trivial observable cost or effect.
isTrivialLeaf(const glslang::TIntermTyped * node)10151 bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
10152 {
10153     // don't know what this is
10154     if (node == nullptr)
10155         return false;
10156 
10157     // a constant is safe
10158     if (node->getAsConstantUnion() != nullptr)
10159         return true;
10160 
10161     // not a symbol means non-trivial
10162     if (node->getAsSymbolNode() == nullptr)
10163         return false;
10164 
10165     // a symbol, depends on what's being read
10166     switch (node->getType().getQualifier().storage) {
10167     case glslang::EvqTemporary:
10168     case glslang::EvqGlobal:
10169     case glslang::EvqIn:
10170     case glslang::EvqInOut:
10171     case glslang::EvqConst:
10172     case glslang::EvqConstReadOnly:
10173     case glslang::EvqUniform:
10174         return true;
10175     default:
10176         return false;
10177     }
10178 }
10179 
10180 // A node is trivial if it is a single operation with no side effects.
10181 // HLSL (and/or vectors) are always trivial, as it does not short circuit.
10182 // Otherwise, error on the side of saying non-trivial.
10183 // Return true if trivial.
isTrivial(const glslang::TIntermTyped * node)10184 bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
10185 {
10186     if (node == nullptr)
10187         return false;
10188 
10189     // count non scalars as trivial, as well as anything coming from HLSL
10190     if (! node->getType().isScalarOrVec1() || glslangIntermediate->getSource() == glslang::EShSourceHlsl)
10191         return true;
10192 
10193     // symbols and constants are trivial
10194     if (isTrivialLeaf(node))
10195         return true;
10196 
10197     // otherwise, it needs to be a simple operation or one or two leaf nodes
10198 
10199     // not a simple operation
10200     const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();
10201     const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();
10202     if (binaryNode == nullptr && unaryNode == nullptr)
10203         return false;
10204 
10205     // not on leaf nodes
10206     if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))
10207         return false;
10208 
10209     if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {
10210         return false;
10211     }
10212 
10213     if (IsOpNumericConv(node->getAsOperator()->getOp()) &&
10214         node->getType().getBasicType() == glslang::EbtBool) {
10215         return true;
10216     }
10217 
10218     switch (node->getAsOperator()->getOp()) {
10219     case glslang::EOpLogicalNot:
10220     case glslang::EOpEqual:
10221     case glslang::EOpNotEqual:
10222     case glslang::EOpLessThan:
10223     case glslang::EOpGreaterThan:
10224     case glslang::EOpLessThanEqual:
10225     case glslang::EOpGreaterThanEqual:
10226     case glslang::EOpIndexDirect:
10227     case glslang::EOpIndexDirectStruct:
10228     case glslang::EOpLogicalXor:
10229     case glslang::EOpAny:
10230     case glslang::EOpAll:
10231         return true;
10232     default:
10233         return false;
10234     }
10235 }
10236 
10237 // Emit short-circuiting code, where 'right' is never evaluated unless
10238 // the left side is true (for &&) or false (for ||).
createShortCircuit(glslang::TOperator op,glslang::TIntermTyped & left,glslang::TIntermTyped & right)10239 spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left,
10240     glslang::TIntermTyped& right)
10241 {
10242     spv::Id boolTypeId = builder.makeBoolType();
10243 
10244     // emit left operand
10245     builder.clearAccessChain();
10246     left.traverse(this);
10247     spv::Id leftId = accessChainLoad(left.getType());
10248 
10249     // Operands to accumulate OpPhi operands
10250     std::vector<spv::Id> phiOperands;
10251     phiOperands.reserve(4);
10252     // accumulate left operand's phi information
10253     phiOperands.push_back(leftId);
10254     phiOperands.push_back(builder.getBuildPoint()->getId());
10255 
10256     // Make the two kinds of operation symmetric with a "!"
10257     //   || => emit "if (! left) result = right"
10258     //   && => emit "if (  left) result = right"
10259     //
10260     // TODO: this runtime "not" for || could be avoided by adding functionality
10261     // to 'builder' to have an "else" without an "then"
10262     if (op == glslang::EOpLogicalOr)
10263         leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);
10264 
10265     // make an "if" based on the left value
10266     spv::Builder::If ifBuilder(leftId, spv::SelectionControlMaskNone, builder);
10267 
10268     // emit right operand as the "then" part of the "if"
10269     builder.clearAccessChain();
10270     right.traverse(this);
10271     spv::Id rightId = accessChainLoad(right.getType());
10272 
10273     // accumulate left operand's phi information
10274     phiOperands.push_back(rightId);
10275     phiOperands.push_back(builder.getBuildPoint()->getId());
10276 
10277     // finish the "if"
10278     ifBuilder.makeEndIf();
10279 
10280     // phi together the two results
10281     return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);
10282 }
10283 
10284 // Return type Id of the imported set of extended instructions corresponds to the name.
10285 // Import this set if it has not been imported yet.
getExtBuiltins(const char * name)10286 spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name)
10287 {
10288     if (extBuiltinMap.find(name) != extBuiltinMap.end())
10289         return extBuiltinMap[name];
10290     else {
10291         spv::Id extBuiltins = builder.import(name);
10292         extBuiltinMap[name] = extBuiltins;
10293         return extBuiltins;
10294     }
10295 }
10296 
10297 } // end anonymous namespace
10298 
10299 namespace glslang {
10300 
GetSpirvVersion(std::string & version)10301 void GetSpirvVersion(std::string& version)
10302 {
10303     const int bufSize = 100;
10304     char buf[bufSize];
10305     snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
10306     version = buf;
10307 }
10308 
10309 // For low-order part of the generator's magic number. Bump up
10310 // when there is a change in the style (e.g., if SSA form changes,
10311 // or a different instruction sequence to do something gets used).
GetSpirvGeneratorVersion()10312 int GetSpirvGeneratorVersion()
10313 {
10314     // return 1; // start
10315     // return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V
10316     // return 3; // change/correct barrier-instruction operands, to match memory model group decisions
10317     // return 4; // some deeper access chains: for dynamic vector component, and local Boolean component
10318     // return 5; // make OpArrayLength result type be an int with signedness of 0
10319     // return 6; // revert version 5 change, which makes a different (new) kind of incorrect code,
10320                  // versions 4 and 6 each generate OpArrayLength as it has long been done
10321     // return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent
10322     // return 8; // switch to new dead block eliminator; use OpUnreachable
10323     // return 9; // don't include opaque function parameters in OpEntryPoint global's operand list
10324     // return 10; // Generate OpFUnordNotEqual for != comparisons
10325     return 11; // Make OpEmitMeshTasksEXT a terminal instruction
10326 }
10327 
10328 // Write SPIR-V out to a binary file
OutputSpvBin(const std::vector<unsigned int> & spirv,const char * baseName)10329 bool OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName)
10330 {
10331     std::ofstream out;
10332     out.open(baseName, std::ios::binary | std::ios::out);
10333     if (out.fail()) {
10334         printf("ERROR: Failed to open file: %s\n", baseName);
10335         return false;
10336     }
10337     for (int i = 0; i < (int)spirv.size(); ++i) {
10338         unsigned int word = spirv[i];
10339         out.write((const char*)&word, 4);
10340     }
10341     out.close();
10342     return true;
10343 }
10344 
10345 // Write SPIR-V out to a text file with 32-bit hexadecimal words
OutputSpvHex(const std::vector<unsigned int> & spirv,const char * baseName,const char * varName)10346 bool OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName)
10347 {
10348     std::ofstream out;
10349     out.open(baseName, std::ios::binary | std::ios::out);
10350     if (out.fail()) {
10351         printf("ERROR: Failed to open file: %s\n", baseName);
10352         return false;
10353     }
10354     out << "\t// " <<
10355         GetSpirvGeneratorVersion() <<
10356         GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH <<
10357         GLSLANG_VERSION_FLAVOR << std::endl;
10358     if (varName != nullptr) {
10359         out << "\t #pragma once" << std::endl;
10360         out << "const uint32_t " << varName << "[] = {" << std::endl;
10361     }
10362     const int WORDS_PER_LINE = 8;
10363     for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) {
10364         out << "\t";
10365         for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) {
10366             const unsigned int word = spirv[i + j];
10367             out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word;
10368             if (i + j + 1 < (int)spirv.size()) {
10369                 out << ",";
10370             }
10371         }
10372         out << std::endl;
10373     }
10374     if (varName != nullptr) {
10375         out << "};";
10376         out << std::endl;
10377     }
10378     out.close();
10379     return true;
10380 }
10381 
10382 //
10383 // Set up the glslang traversal
10384 //
GlslangToSpv(const TIntermediate & intermediate,std::vector<unsigned int> & spirv,SpvOptions * options)10385 void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv, SpvOptions* options)
10386 {
10387     spv::SpvBuildLogger logger;
10388     GlslangToSpv(intermediate, spirv, &logger, options);
10389 }
10390 
GlslangToSpv(const TIntermediate & intermediate,std::vector<unsigned int> & spirv,spv::SpvBuildLogger * logger,SpvOptions * options)10391 void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv,
10392                   spv::SpvBuildLogger* logger, SpvOptions* options)
10393 {
10394     TIntermNode* root = intermediate.getTreeRoot();
10395 
10396     if (root == nullptr)
10397         return;
10398 
10399     SpvOptions defaultOptions;
10400     if (options == nullptr)
10401         options = &defaultOptions;
10402 
10403     GetThreadPoolAllocator().push();
10404 
10405     TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);
10406     root->traverse(&it);
10407     it.finishSpv(options->compileOnly);
10408     it.dumpSpv(spirv);
10409 
10410 #if ENABLE_OPT
10411     // If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan
10412     // eg. forward and remove memory writes of opaque types.
10413     bool prelegalization = intermediate.getSource() == EShSourceHlsl;
10414     if ((prelegalization || options->optimizeSize) && !options->disableOptimizer) {
10415         SpirvToolsTransform(intermediate, spirv, logger, options);
10416         prelegalization = false;
10417     }
10418     else if (options->stripDebugInfo) {
10419         // Strip debug info even if optimization is disabled.
10420         SpirvToolsStripDebugInfo(intermediate, spirv, logger);
10421     }
10422 
10423     if (options->validate)
10424         SpirvToolsValidate(intermediate, spirv, logger, prelegalization);
10425 
10426     if (options->disassemble)
10427         SpirvToolsDisassemble(std::cout, spirv);
10428 
10429 #endif
10430 
10431     GetThreadPoolAllocator().pop();
10432 }
10433 
10434 } // end namespace glslang
10435