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