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