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