Don't remove SPIR-V blocks before codegen.
[platform/upstream/glslang.git] / SPIRV / GlslangToSpv.cpp
1 //
2 //Copyright (C) 2014 LunarG, Inc.
3 //
4 //All rights reserved.
5 //
6 //Redistribution and use in source and binary forms, with or without
7 //modification, are permitted provided that the following conditions
8 //are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 //POSSIBILITY OF SUCH DAMAGE.
34
35 //
36 // Author: John Kessenich, LunarG
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 }
48
49 // Glslang includes
50 #include "../glslang/MachineIndependent/localintermediate.h"
51 #include "../glslang/MachineIndependent/SymbolTable.h"
52 #include "../glslang/Include/Common.h"
53
54 #include <string>
55 #include <map>
56 #include <list>
57 #include <vector>
58 #include <stack>
59 #include <fstream>
60
61 namespace {
62
63 // For low-order part of the generator's magic number. Bump up
64 // when there is a change in the style (e.g., if SSA form changes,
65 // or a different instruction sequence to do something gets used).
66 const int GeneratorVersion = 1;
67
68 //
69 // The main holder of information for translating glslang to SPIR-V.
70 //
71 // Derives from the AST walking base class.
72 //
73 class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
74 public:
75     TGlslangToSpvTraverser(const glslang::TIntermediate*);
76     virtual ~TGlslangToSpvTraverser();
77
78     bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
79     bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
80     void visitConstantUnion(glslang::TIntermConstantUnion*);
81     bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
82     bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
83     void visitSymbol(glslang::TIntermSymbol* symbol);
84     bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
85     bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
86     bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
87
88     void dumpSpv(std::vector<unsigned int>& out);
89
90 protected:
91     spv::Id createSpvVariable(const glslang::TIntermSymbol*);
92     spv::Id getSampledType(const glslang::TSampler&);
93     spv::Id convertGlslangToSpvType(const glslang::TType& type);
94     spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&);
95     glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
96     int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
97     int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
98     void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);
99
100     bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
101     void makeFunctions(const glslang::TIntermSequence&);
102     void makeGlobalInitializers(const glslang::TIntermSequence&);
103     void visitFunctions(const glslang::TIntermSequence&);
104     void handleFunctionEntry(const glslang::TIntermAggregate* node);
105     void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments);
106     void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
107     spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
108     spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
109
110     spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
111     spv::Id createBinaryMatrixOperation(spv::Op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right);
112     spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand,glslang::TBasicType typeProxy);
113     spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
114     spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
115     spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
116     spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
117     spv::Id createNoArgOperation(glslang::TOperator op);
118     spv::Id getSymbolId(const glslang::TIntermSymbol* node);
119     void addDecoration(spv::Id id, spv::Decoration dec);
120     void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
121     void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
122     spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
123     spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
124     bool isTrivialLeaf(const glslang::TIntermTyped* node);
125     bool isTrivial(const glslang::TIntermTyped* node);
126     spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
127
128     spv::Function* shaderEntry;
129     spv::Instruction* entryPoint;
130     int sequenceDepth;
131
132     // There is a 1:1 mapping between a spv builder and a module; this is thread safe
133     spv::Builder builder;
134     bool inMain;
135     bool mainTerminated;
136     bool linkageOnly;                  // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used
137     std::set<spv::Id> iOSet;           // all input/output variables from either static use or declaration of interface
138     const glslang::TIntermediate* glslangIntermediate;
139     spv::Id stdBuiltins;
140
141     std::unordered_map<int, spv::Id> symbolValues;
142     std::unordered_set<int> constReadOnlyParameters;  // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
143     std::unordered_map<std::string, spv::Function*> functionMap;
144     std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
145     std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)
146     std::stack<bool> breakForLoop;  // false means break for switch
147 };
148
149 //
150 // Helper functions for translating glslang representations to SPIR-V enumerants.
151 //
152
153 // Translate glslang profile to SPIR-V source language.
154 spv::SourceLanguage TranslateSourceLanguage(EProfile profile)
155 {
156     switch (profile) {
157     case ENoProfile:
158     case ECoreProfile:
159     case ECompatibilityProfile:
160         return spv::SourceLanguageGLSL;
161     case EEsProfile:
162         return spv::SourceLanguageESSL;
163     default:
164         return spv::SourceLanguageUnknown;
165     }
166 }
167
168 // Translate glslang language (stage) to SPIR-V execution model.
169 spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
170 {
171     switch (stage) {
172     case EShLangVertex:           return spv::ExecutionModelVertex;
173     case EShLangTessControl:      return spv::ExecutionModelTessellationControl;
174     case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;
175     case EShLangGeometry:         return spv::ExecutionModelGeometry;
176     case EShLangFragment:         return spv::ExecutionModelFragment;
177     case EShLangCompute:          return spv::ExecutionModelGLCompute;
178     default:
179         assert(0);
180         return spv::ExecutionModelFragment;
181     }
182 }
183
184 // Translate glslang type to SPIR-V storage class.
185 spv::StorageClass TranslateStorageClass(const glslang::TType& type)
186 {
187     if (type.getQualifier().isPipeInput())
188         return spv::StorageClassInput;
189     else if (type.getQualifier().isPipeOutput())
190         return spv::StorageClassOutput;
191     else if (type.getQualifier().isUniformOrBuffer()) {
192         if (type.getBasicType() == glslang::EbtBlock)
193             return spv::StorageClassUniform;
194         else if (type.getBasicType() == glslang::EbtAtomicUint)
195             return spv::StorageClassAtomicCounter;
196         else
197             return spv::StorageClassUniformConstant;
198         // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?
199     } else {
200         switch (type.getQualifier().storage) {
201         case glslang::EvqShared:        return spv::StorageClassWorkgroup;  break;
202         case glslang::EvqGlobal:        return spv::StorageClassPrivate;
203         case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
204         case glslang::EvqTemporary:     return spv::StorageClassFunction;
205         default: 
206             assert(0);
207             return spv::StorageClassFunction;
208         }
209     }
210 }
211
212 // Translate glslang sampler type to SPIR-V dimensionality.
213 spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
214 {
215     switch (sampler.dim) {
216     case glslang::Esd1D:      return spv::Dim1D;
217     case glslang::Esd2D:      return spv::Dim2D;
218     case glslang::Esd3D:      return spv::Dim3D;
219     case glslang::EsdCube:    return spv::DimCube;
220     case glslang::EsdRect:    return spv::DimRect;
221     case glslang::EsdBuffer:  return spv::DimBuffer;
222     default:
223         assert(0);
224         return spv::Dim2D;
225     }
226 }
227
228 // Translate glslang type to SPIR-V precision decorations.
229 spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
230 {
231     switch (type.getQualifier().precision) {
232     case glslang::EpqLow:    return spv::DecorationRelaxedPrecision;
233     case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
234     case glslang::EpqHigh:   return spv::NoPrecision;
235     default:
236         return spv::NoPrecision;
237     }
238 }
239
240 // Translate glslang type to SPIR-V block decorations.
241 spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
242 {
243     if (type.getBasicType() == glslang::EbtBlock) {
244         switch (type.getQualifier().storage) {
245         case glslang::EvqUniform:      return spv::DecorationBlock;
246         case glslang::EvqBuffer:       return spv::DecorationBufferBlock;
247         case glslang::EvqVaryingIn:    return spv::DecorationBlock;
248         case glslang::EvqVaryingOut:   return spv::DecorationBlock;
249         default:
250             assert(0);
251             break;
252         }
253     }
254
255     return (spv::Decoration)spv::BadValue;
256 }
257
258 // Translate glslang type to SPIR-V layout decorations.
259 spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
260 {
261     if (type.isMatrix()) {
262         switch (matrixLayout) {
263         case glslang::ElmRowMajor:
264             return spv::DecorationRowMajor;
265         case glslang::ElmColumnMajor:
266             return spv::DecorationColMajor;
267         default:
268             // opaque layouts don't need a majorness
269             return (spv::Decoration)spv::BadValue;
270         }
271     } else {
272         switch (type.getBasicType()) {
273         default:
274             return (spv::Decoration)spv::BadValue;
275             break;
276         case glslang::EbtBlock:
277             switch (type.getQualifier().storage) {
278             case glslang::EvqUniform:
279             case glslang::EvqBuffer:
280                 switch (type.getQualifier().layoutPacking) {
281                 case glslang::ElpShared:  return spv::DecorationGLSLShared;
282                 case glslang::ElpPacked:  return spv::DecorationGLSLPacked;
283                 default:
284                     return (spv::Decoration)spv::BadValue;
285                 }
286             case glslang::EvqVaryingIn:
287             case glslang::EvqVaryingOut:
288                 assert(type.getQualifier().layoutPacking == glslang::ElpNone);
289                 return (spv::Decoration)spv::BadValue;
290             default:
291                 assert(0);
292                 return (spv::Decoration)spv::BadValue;
293             }
294         }
295     }
296 }
297
298 // Translate glslang type to SPIR-V interpolation decorations.
299 // Returns spv::Decoration(spv::BadValue) when no decoration
300 // should be applied.
301 spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
302 {
303     if (qualifier.smooth) {
304         // Smooth decoration doesn't exist in SPIR-V 1.0
305         return (spv::Decoration)spv::BadValue;
306     }
307     if (qualifier.nopersp)
308         return spv::DecorationNoPerspective;
309     else if (qualifier.patch)
310         return spv::DecorationPatch;
311     else if (qualifier.flat)
312         return spv::DecorationFlat;
313     else if (qualifier.centroid)
314         return spv::DecorationCentroid;
315     else if (qualifier.sample)
316         return spv::DecorationSample;
317     else
318         return (spv::Decoration)spv::BadValue;
319 }
320
321 // If glslang type is invaraiant, return SPIR-V invariant decoration.
322 spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
323 {
324     if (qualifier.invariant)
325         return spv::DecorationInvariant;
326     else
327         return (spv::Decoration)spv::BadValue;
328 }
329
330 // Translate glslang built-in variable to SPIR-V built in decoration.
331 spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
332 {
333     switch (builtIn) {
334     case glslang::EbvPosition:             return spv::BuiltInPosition;
335     case glslang::EbvPointSize:            return spv::BuiltInPointSize;
336     case glslang::EbvClipDistance:         return spv::BuiltInClipDistance;
337     case glslang::EbvCullDistance:         return spv::BuiltInCullDistance;
338     case glslang::EbvVertexId:             return spv::BuiltInVertexId;
339     case glslang::EbvInstanceId:           return spv::BuiltInInstanceId;
340     case glslang::EbvBaseVertex:
341     case glslang::EbvBaseInstance:
342     case glslang::EbvDrawId:
343         // TODO: Add SPIR-V builtin ID.
344         spv::MissingFunctionality("Draw parameters");
345         return (spv::BuiltIn)spv::BadValue;
346     case glslang::EbvPrimitiveId:          return spv::BuiltInPrimitiveId;
347     case glslang::EbvInvocationId:         return spv::BuiltInInvocationId;
348     case glslang::EbvLayer:                return spv::BuiltInLayer;
349     case glslang::EbvViewportIndex:        return spv::BuiltInViewportIndex;
350     case glslang::EbvTessLevelInner:       return spv::BuiltInTessLevelInner;
351     case glslang::EbvTessLevelOuter:       return spv::BuiltInTessLevelOuter;
352     case glslang::EbvTessCoord:            return spv::BuiltInTessCoord;
353     case glslang::EbvPatchVertices:        return spv::BuiltInPatchVertices;
354     case glslang::EbvFragCoord:            return spv::BuiltInFragCoord;
355     case glslang::EbvPointCoord:           return spv::BuiltInPointCoord;
356     case glslang::EbvFace:                 return spv::BuiltInFrontFacing;
357     case glslang::EbvSampleId:             return spv::BuiltInSampleId;
358     case glslang::EbvSamplePosition:       return spv::BuiltInSamplePosition;
359     case glslang::EbvSampleMask:           return spv::BuiltInSampleMask;
360     case glslang::EbvFragDepth:            return spv::BuiltInFragDepth;
361     case glslang::EbvHelperInvocation:     return spv::BuiltInHelperInvocation;
362     case glslang::EbvNumWorkGroups:        return spv::BuiltInNumWorkgroups;
363     case glslang::EbvWorkGroupSize:        return spv::BuiltInWorkgroupSize;
364     case glslang::EbvWorkGroupId:          return spv::BuiltInWorkgroupId;
365     case glslang::EbvLocalInvocationId:    return spv::BuiltInLocalInvocationId;
366     case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
367     case glslang::EbvGlobalInvocationId:   return spv::BuiltInGlobalInvocationId;
368     default:                               return (spv::BuiltIn)spv::BadValue;
369     }
370 }
371
372 // Translate glslang image layout format to SPIR-V image format.
373 spv::ImageFormat TranslateImageFormat(const glslang::TType& type)
374 {
375     assert(type.getBasicType() == glslang::EbtSampler);
376
377     switch (type.getQualifier().layoutFormat) {
378     case glslang::ElfNone:          return spv::ImageFormatUnknown;
379     case glslang::ElfRgba32f:       return spv::ImageFormatRgba32f;
380     case glslang::ElfRgba16f:       return spv::ImageFormatRgba16f;
381     case glslang::ElfR32f:          return spv::ImageFormatR32f;
382     case glslang::ElfRgba8:         return spv::ImageFormatRgba8;
383     case glslang::ElfRgba8Snorm:    return spv::ImageFormatRgba8Snorm;
384     case glslang::ElfRg32f:         return spv::ImageFormatRg32f;
385     case glslang::ElfRg16f:         return spv::ImageFormatRg16f;
386     case glslang::ElfR11fG11fB10f:  return spv::ImageFormatR11fG11fB10f;
387     case glslang::ElfR16f:          return spv::ImageFormatR16f;
388     case glslang::ElfRgba16:        return spv::ImageFormatRgba16;
389     case glslang::ElfRgb10A2:       return spv::ImageFormatRgb10A2;
390     case glslang::ElfRg16:          return spv::ImageFormatRg16;
391     case glslang::ElfRg8:           return spv::ImageFormatRg8;
392     case glslang::ElfR16:           return spv::ImageFormatR16;
393     case glslang::ElfR8:            return spv::ImageFormatR8;
394     case glslang::ElfRgba16Snorm:   return spv::ImageFormatRgba16Snorm;
395     case glslang::ElfRg16Snorm:     return spv::ImageFormatRg16Snorm;
396     case glslang::ElfRg8Snorm:      return spv::ImageFormatRg8Snorm;
397     case glslang::ElfR16Snorm:      return spv::ImageFormatR16Snorm;
398     case glslang::ElfR8Snorm:       return spv::ImageFormatR8Snorm;
399     case glslang::ElfRgba32i:       return spv::ImageFormatRgba32i;
400     case glslang::ElfRgba16i:       return spv::ImageFormatRgba16i;
401     case glslang::ElfRgba8i:        return spv::ImageFormatRgba8i;
402     case glslang::ElfR32i:          return spv::ImageFormatR32i;
403     case glslang::ElfRg32i:         return spv::ImageFormatRg32i;
404     case glslang::ElfRg16i:         return spv::ImageFormatRg16i;
405     case glslang::ElfRg8i:          return spv::ImageFormatRg8i;
406     case glslang::ElfR16i:          return spv::ImageFormatR16i;
407     case glslang::ElfR8i:           return spv::ImageFormatR8i;
408     case glslang::ElfRgba32ui:      return spv::ImageFormatRgba32ui;
409     case glslang::ElfRgba16ui:      return spv::ImageFormatRgba16ui;
410     case glslang::ElfRgba8ui:       return spv::ImageFormatRgba8ui;
411     case glslang::ElfR32ui:         return spv::ImageFormatR32ui;
412     case glslang::ElfRg32ui:        return spv::ImageFormatRg32ui;
413     case glslang::ElfRg16ui:        return spv::ImageFormatRg16ui;
414     case glslang::ElfRgb10a2ui:     return spv::ImageFormatRgb10a2ui;
415     case glslang::ElfRg8ui:         return spv::ImageFormatRg8ui;
416     case glslang::ElfR16ui:         return spv::ImageFormatR16ui;
417     case glslang::ElfR8ui:          return spv::ImageFormatR8ui;
418     default:                        return (spv::ImageFormat)spv::BadValue;
419     }
420 }
421
422 void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
423 {
424     if (child.layoutMatrix == glslang::ElmNone)
425         child.layoutMatrix = parent.layoutMatrix;
426
427     if (parent.invariant)
428         child.invariant = true;
429     if (parent.nopersp)
430         child.nopersp = true;
431     if (parent.flat)
432         child.flat = true;
433     if (parent.centroid)
434         child.centroid = true;
435     if (parent.patch)
436         child.patch = true;
437     if (parent.sample)
438         child.sample = true;
439 }
440
441 bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier)
442 {
443     // This should list qualifiers that simultaneous satisify:
444     // - struct members can inherit from a struct declaration
445     // - effect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object)
446     // - are not part of the offset/st430/etc or row/column-major layout
447     return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample;
448 }
449
450 //
451 // Implement the TGlslangToSpvTraverser class.
452 //
453
454 TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
455     : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
456       builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion),
457       inMain(false), mainTerminated(false), linkageOnly(false),
458       glslangIntermediate(glslangIntermediate)
459 {
460     spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
461
462     builder.clearAccessChain();
463     builder.setSource(TranslateSourceLanguage(glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
464     stdBuiltins = builder.import("GLSL.std.450");
465     builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
466     shaderEntry = builder.makeMain();
467     entryPoint = builder.addEntryPoint(executionModel, shaderEntry, "main");
468
469     // Add the source extensions
470     const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
471     for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
472         builder.addSourceExtension(it->c_str());
473
474     // Add the top-level modes for this shader.
475
476     if (glslangIntermediate->getXfbMode())
477         builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
478
479     unsigned int mode;
480     switch (glslangIntermediate->getStage()) {
481     case EShLangVertex:
482         builder.addCapability(spv::CapabilityShader);
483         break;
484
485     case EShLangTessControl:
486         builder.addCapability(spv::CapabilityTessellation);
487         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
488         break;
489
490     case EShLangTessEvaluation:
491         builder.addCapability(spv::CapabilityTessellation);
492         switch (glslangIntermediate->getInputPrimitive()) {
493         case glslang::ElgTriangles:           mode = spv::ExecutionModeTriangles;     break;
494         case glslang::ElgQuads:               mode = spv::ExecutionModeQuads;         break;
495         case glslang::ElgIsolines:            mode = spv::ExecutionModeIsolines;      break;
496         default:                              mode = spv::BadValue;                        break;
497         }
498         if (mode != spv::BadValue)
499             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
500
501         switch (glslangIntermediate->getVertexSpacing()) {
502         case glslang::EvsEqual:            mode = spv::ExecutionModeSpacingEqual;          break;
503         case glslang::EvsFractionalEven:   mode = spv::ExecutionModeSpacingFractionalEven; break;
504         case glslang::EvsFractionalOdd:    mode = spv::ExecutionModeSpacingFractionalOdd;  break;
505         default:                           mode = spv::BadValue;                           break;
506         }
507         if (mode != spv::BadValue)
508             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
509
510         switch (glslangIntermediate->getVertexOrder()) {
511         case glslang::EvoCw:     mode = spv::ExecutionModeVertexOrderCw;  break;
512         case glslang::EvoCcw:    mode = spv::ExecutionModeVertexOrderCcw; break;
513         default:                 mode = spv::BadValue;                    break;
514         }
515         if (mode != spv::BadValue)
516             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
517
518         if (glslangIntermediate->getPointMode())
519             builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode);
520         break;
521
522     case EShLangGeometry:
523         builder.addCapability(spv::CapabilityGeometry);
524         switch (glslangIntermediate->getInputPrimitive()) {
525         case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;
526         case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;
527         case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;
528         case glslang::ElgTriangles:          mode = spv::ExecutionModeTriangles;               break;
529         case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
530         default:                             mode = spv::BadValue;         break;
531         }
532         if (mode != spv::BadValue)
533             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
534
535         builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
536
537         switch (glslangIntermediate->getOutputPrimitive()) {
538         case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;
539         case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;
540         case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;
541         default:                        mode = spv::BadValue;              break;
542         }
543         if (mode != spv::BadValue)
544             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
545         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
546         break;
547
548     case EShLangFragment:
549         builder.addCapability(spv::CapabilityShader);
550         if (glslangIntermediate->getPixelCenterInteger())
551             builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
552
553         if (glslangIntermediate->getOriginUpperLeft())
554             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
555         else
556             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);
557
558         if (glslangIntermediate->getEarlyFragmentTests())
559             builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
560
561         switch(glslangIntermediate->getDepth()) {
562         case glslang::EldGreater:  mode = spv::ExecutionModeDepthGreater; break;
563         case glslang::EldLess:     mode = spv::ExecutionModeDepthLess;    break;
564         default:                   mode = spv::BadValue;                  break;
565         }
566         if (mode != spv::BadValue)
567             builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
568
569         if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing())
570             builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);
571         break;
572
573     case EShLangCompute:
574         builder.addCapability(spv::CapabilityShader);
575         builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
576                                                                            glslangIntermediate->getLocalSize(1),
577                                                                            glslangIntermediate->getLocalSize(2));
578         break;
579
580     default:
581         break;
582     }
583
584 }
585
586 // Finish everything and dump
587 void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
588 {
589     // finish off the entry-point SPV instruction by adding the Input/Output <id>
590     for (auto it : iOSet)
591         entryPoint->addIdOperand(it);
592
593     builder.dump(out);
594 }
595
596 TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
597 {
598     if (! mainTerminated) {
599         spv::Block* lastMainBlock = shaderEntry->getLastBlock();
600         builder.setBuildPoint(lastMainBlock);
601         builder.leaveFunction();
602     }
603 }
604
605 //
606 // Implement the traversal functions.
607 //
608 // Return true from interior nodes to have the external traversal
609 // continue on to children.  Return false if children were
610 // already processed.
611 //
612
613 //
614 // Symbols can turn into 
615 //  - uniform/input reads
616 //  - output writes
617 //  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain
618 //  - something simple that degenerates into the last bullet
619 //
620 void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
621 {
622     // getSymbolId() will set up all the IO decorations on the first call.
623     // Formal function parameters were mapped during makeFunctions().
624     spv::Id id = getSymbolId(symbol);
625
626     // Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
627     if (builder.isPointer(id)) {
628         spv::StorageClass sc = builder.getStorageClass(id);
629         if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)
630             iOSet.insert(id);
631     }
632
633     // Only process non-linkage-only nodes for generating actual static uses
634     if (! linkageOnly) {
635         // Prepare to generate code for the access
636
637         // L-value chains will be computed left to right.  We're on the symbol now,
638         // which is the left-most part of the access chain, so now is "clear" time,
639         // followed by setting the base.
640         builder.clearAccessChain();
641
642         // For now, we consider all user variables as being in memory, so they are pointers,
643         // except for "const in" arguments to a function, which are an intermediate object.
644         // See comments in handleUserFunctionCall().
645         glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;
646         if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())
647             builder.setAccessChainRValue(id);
648         else
649             builder.setAccessChainLValue(id);
650     }
651 }
652
653 bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
654 {
655     // First, handle special cases
656     switch (node->getOp()) {
657     case glslang::EOpAssign:
658     case glslang::EOpAddAssign:
659     case glslang::EOpSubAssign:
660     case glslang::EOpMulAssign:
661     case glslang::EOpVectorTimesMatrixAssign:
662     case glslang::EOpVectorTimesScalarAssign:
663     case glslang::EOpMatrixTimesScalarAssign:
664     case glslang::EOpMatrixTimesMatrixAssign:
665     case glslang::EOpDivAssign:
666     case glslang::EOpModAssign:
667     case glslang::EOpAndAssign:
668     case glslang::EOpInclusiveOrAssign:
669     case glslang::EOpExclusiveOrAssign:
670     case glslang::EOpLeftShiftAssign:
671     case glslang::EOpRightShiftAssign:
672         // A bin-op assign "a += b" means the same thing as "a = a + b"
673         // where a is evaluated before b. For a simple assignment, GLSL
674         // says to evaluate the left before the right.  So, always, left
675         // node then right node.
676         {
677             // get the left l-value, save it away
678             builder.clearAccessChain();
679             node->getLeft()->traverse(this);
680             spv::Builder::AccessChain lValue = builder.getAccessChain();
681
682             // evaluate the right
683             builder.clearAccessChain();
684             node->getRight()->traverse(this);
685             spv::Id rValue = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
686
687             if (node->getOp() != glslang::EOpAssign) {
688                 // the left is also an r-value
689                 builder.setAccessChain(lValue);
690                 spv::Id leftRValue = builder.accessChainLoad(convertGlslangToSpvType(node->getLeft()->getType()));
691
692                 // do the operation
693                 rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), 
694                                                convertGlslangToSpvType(node->getType()), leftRValue, rValue,
695                                                node->getType().getBasicType());
696
697                 // these all need their counterparts in createBinaryOperation()
698                 assert(rValue != spv::NoResult);
699             }
700
701             // store the result
702             builder.setAccessChain(lValue);
703             builder.accessChainStore(rValue);
704
705             // assignments are expressions having an rValue after they are evaluated...
706             builder.clearAccessChain();
707             builder.setAccessChainRValue(rValue);
708         }
709         return false;
710     case glslang::EOpIndexDirect:
711     case glslang::EOpIndexDirectStruct:
712         {
713             // Get the left part of the access chain.
714             node->getLeft()->traverse(this);
715
716             // Add the next element in the chain
717
718             int index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
719             if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
720                 // This may be, e.g., an anonymous block-member selection, which generally need
721                 // index remapping due to hidden members in anonymous blocks.
722                 std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
723                 assert(remapper.size() > 0);
724                 index = remapper[index];
725             }
726
727             if (! node->getLeft()->getType().isArray() &&
728                 node->getLeft()->getType().isVector() &&
729                 node->getOp() == glslang::EOpIndexDirect) {
730                 // This is essentially a hard-coded vector swizzle of size 1,
731                 // so short circuit the access-chain stuff with a swizzle.
732                 std::vector<unsigned> swizzle;
733                 swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());
734                 builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
735             } else {
736                 // normal case for indexing array or structure or block
737                 builder.accessChainPush(builder.makeIntConstant(index));
738             }
739         }
740         return false;
741     case glslang::EOpIndexIndirect:
742         {
743             // Structure or array or vector indirection.
744             // Will use native SPIR-V access-chain for struct and array indirection;
745             // matrices are arrays of vectors, so will also work for a matrix.
746             // Will use the access chain's 'component' for variable index into a vector.
747
748             // This adapter is building access chains left to right.
749             // Set up the access chain to the left.
750             node->getLeft()->traverse(this);
751
752             // save it so that computing the right side doesn't trash it
753             spv::Builder::AccessChain partial = builder.getAccessChain();
754
755             // compute the next index in the chain
756             builder.clearAccessChain();
757             node->getRight()->traverse(this);
758             spv::Id index = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
759
760             // restore the saved access chain
761             builder.setAccessChain(partial);
762
763             if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
764                 builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()));
765             else
766                 builder.accessChainPush(index);
767         }
768         return false;
769     case glslang::EOpVectorSwizzle:
770         {
771             node->getLeft()->traverse(this);
772             glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();
773             std::vector<unsigned> swizzle;
774             for (int i = 0; i < (int)swizzleSequence.size(); ++i)
775                 swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
776             builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
777         }
778         return false;
779     case glslang::EOpLogicalOr:
780     case glslang::EOpLogicalAnd:
781         {
782
783             // These may require short circuiting, but can sometimes be done as straight
784             // binary operations.  The right operand must be short circuited if it has
785             // side effects, and should probably be if it is complex.
786             if (isTrivial(node->getRight()->getAsTyped()))
787                 break; // handle below as a normal binary operation
788             // otherwise, we need to do dynamic short circuiting on the right operand
789             spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), *node->getRight()->getAsTyped());
790             builder.clearAccessChain();
791             builder.setAccessChainRValue(result);
792         }
793         return false;
794     default:
795         break;
796     }
797
798     // Assume generic binary op...
799
800     // Get the operands
801     builder.clearAccessChain();
802     node->getLeft()->traverse(this);
803     spv::Id left = builder.accessChainLoad(convertGlslangToSpvType(node->getLeft()->getType()));
804
805     builder.clearAccessChain();
806     node->getRight()->traverse(this);
807     spv::Id right = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
808
809     spv::Id result;
810     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
811
812     result = createBinaryOperation(node->getOp(), precision, 
813                                    convertGlslangToSpvType(node->getType()), left, right,
814                                    node->getLeft()->getType().getBasicType());
815
816     builder.clearAccessChain();
817     if (! result) {
818         spv::MissingFunctionality("unknown glslang binary operation");
819         return true;  // pick up a child as the place-holder result
820     } else {
821         builder.setAccessChainRValue(result);
822         return false;
823     }
824 }
825
826 bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
827 {
828     spv::Id result = spv::NoResult;
829
830     // try texturing first
831     result = createImageTextureFunctionCall(node);
832     if (result != spv::NoResult) {
833         builder.clearAccessChain();
834         builder.setAccessChainRValue(result);
835
836         return false; // done with this node
837     }
838
839     // Non-texturing.
840
841     if (node->getOp() == glslang::EOpArrayLength) {
842         // Quite special; won't want to evaluate the operand.
843
844         // Normal .length() would have been constant folded by the front-end.
845         // So, this has to be block.lastMember.length().
846         // SPV wants "block" and member number as the operands, go get them.
847         assert(node->getOperand()->getType().isRuntimeSizedArray());
848         glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
849         block->traverse(this);
850         unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst();
851         spv::Id length = builder.createArrayLength(builder.accessChainGetLValue(), member);
852
853         builder.clearAccessChain();
854         builder.setAccessChainRValue(length);
855
856         return false;
857     }
858
859     // Start by evaluating the operand
860
861     builder.clearAccessChain();
862     node->getOperand()->traverse(this);
863
864     spv::Id operand = spv::NoResult;
865
866     if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
867         node->getOp() == glslang::EOpAtomicCounterDecrement ||
868         node->getOp() == glslang::EOpAtomicCounter          ||
869         node->getOp() == glslang::EOpInterpolateAtCentroid)
870         operand = builder.accessChainGetLValue(); // Special case l-value operands
871     else
872         operand = builder.accessChainLoad(convertGlslangToSpvType(node->getOperand()->getType()));
873
874     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
875
876     // it could be a conversion
877     if (! result)
878         result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);
879
880     // if not, then possibly an operation
881     if (! result)
882         result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
883
884     if (result) {
885         builder.clearAccessChain();
886         builder.setAccessChainRValue(result);
887
888         return false; // done with this node
889     }
890
891     // it must be a special case, check...
892     switch (node->getOp()) {
893     case glslang::EOpPostIncrement:
894     case glslang::EOpPostDecrement:
895     case glslang::EOpPreIncrement:
896     case glslang::EOpPreDecrement:
897         {
898             // we need the integer value "1" or the floating point "1.0" to add/subtract
899             spv::Id one = node->getBasicType() == glslang::EbtFloat ?
900                                      builder.makeFloatConstant(1.0F) :
901                                      builder.makeIntConstant(1);
902             glslang::TOperator op;
903             if (node->getOp() == glslang::EOpPreIncrement ||
904                 node->getOp() == glslang::EOpPostIncrement)
905                 op = glslang::EOpAdd;
906             else
907                 op = glslang::EOpSub;
908
909             spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), 
910                                                      convertGlslangToSpvType(node->getType()), operand, one, 
911                                                      node->getType().getBasicType());
912             assert(result != spv::NoResult);
913
914             // The result of operation is always stored, but conditionally the
915             // consumed result.  The consumed result is always an r-value.
916             builder.accessChainStore(result);
917             builder.clearAccessChain();
918             if (node->getOp() == glslang::EOpPreIncrement ||
919                 node->getOp() == glslang::EOpPreDecrement)
920                 builder.setAccessChainRValue(result);
921             else
922                 builder.setAccessChainRValue(operand);
923         }
924
925         return false;
926
927     case glslang::EOpEmitStreamVertex:
928         builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
929         return false;
930     case glslang::EOpEndStreamPrimitive:
931         builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
932         return false;
933
934     default:
935         spv::MissingFunctionality("unknown glslang unary");
936         return true;  // pick up operand as placeholder result
937     }
938 }
939
940 bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
941 {
942     spv::Id result = spv::NoResult;
943
944     // try texturing
945     result = createImageTextureFunctionCall(node);
946     if (result != spv::NoResult) {
947         builder.clearAccessChain();
948         builder.setAccessChainRValue(result);
949
950         return false;
951     } else if (node->getOp() == glslang::EOpImageStore) {
952         // "imageStore" is a special case, which has no result
953         return false;
954     }
955
956     glslang::TOperator binOp = glslang::EOpNull;
957     bool reduceComparison = true;
958     bool isMatrix = false;
959     bool noReturnValue = false;
960     bool atomic = false;
961
962     assert(node->getOp());
963
964     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
965
966     switch (node->getOp()) {
967     case glslang::EOpSequence:
968     {
969         if (preVisit)
970             ++sequenceDepth;
971         else
972             --sequenceDepth;
973
974         if (sequenceDepth == 1) {
975             // If this is the parent node of all the functions, we want to see them
976             // early, so all call points have actual SPIR-V functions to reference.
977             // In all cases, still let the traverser visit the children for us.
978             makeFunctions(node->getAsAggregate()->getSequence());
979
980             // Also, we want all globals initializers to go into the entry of main(), before
981             // anything else gets there, so visit out of order, doing them all now.
982             makeGlobalInitializers(node->getAsAggregate()->getSequence());
983
984             // Initializers are done, don't want to visit again, but functions link objects need to be processed,
985             // so do them manually.
986             visitFunctions(node->getAsAggregate()->getSequence());
987
988             return false;
989         }
990
991         return true;
992     }
993     case glslang::EOpLinkerObjects:
994     {
995         if (visit == glslang::EvPreVisit)
996             linkageOnly = true;
997         else
998             linkageOnly = false;
999
1000         return true;
1001     }
1002     case glslang::EOpComma:
1003     {
1004         // processing from left to right naturally leaves the right-most
1005         // lying around in the access chain
1006         glslang::TIntermSequence& glslangOperands = node->getSequence();
1007         for (int i = 0; i < (int)glslangOperands.size(); ++i)
1008             glslangOperands[i]->traverse(this);
1009
1010         return false;
1011     }
1012     case glslang::EOpFunction:
1013         if (visit == glslang::EvPreVisit) {
1014             if (isShaderEntrypoint(node)) {
1015                 inMain = true;
1016                 builder.setBuildPoint(shaderEntry->getLastBlock());
1017             } else {
1018                 handleFunctionEntry(node);
1019             }
1020         } else {
1021             if (inMain)
1022                 mainTerminated = true;
1023             builder.leaveFunction();
1024             inMain = false;
1025         }
1026
1027         return true;
1028     case glslang::EOpParameters:
1029         // Parameters will have been consumed by EOpFunction processing, but not
1030         // the body, so we still visited the function node's children, making this
1031         // child redundant.
1032         return false;
1033     case glslang::EOpFunctionCall:
1034     {
1035         if (node->isUserDefined())
1036             result = handleUserFunctionCall(node);
1037         assert(result);
1038         builder.clearAccessChain();
1039         builder.setAccessChainRValue(result);
1040
1041         return false;
1042     }
1043     case glslang::EOpConstructMat2x2:
1044     case glslang::EOpConstructMat2x3:
1045     case glslang::EOpConstructMat2x4:
1046     case glslang::EOpConstructMat3x2:
1047     case glslang::EOpConstructMat3x3:
1048     case glslang::EOpConstructMat3x4:
1049     case glslang::EOpConstructMat4x2:
1050     case glslang::EOpConstructMat4x3:
1051     case glslang::EOpConstructMat4x4:
1052     case glslang::EOpConstructDMat2x2:
1053     case glslang::EOpConstructDMat2x3:
1054     case glslang::EOpConstructDMat2x4:
1055     case glslang::EOpConstructDMat3x2:
1056     case glslang::EOpConstructDMat3x3:
1057     case glslang::EOpConstructDMat3x4:
1058     case glslang::EOpConstructDMat4x2:
1059     case glslang::EOpConstructDMat4x3:
1060     case glslang::EOpConstructDMat4x4:
1061         isMatrix = true;
1062         // fall through
1063     case glslang::EOpConstructFloat:
1064     case glslang::EOpConstructVec2:
1065     case glslang::EOpConstructVec3:
1066     case glslang::EOpConstructVec4:
1067     case glslang::EOpConstructDouble:
1068     case glslang::EOpConstructDVec2:
1069     case glslang::EOpConstructDVec3:
1070     case glslang::EOpConstructDVec4:
1071     case glslang::EOpConstructBool:
1072     case glslang::EOpConstructBVec2:
1073     case glslang::EOpConstructBVec3:
1074     case glslang::EOpConstructBVec4:
1075     case glslang::EOpConstructInt:
1076     case glslang::EOpConstructIVec2:
1077     case glslang::EOpConstructIVec3:
1078     case glslang::EOpConstructIVec4:
1079     case glslang::EOpConstructUint:
1080     case glslang::EOpConstructUVec2:
1081     case glslang::EOpConstructUVec3:
1082     case glslang::EOpConstructUVec4:
1083     case glslang::EOpConstructStruct:
1084     {
1085         std::vector<spv::Id> arguments;
1086         translateArguments(*node, arguments);
1087         spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
1088         spv::Id constructed;
1089         if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
1090             std::vector<spv::Id> constituents;
1091             for (int c = 0; c < (int)arguments.size(); ++c)
1092                 constituents.push_back(arguments[c]);
1093             constructed = builder.createCompositeConstruct(resultTypeId, constituents);
1094         } else if (isMatrix)
1095             constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
1096         else
1097             constructed = builder.createConstructor(precision, arguments, resultTypeId);
1098
1099         builder.clearAccessChain();
1100         builder.setAccessChainRValue(constructed);
1101
1102         return false;
1103     }
1104
1105     // These six are component-wise compares with component-wise results.
1106     // Forward on to createBinaryOperation(), requesting a vector result.
1107     case glslang::EOpLessThan:
1108     case glslang::EOpGreaterThan:
1109     case glslang::EOpLessThanEqual:
1110     case glslang::EOpGreaterThanEqual:
1111     case glslang::EOpVectorEqual:
1112     case glslang::EOpVectorNotEqual:
1113     {
1114         // Map the operation to a binary
1115         binOp = node->getOp();
1116         reduceComparison = false;
1117         switch (node->getOp()) {
1118         case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;
1119         case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;
1120         default:                          binOp = node->getOp();                break;
1121         }
1122
1123         break;
1124     }
1125     case glslang::EOpMul:
1126         // compontent-wise matrix multiply      
1127         binOp = glslang::EOpMul;
1128         break;
1129     case glslang::EOpOuterProduct:
1130         // two vectors multiplied to make a matrix
1131         binOp = glslang::EOpOuterProduct;
1132         break;
1133     case glslang::EOpDot:
1134     {
1135         // for scalar dot product, use multiply        
1136         glslang::TIntermSequence& glslangOperands = node->getSequence();
1137         if (! glslangOperands[0]->getAsTyped()->isVector())
1138             binOp = glslang::EOpMul;
1139         break;
1140     }
1141     case glslang::EOpMod:
1142         // when an aggregate, this is the floating-point mod built-in function,
1143         // which can be emitted by the one in createBinaryOperation()
1144         binOp = glslang::EOpMod;
1145         break;
1146     case glslang::EOpEmitVertex:
1147     case glslang::EOpEndPrimitive:
1148     case glslang::EOpBarrier:
1149     case glslang::EOpMemoryBarrier:
1150     case glslang::EOpMemoryBarrierAtomicCounter:
1151     case glslang::EOpMemoryBarrierBuffer:
1152     case glslang::EOpMemoryBarrierImage:
1153     case glslang::EOpMemoryBarrierShared:
1154     case glslang::EOpGroupMemoryBarrier:
1155         noReturnValue = true;
1156         // These all have 0 operands and will naturally finish up in the code below for 0 operands
1157         break;
1158
1159     case glslang::EOpAtomicAdd:
1160     case glslang::EOpAtomicMin:
1161     case glslang::EOpAtomicMax:
1162     case glslang::EOpAtomicAnd:
1163     case glslang::EOpAtomicOr:
1164     case glslang::EOpAtomicXor:
1165     case glslang::EOpAtomicExchange:
1166     case glslang::EOpAtomicCompSwap:
1167         atomic = true;
1168         break;
1169
1170     default:
1171         break;
1172     }
1173
1174     //
1175     // See if it maps to a regular operation.
1176     //
1177     if (binOp != glslang::EOpNull) {
1178         glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
1179         glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
1180         assert(left && right);
1181
1182         builder.clearAccessChain();
1183         left->traverse(this);
1184         spv::Id leftId = builder.accessChainLoad(convertGlslangToSpvType(left->getType()));
1185
1186         builder.clearAccessChain();
1187         right->traverse(this);
1188         spv::Id rightId = builder.accessChainLoad(convertGlslangToSpvType(right->getType()));
1189
1190         result = createBinaryOperation(binOp, precision, 
1191                                        convertGlslangToSpvType(node->getType()), leftId, rightId, 
1192                                        left->getType().getBasicType(), reduceComparison);
1193
1194         // code above should only make binOp that exists in createBinaryOperation
1195         assert(result != spv::NoResult);
1196         builder.clearAccessChain();
1197         builder.setAccessChainRValue(result);
1198
1199         return false;
1200     }
1201
1202     //
1203     // Create the list of operands.
1204     //
1205     glslang::TIntermSequence& glslangOperands = node->getSequence();
1206     std::vector<spv::Id> operands;
1207     for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
1208         builder.clearAccessChain();
1209         glslangOperands[arg]->traverse(this);
1210
1211         // special case l-value operands; there are just a few
1212         bool lvalue = false;
1213         switch (node->getOp()) {
1214         case glslang::EOpFrexp:
1215         case glslang::EOpModf:
1216             if (arg == 1)
1217                 lvalue = true;
1218             break;
1219         case glslang::EOpInterpolateAtSample:
1220         case glslang::EOpInterpolateAtOffset:
1221             if (arg == 0)
1222                 lvalue = true;
1223             break;
1224         case glslang::EOpAtomicAdd:
1225         case glslang::EOpAtomicMin:
1226         case glslang::EOpAtomicMax:
1227         case glslang::EOpAtomicAnd:
1228         case glslang::EOpAtomicOr:
1229         case glslang::EOpAtomicXor:
1230         case glslang::EOpAtomicExchange:
1231         case glslang::EOpAtomicCompSwap:
1232             if (arg == 0)
1233                 lvalue = true;
1234             break;
1235         case glslang::EOpAddCarry:
1236         case glslang::EOpSubBorrow:
1237             if (arg == 2)
1238                 lvalue = true;
1239             break;
1240         case glslang::EOpUMulExtended:
1241         case glslang::EOpIMulExtended:
1242             if (arg >= 2)
1243                 lvalue = true;
1244             break;
1245         default:
1246             break;
1247         }
1248         if (lvalue)
1249             operands.push_back(builder.accessChainGetLValue());
1250         else
1251             operands.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangOperands[arg]->getAsTyped()->getType())));
1252     }
1253
1254     if (atomic) {
1255         // Handle all atomics
1256         result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
1257     } else {
1258         // Pass through to generic operations.
1259         switch (glslangOperands.size()) {
1260         case 0:
1261             result = createNoArgOperation(node->getOp());
1262             break;
1263         case 1:
1264             result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType());
1265             break;
1266         default:
1267             result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
1268             break;
1269         }
1270     }
1271
1272     if (noReturnValue)
1273         return false;
1274
1275     if (! result) {
1276         spv::MissingFunctionality("unknown glslang aggregate");
1277         return true;  // pick up a child as a placeholder operand
1278     } else {
1279         builder.clearAccessChain();
1280         builder.setAccessChainRValue(result);
1281         return false;
1282     }
1283 }
1284
1285 bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
1286 {
1287     // This path handles both if-then-else and ?:
1288     // The if-then-else has a node type of void, while
1289     // ?: has a non-void node type
1290     spv::Id result = 0;
1291     if (node->getBasicType() != glslang::EbtVoid) {
1292         // don't handle this as just on-the-fly temporaries, because there will be two names
1293         // and better to leave SSA to later passes
1294         result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
1295     }
1296
1297     // emit the condition before doing anything with selection
1298     node->getCondition()->traverse(this);
1299
1300     // make an "if" based on the value created by the condition
1301     spv::Builder::If ifBuilder(builder.accessChainLoad(convertGlslangToSpvType(node->getCondition()->getType())), builder);
1302
1303     if (node->getTrueBlock()) {
1304         // emit the "then" statement
1305         node->getTrueBlock()->traverse(this);
1306         if (result)
1307             builder.createStore(builder.accessChainLoad(convertGlslangToSpvType(node->getTrueBlock()->getAsTyped()->getType())), result);
1308     }
1309
1310     if (node->getFalseBlock()) {
1311         ifBuilder.makeBeginElse();
1312         // emit the "else" statement
1313         node->getFalseBlock()->traverse(this);
1314         if (result)
1315             builder.createStore(builder.accessChainLoad(convertGlslangToSpvType(node->getFalseBlock()->getAsTyped()->getType())), result);
1316     }
1317
1318     ifBuilder.makeEndIf();
1319
1320     if (result) {
1321         // GLSL only has r-values as the result of a :?, but
1322         // if we have an l-value, that can be more efficient if it will
1323         // become the base of a complex r-value expression, because the
1324         // next layer copies r-values into memory to use the access-chain mechanism
1325         builder.clearAccessChain();
1326         builder.setAccessChainLValue(result);
1327     }
1328
1329     return false;
1330 }
1331
1332 bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
1333 {
1334     // emit and get the condition before doing anything with switch
1335     node->getCondition()->traverse(this);
1336     spv::Id selector = builder.accessChainLoad(convertGlslangToSpvType(node->getCondition()->getAsTyped()->getType()));
1337
1338     // browse the children to sort out code segments
1339     int defaultSegment = -1;
1340     std::vector<TIntermNode*> codeSegments;
1341     glslang::TIntermSequence& sequence = node->getBody()->getSequence();
1342     std::vector<int> caseValues;
1343     std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate
1344     for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
1345         TIntermNode* child = *c;
1346         if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
1347             defaultSegment = (int)codeSegments.size();
1348         else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
1349             valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
1350             caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
1351         } else
1352             codeSegments.push_back(child);
1353     }
1354
1355     // handle the case where the last code segment is missing, due to no code 
1356     // statements between the last case and the end of the switch statement
1357     if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
1358         (int)codeSegments.size() == defaultSegment)
1359         codeSegments.push_back(nullptr);
1360
1361     // make the switch statement
1362     std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
1363     builder.makeSwitch(selector, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
1364
1365     // emit all the code in the segments
1366     breakForLoop.push(false);
1367     for (unsigned int s = 0; s < codeSegments.size(); ++s) {
1368         builder.nextSwitchSegment(segmentBlocks, s);
1369         if (codeSegments[s])
1370             codeSegments[s]->traverse(this);
1371         else
1372             builder.addSwitchBreak();
1373     }
1374     breakForLoop.pop();
1375
1376     builder.endSwitch(segmentBlocks);
1377
1378     return false;
1379 }
1380
1381 void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
1382 {
1383     int nextConst = 0;
1384     spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
1385
1386     builder.clearAccessChain();
1387     builder.setAccessChainRValue(constant);
1388 }
1389
1390 bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
1391 {
1392     auto blocks = builder.makeNewLoop();
1393     builder.createBranch(&blocks.head);
1394     if (node->testFirst() && node->getTest()) {
1395         builder.setBuildPoint(&blocks.head);
1396         node->getTest()->traverse(this);
1397         spv::Id condition =
1398             builder.accessChainLoad(convertGlslangToSpvType(node->getTest()->getType()));
1399         builder.createLoopMerge(&blocks.merge, &blocks.continue_target, spv::LoopControlMaskNone);
1400         builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
1401
1402         builder.setBuildPoint(&blocks.body);
1403         breakForLoop.push(true);
1404         if (node->getBody())
1405             node->getBody()->traverse(this);
1406         builder.createBranch(&blocks.continue_target);
1407         breakForLoop.pop();
1408
1409         builder.setBuildPoint(&blocks.continue_target);
1410         if (node->getTerminal())
1411             node->getTerminal()->traverse(this);
1412         builder.createBranch(&blocks.head);
1413     } else {
1414         // Spec requires back edges to target header blocks, and every header
1415         // block must dominate its merge block.  Make a header block first to
1416         // ensure these conditions are met.  By definition, it will contain
1417         // OpLoopMerge, followed by a block-ending branch.  But we don't want to
1418         // put any other body instructions in it, since the body may have
1419         // arbitrary instructions, including merges of its own.
1420         builder.setBuildPoint(&blocks.head);
1421         builder.createLoopMerge(&blocks.merge, &blocks.continue_target, spv::LoopControlMaskNone);
1422         builder.createBranch(&blocks.body);
1423
1424         breakForLoop.push(true);
1425         builder.setBuildPoint(&blocks.body);
1426         if (node->getBody())
1427             node->getBody()->traverse(this);
1428         builder.createBranch(&blocks.continue_target);
1429         breakForLoop.pop();
1430
1431         builder.setBuildPoint(&blocks.continue_target);
1432         if (node->getTerminal())
1433             node->getTerminal()->traverse(this);
1434         if (node->getTest()) {
1435             node->getTest()->traverse(this);
1436             spv::Id condition =
1437                 builder.accessChainLoad(convertGlslangToSpvType(node->getTest()->getType()));
1438             builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
1439         } else {
1440             // TODO: unless there was a break/return/discard instruction
1441             // somewhere in the body, this is an infinite loop, so we should
1442             // issue a warning.
1443             builder.createBranch(&blocks.head);
1444         }
1445     }
1446     builder.setBuildPoint(&blocks.merge);
1447     builder.closeLoop();
1448     return false;
1449 }
1450
1451 bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
1452 {
1453     if (node->getExpression())
1454         node->getExpression()->traverse(this);
1455
1456     switch (node->getFlowOp()) {
1457     case glslang::EOpKill:
1458         builder.makeDiscard();
1459         break;
1460     case glslang::EOpBreak:
1461         if (breakForLoop.top())
1462             builder.createLoopExit();
1463         else
1464             builder.addSwitchBreak();
1465         break;
1466     case glslang::EOpContinue:
1467         builder.createLoopContinue();
1468         break;
1469     case glslang::EOpReturn:
1470         if (node->getExpression())
1471             builder.makeReturn(false, builder.accessChainLoad(convertGlslangToSpvType(node->getExpression()->getType())));
1472         else
1473             builder.makeReturn(false);
1474
1475         builder.clearAccessChain();
1476         break;
1477
1478     default:
1479         assert(0);
1480         break;
1481     }
1482
1483     return false;
1484 }
1485
1486 spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
1487 {
1488     // First, steer off constants, which are not SPIR-V variables, but 
1489     // can still have a mapping to a SPIR-V Id.
1490     // This includes specialization constants.
1491     if (node->getQualifier().storage == glslang::EvqConst) {
1492         return createSpvSpecConstant(*node);
1493     }
1494
1495     // Now, handle actual variables
1496     spv::StorageClass storageClass = TranslateStorageClass(node->getType());
1497     spv::Id spvType = convertGlslangToSpvType(node->getType());
1498
1499     const char* name = node->getName().c_str();
1500     if (glslang::IsAnonymous(name))
1501         name = "";
1502
1503     return builder.createVariable(storageClass, spvType, name);
1504 }
1505
1506 // Return type Id of the sampled type.
1507 spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
1508 {
1509     switch (sampler.type) {
1510         case glslang::EbtFloat:    return builder.makeFloatType(32);
1511         case glslang::EbtInt:      return builder.makeIntType(32);
1512         case glslang::EbtUint:     return builder.makeUintType(32);
1513         default:
1514             assert(0);
1515             return builder.makeFloatType(32);
1516     }
1517 }
1518
1519 // Convert from a glslang type to an SPV type, by calling into a
1520 // recursive version of this function. This establishes the inherited
1521 // layout state rooted from the top-level type.
1522 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
1523 {
1524     return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier());
1525 }
1526
1527 // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
1528 // explicitLayout can be kept the same throughout the heirarchical recursive walk.
1529 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier)
1530 {
1531     spv::Id spvType = spv::NoResult;
1532
1533     switch (type.getBasicType()) {
1534     case glslang::EbtVoid:
1535         spvType = builder.makeVoidType();
1536         assert (! type.isArray());
1537         break;
1538     case glslang::EbtFloat:
1539         spvType = builder.makeFloatType(32);
1540         break;
1541     case glslang::EbtDouble:
1542         spvType = builder.makeFloatType(64);
1543         break;
1544     case glslang::EbtBool:
1545         spvType = builder.makeBoolType();
1546         break;
1547     case glslang::EbtInt:
1548         spvType = builder.makeIntType(32);
1549         break;
1550     case glslang::EbtUint:
1551         spvType = builder.makeUintType(32);
1552         break;
1553     case glslang::EbtAtomicUint:
1554         spv::TbdFunctionality("Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?");
1555         spvType = builder.makeUintType(32);
1556         break;
1557     case glslang::EbtSampler:
1558         {
1559             const glslang::TSampler& sampler = type.getSampler();
1560             // an image is present, make its type
1561             spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
1562                                             sampler.image ? 2 : 1, TranslateImageFormat(type));
1563             if (! sampler.image) {
1564                 spvType = builder.makeSampledImageType(spvType);
1565             }
1566         }
1567         break;
1568     case glslang::EbtStruct:
1569     case glslang::EbtBlock:
1570         {
1571             // If we've seen this struct type, return it
1572             const glslang::TTypeList* glslangStruct = type.getStruct();
1573             std::vector<spv::Id> structFields;
1574
1575             // Try to share structs for different layouts, but not yet for other
1576             // kinds of qualification (primarily not yet including interpolant qualification).
1577             if (! HasNonLayoutQualifiers(qualifier))
1578                 spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangStruct];
1579             if (spvType != spv::NoResult)
1580                 break;
1581
1582             // else, we haven't seen it...
1583
1584             // Create a vector of struct types for SPIR-V to consume
1585             int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
1586             if (type.getBasicType() == glslang::EbtBlock)
1587                 memberRemapper[glslangStruct].resize(glslangStruct->size());
1588             for (int i = 0; i < (int)glslangStruct->size(); i++) {
1589                 glslang::TType& glslangType = *(*glslangStruct)[i].type;
1590                 if (glslangType.hiddenMember()) {
1591                     ++memberDelta;
1592                     if (type.getBasicType() == glslang::EbtBlock)
1593                         memberRemapper[glslangStruct][i] = -1;
1594                 } else {
1595                     if (type.getBasicType() == glslang::EbtBlock)
1596                         memberRemapper[glslangStruct][i] = i - memberDelta;
1597                     // modify just this child's view of the qualifier
1598                     glslang::TQualifier subQualifier = glslangType.getQualifier();
1599                     InheritQualifiers(subQualifier, qualifier);
1600                     structFields.push_back(convertGlslangToSpvType(glslangType, explicitLayout, subQualifier));
1601                 }
1602             }
1603
1604             // Make the SPIR-V type
1605             spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
1606             if (! HasNonLayoutQualifiers(qualifier))
1607                 structMap[explicitLayout][qualifier.layoutMatrix][glslangStruct] = spvType;
1608
1609             // Name and decorate the non-hidden members
1610             int offset = -1;
1611             for (int i = 0; i < (int)glslangStruct->size(); i++) {
1612                 glslang::TType& glslangType = *(*glslangStruct)[i].type;
1613                 int member = i;
1614                 if (type.getBasicType() == glslang::EbtBlock)
1615                     member = memberRemapper[glslangStruct][i];
1616
1617                 // modify just this child's view of the qualifier
1618                 glslang::TQualifier subQualifier = glslangType.getQualifier();
1619                 InheritQualifiers(subQualifier, qualifier);
1620
1621                 // using -1 above to indicate a hidden member
1622                 if (member >= 0) {
1623                     builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());
1624                     addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType, subQualifier.layoutMatrix));
1625                     addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));
1626                     addMemberDecoration(spvType, member, TranslateInterpolationDecoration(subQualifier));
1627                     addMemberDecoration(spvType, member, TranslateInvariantDecoration(subQualifier));
1628                     if (glslangType.getQualifier().hasLocation())
1629                         builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);
1630                     if (glslangType.getQualifier().hasComponent())
1631                         builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
1632                     if (glslangType.getQualifier().hasXfbOffset())
1633                         builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
1634                     else if (explicitLayout != glslang::ElpNone) {
1635                         // figure out what to do with offset, which is accumulating
1636                         int nextOffset;
1637                         updateMemberOffset(type, glslangType, offset, nextOffset, explicitLayout, subQualifier.layoutMatrix);
1638                         if (offset >= 0)
1639                             builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
1640                         offset = nextOffset;
1641                     }
1642
1643                     if (glslangType.isMatrix() && explicitLayout != glslang::ElpNone)
1644                         builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType, explicitLayout, subQualifier.layoutMatrix));
1645
1646                     // built-in variable decorations
1647                     spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
1648                     if (builtIn != spv::BadValue)
1649                         builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
1650                 }
1651             }
1652
1653             // Decorate the structure
1654             addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
1655             addDecoration(spvType, TranslateBlockDecoration(type));
1656             if (type.getQualifier().hasStream())
1657                 builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
1658             if (glslangIntermediate->getXfbMode()) {
1659                 if (type.getQualifier().hasXfbStride())
1660                     builder.addDecoration(spvType, spv::DecorationXfbStride, type.getQualifier().layoutXfbStride);
1661                 if (type.getQualifier().hasXfbBuffer())
1662                     builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
1663             }
1664         }
1665         break;
1666     default:
1667         assert(0);
1668         break;
1669     }
1670
1671     if (type.isMatrix())
1672         spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
1673     else {
1674         // If this variable has a vector element count greater than 1, create a SPIR-V vector
1675         if (type.getVectorSize() > 1)
1676             spvType = builder.makeVectorType(spvType, type.getVectorSize());
1677     }
1678
1679     if (type.isArray()) {
1680         int stride = 0;  // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
1681
1682         // Do all but the outer dimension
1683         if (type.getArraySizes()->getNumDims() > 1) {
1684             // We need to decorate array strides for types needing explicit layout, except blocks.
1685             if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {
1686                 // Use a dummy glslang type for querying internal strides of
1687                 // arrays of arrays, but using just a one-dimensional array.
1688                 glslang::TType simpleArrayType(type, 0); // deference type of the array
1689                 while (simpleArrayType.getArraySizes().getNumDims() > 1)
1690                     simpleArrayType.getArraySizes().dereference();
1691
1692                 // Will compute the higher-order strides here, rather than making a whole
1693                 // pile of types and doing repetitive recursion on their contents.
1694                 stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);
1695             }
1696
1697             // make the arrays
1698             for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
1699                 int size = type.getArraySizes()->getDimSize(dim);
1700                 assert(size > 0);
1701                 spvType = builder.makeArrayType(spvType, size, stride);
1702                 if (stride > 0)
1703                     builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
1704                 stride *= size;
1705             }
1706         } else {
1707             // single-dimensional array, and don't yet have stride
1708
1709             // We need to decorate array strides for types needing explicit layout, except blocks.
1710             if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)
1711                 stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);
1712         }
1713
1714         // Do the outer dimension, which might not be known for a runtime-sized array
1715         if (type.isRuntimeSizedArray()) {
1716             spvType = builder.makeRuntimeArray(spvType);
1717         } else {
1718             assert(type.getOuterArraySize() > 0);
1719             spvType = builder.makeArrayType(spvType, type.getOuterArraySize(), stride);
1720         }
1721         if (stride > 0)
1722             builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
1723     }
1724
1725     return spvType;
1726 }
1727
1728 // Decide whether or not this type should be
1729 // decorated with offsets and strides, and if so
1730 // whether std140 or std430 rules should be applied.
1731 glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
1732 {
1733     // has to be a block
1734     if (type.getBasicType() != glslang::EbtBlock)
1735         return glslang::ElpNone;
1736
1737     // has to be a uniform or buffer block
1738     if (type.getQualifier().storage != glslang::EvqUniform &&
1739         type.getQualifier().storage != glslang::EvqBuffer)
1740         return glslang::ElpNone;
1741
1742     // return the layout to use
1743     switch (type.getQualifier().layoutPacking) {
1744     case glslang::ElpStd140:
1745     case glslang::ElpStd430:
1746         return type.getQualifier().layoutPacking;
1747     default:
1748         return glslang::ElpNone;
1749     }
1750 }
1751
1752 // Given an array type, returns the integer stride required for that array
1753 int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
1754 {
1755     int size;
1756     int stride;
1757     glslangIntermediate->getBaseAlignment(arrayType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
1758
1759     return stride;
1760 }
1761
1762 // Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
1763 // when used as a member of an interface block
1764 int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
1765 {
1766     glslang::TType elementType;
1767     elementType.shallowCopy(matrixType);
1768     elementType.clearArraySizes();
1769
1770     int size;
1771     int stride;
1772     glslangIntermediate->getBaseAlignment(elementType, size, stride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
1773
1774     return stride;
1775 }
1776
1777 // Given a member type of a struct, realign the current offset for it, and compute
1778 // the next (not yet aligned) offset for the next member, which will get aligned
1779 // on the next call.
1780 // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
1781 // the migration of data from nextOffset -> currentOffset.  It should be -1 on the first call.
1782 // -1 means a non-forced member offset (no decoration needed).
1783 void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset,
1784                                                 glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
1785 {
1786     // this will get a positive value when deemed necessary
1787     nextOffset = -1;
1788
1789     // override anything in currentOffset with user-set offset
1790     if (memberType.getQualifier().hasOffset())
1791         currentOffset = memberType.getQualifier().layoutOffset;
1792
1793     // It could be that current linker usage in glslang updated all the layoutOffset,
1794     // in which case the following code does not matter.  But, that's not quite right
1795     // once cross-compilation unit GLSL validation is done, as the original user
1796     // settings are needed in layoutOffset, and then the following will come into play.
1797
1798     if (explicitLayout == glslang::ElpNone) {
1799         if (! memberType.getQualifier().hasOffset())
1800             currentOffset = -1;
1801
1802         return;
1803     }
1804
1805     // Getting this far means we need explicit offsets
1806     if (currentOffset < 0)
1807         currentOffset = 0;
1808     
1809     // Now, currentOffset is valid (either 0, or from a previous nextOffset),
1810     // but possibly not yet correctly aligned.
1811
1812     int memberSize;
1813     int dummyStride;
1814     int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, dummyStride, explicitLayout == glslang::ElpStd140, matrixLayout == glslang::ElmRowMajor);
1815     glslang::RoundToPow2(currentOffset, memberAlignment);
1816     nextOffset = currentOffset + memberSize;
1817 }
1818
1819 bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
1820 {
1821     return node->getName() == "main(";
1822 }
1823
1824 // Make all the functions, skeletally, without actually visiting their bodies.
1825 void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
1826 {
1827     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
1828         glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
1829         if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))
1830             continue;
1831
1832         // We're on a user function.  Set up the basic interface for the function now,
1833         // so that it's available to call.
1834         // Translating the body will happen later.
1835         //
1836         // Typically (except for a "const in" parameter), an address will be passed to the 
1837         // function.  What it is an address of varies:
1838         //
1839         // - "in" parameters not marked as "const" can be written to without modifying the argument,
1840         //  so that write needs to be to a copy, hence the address of a copy works.
1841         //
1842         // - "const in" parameters can just be the r-value, as no writes need occur.
1843         //
1844         // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
1845         // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.
1846
1847         std::vector<spv::Id> paramTypes;
1848         glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
1849
1850         for (int p = 0; p < (int)parameters.size(); ++p) {
1851             const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
1852             spv::Id typeId = convertGlslangToSpvType(paramType);
1853             if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
1854                 typeId = builder.makePointer(spv::StorageClassFunction, typeId);
1855             else
1856                 constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
1857             paramTypes.push_back(typeId);
1858         }
1859
1860         spv::Block* functionBlock;
1861         spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),
1862                                                               paramTypes, &functionBlock);
1863
1864         // Track function to emit/call later
1865         functionMap[glslFunction->getName().c_str()] = function;
1866
1867         // Set the parameter id's
1868         for (int p = 0; p < (int)parameters.size(); ++p) {
1869             symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
1870             // give a name too
1871             builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
1872         }
1873     }
1874 }
1875
1876 // Process all the initializers, while skipping the functions and link objects
1877 void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
1878 {
1879     builder.setBuildPoint(shaderEntry->getLastBlock());
1880     for (int i = 0; i < (int)initializers.size(); ++i) {
1881         glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
1882         if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
1883
1884             // We're on a top-level node that's not a function.  Treat as an initializer, whose
1885             // code goes into the beginning of main.
1886             initializer->traverse(this);
1887         }
1888     }
1889 }
1890
1891 // Process all the functions, while skipping initializers.
1892 void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
1893 {
1894     for (int f = 0; f < (int)glslFunctions.size(); ++f) {
1895         glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
1896         if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))
1897             node->traverse(this);
1898     }
1899 }
1900
1901 void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
1902 {
1903     // SPIR-V functions should already be in the functionMap from the prepass 
1904     // that called makeFunctions().
1905     spv::Function* function = functionMap[node->getName().c_str()];
1906     spv::Block* functionBlock = function->getEntryBlock();
1907     builder.setBuildPoint(functionBlock);
1908 }
1909
1910 void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments)
1911 {
1912     const glslang::TIntermSequence& glslangArguments = node.getSequence();
1913
1914     glslang::TSampler sampler = {};
1915     bool cubeCompare = false;
1916     if (node.isTexture()) {
1917         sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
1918         cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
1919     }
1920
1921     for (int i = 0; i < (int)glslangArguments.size(); ++i) {
1922         builder.clearAccessChain();
1923         glslangArguments[i]->traverse(this);
1924
1925         // Special case l-value operands
1926         bool lvalue = false;
1927         switch (node.getOp()) {
1928         case glslang::EOpImageAtomicAdd:
1929         case glslang::EOpImageAtomicMin:
1930         case glslang::EOpImageAtomicMax:
1931         case glslang::EOpImageAtomicAnd:
1932         case glslang::EOpImageAtomicOr:
1933         case glslang::EOpImageAtomicXor:
1934         case glslang::EOpImageAtomicExchange:
1935         case glslang::EOpImageAtomicCompSwap:
1936             if (i == 0)
1937                 lvalue = true;
1938             break;
1939         case glslang::EOpSparseTexture:
1940             if ((cubeCompare && i == 3) || (! cubeCompare && i == 2))
1941                 lvalue = true;
1942             break;
1943         case glslang::EOpSparseTextureClamp:
1944             if ((cubeCompare && i == 4) || (! cubeCompare && i == 3))
1945                 lvalue = true;
1946             break;
1947         case glslang::EOpSparseTextureLod:
1948         case glslang::EOpSparseTextureOffset:
1949             if (i == 3)
1950                 lvalue = true;
1951             break;
1952         case glslang::EOpSparseTextureFetch:
1953             if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))
1954                 lvalue = true;
1955             break;
1956         case glslang::EOpSparseTextureFetchOffset:
1957             if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))
1958                 lvalue = true;
1959             break;
1960         case glslang::EOpSparseTextureLodOffset:
1961         case glslang::EOpSparseTextureGrad:
1962         case glslang::EOpSparseTextureOffsetClamp:
1963             if (i == 4)
1964                 lvalue = true;
1965             break;
1966         case glslang::EOpSparseTextureGradOffset:
1967         case glslang::EOpSparseTextureGradClamp:
1968             if (i == 5)
1969                 lvalue = true;
1970             break;
1971         case glslang::EOpSparseTextureGradOffsetClamp:
1972             if (i == 6)
1973                 lvalue = true;
1974             break;
1975          case glslang::EOpSparseTextureGather:
1976             if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
1977                 lvalue = true;
1978             break;
1979         case glslang::EOpSparseTextureGatherOffset:
1980         case glslang::EOpSparseTextureGatherOffsets:
1981             if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
1982                 lvalue = true;
1983             break;
1984         default:
1985             break;
1986         }
1987
1988         if (lvalue)
1989             arguments.push_back(builder.accessChainGetLValue());
1990         else
1991             arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangArguments[i]->getAsTyped()->getType())));
1992     }
1993 }
1994
1995 void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)
1996 {
1997     builder.clearAccessChain();
1998     node.getOperand()->traverse(this);
1999     arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(node.getOperand()->getType())));
2000 }
2001
2002 spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
2003 {
2004     if (! node->isImage() && ! node->isTexture()) {
2005         return spv::NoResult;
2006     }
2007
2008     // Process a GLSL texturing op (will be SPV image)
2009     const glslang::TSampler sampler = node->getAsAggregate() ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler()
2010                                                              : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType().getSampler();
2011     std::vector<spv::Id> arguments;
2012     if (node->getAsAggregate())
2013         translateArguments(*node->getAsAggregate(), arguments);
2014     else
2015         translateArguments(*node->getAsUnaryNode(), arguments);
2016     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
2017
2018     spv::Builder::TextureParameters params = { };
2019     params.sampler = arguments[0];
2020
2021     glslang::TCrackedTextureOp cracked;
2022     node->crackTexture(sampler, cracked);
2023
2024     // Check for queries
2025     if (cracked.query) {
2026         // a sampled image needs to have the image extracted first
2027         if (builder.isSampledImage(params.sampler))
2028             params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
2029         switch (node->getOp()) {
2030         case glslang::EOpImageQuerySize:
2031         case glslang::EOpTextureQuerySize:
2032             if (arguments.size() > 1) {
2033                 params.lod = arguments[1];
2034                 return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params);
2035             } else
2036                 return builder.createTextureQueryCall(spv::OpImageQuerySize, params);
2037         case glslang::EOpImageQuerySamples:
2038         case glslang::EOpTextureQuerySamples:
2039             return builder.createTextureQueryCall(spv::OpImageQuerySamples, params);
2040         case glslang::EOpTextureQueryLod:
2041             params.coords = arguments[1];
2042             return builder.createTextureQueryCall(spv::OpImageQueryLod, params);
2043         case glslang::EOpTextureQueryLevels:
2044             return builder.createTextureQueryCall(spv::OpImageQueryLevels, params);
2045         case glslang::EOpSparseTexelsResident:
2046             return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);
2047         default:
2048             assert(0);
2049             break;
2050         }
2051     }
2052
2053     // Check for image functions other than queries
2054     if (node->isImage()) {
2055         std::vector<spv::Id> operands;
2056         auto opIt = arguments.begin();
2057         operands.push_back(*(opIt++));
2058         operands.push_back(*(opIt++));
2059         if (node->getOp() == glslang::EOpImageLoad) {
2060             if (sampler.ms) {
2061                 operands.push_back(spv::ImageOperandsSampleMask);
2062                 operands.push_back(*opIt);
2063             }
2064             return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
2065         } else if (node->getOp() == glslang::EOpImageStore) {
2066             if (sampler.ms) {
2067                 operands.push_back(*(opIt + 1));
2068                 operands.push_back(spv::ImageOperandsSampleMask);
2069                 operands.push_back(*opIt);
2070             } else
2071                 operands.push_back(*opIt);
2072             builder.createNoResultOp(spv::OpImageWrite, operands);
2073             return spv::NoResult;
2074         } else if (node->isSparseImage()) {
2075             spv::MissingFunctionality("sparse image functions");
2076             return spv::NoResult;
2077         }
2078         else {
2079             // Process image atomic operations
2080
2081             // GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
2082             // as the first source operand, is required by SPIR-V atomic operations.
2083             operands.push_back(sampler.ms ? *(opIt++) : 0); // For non-MS, the value should be 0
2084
2085             spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, convertGlslangToSpvType(node->getType()));
2086             spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands);
2087
2088             std::vector<spv::Id> operands;
2089             operands.push_back(pointer);
2090             for (; opIt != arguments.end(); ++opIt)
2091                 operands.push_back(*opIt);
2092
2093             return createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
2094         }
2095     }
2096
2097     // Check for texture functions other than queries
2098     bool sparse = node->isSparseTexture();
2099     bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
2100
2101     // check for bias argument
2102     bool bias = false;
2103     if (! cracked.lod && ! cracked.gather && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
2104         int nonBiasArgCount = 2;
2105         if (cracked.offset)
2106             ++nonBiasArgCount;
2107         if (cracked.grad)
2108             nonBiasArgCount += 2;
2109         if (cracked.lodClamp)
2110             ++nonBiasArgCount;
2111         if (sparse)
2112             ++nonBiasArgCount;
2113
2114         if ((int)arguments.size() > nonBiasArgCount)
2115             bias = true;
2116     }
2117
2118     // set the rest of the arguments
2119
2120     params.coords = arguments[1];
2121     int extraArgs = 0;
2122
2123     // sort out where Dref is coming from
2124     if (cubeCompare) {
2125         params.Dref = arguments[2];
2126         ++extraArgs;
2127     } else if (sampler.shadow && cracked.gather) {
2128         params.Dref = arguments[2];
2129         ++extraArgs;
2130     } else if (sampler.shadow) {
2131         std::vector<spv::Id> indexes;
2132         int comp;
2133         if (cracked.proj)
2134             comp = 2;  // "The resulting 3rd component of P in the shadow forms is used as Dref"
2135         else
2136             comp = builder.getNumComponents(params.coords) - 1;
2137         indexes.push_back(comp);
2138         params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
2139     }
2140     if (cracked.lod) {
2141         params.lod = arguments[2];
2142         ++extraArgs;
2143     } else if (sampler.ms) {
2144         params.sample = arguments[2]; // For MS, "sample" should be specified
2145         ++extraArgs;
2146     }
2147     if (cracked.grad) {
2148         params.gradX = arguments[2 + extraArgs];
2149         params.gradY = arguments[3 + extraArgs];
2150         extraArgs += 2;
2151     }
2152     if (cracked.offset) {
2153         params.offset = arguments[2 + extraArgs];
2154         ++extraArgs;
2155     } else if (cracked.offsets) {
2156         params.offsets = arguments[2 + extraArgs];
2157         ++extraArgs;
2158     }
2159     if (cracked.lodClamp) {
2160         params.lodClamp = arguments[2 + extraArgs];
2161         ++extraArgs;
2162     }
2163     if (sparse) {
2164         params.texelOut = arguments[2 + extraArgs];
2165         ++extraArgs;
2166     }
2167     if (bias) {
2168         params.bias = arguments[2 + extraArgs];
2169         ++extraArgs;
2170     }
2171     if (cracked.gather && ! sampler.shadow) {
2172         // default component is 0, if missing, otherwise an argument
2173         if (2 + extraArgs < (int)arguments.size()) {
2174             params.comp = arguments[2 + extraArgs];
2175             ++extraArgs;
2176         } else {
2177             params.comp = builder.makeIntConstant(0);
2178         }
2179     }
2180
2181     return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), sparse, cracked.fetch, cracked.proj, cracked.gather, params);
2182 }
2183
2184 spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
2185 {
2186     // Grab the function's pointer from the previously created function
2187     spv::Function* function = functionMap[node->getName().c_str()];
2188     if (! function)
2189         return 0;
2190
2191     const glslang::TIntermSequence& glslangArgs = node->getSequence();
2192     const glslang::TQualifierList& qualifiers = node->getQualifierList();
2193
2194     //  See comments in makeFunctions() for details about the semantics for parameter passing.
2195     //
2196     // These imply we need a four step process:
2197     // 1. Evaluate the arguments
2198     // 2. Allocate and make copies of in, out, and inout arguments
2199     // 3. Make the call
2200     // 4. Copy back the results
2201
2202     // 1. Evaluate the arguments
2203     std::vector<spv::Builder::AccessChain> lValues;
2204     std::vector<spv::Id> rValues;
2205     std::vector<spv::Id> argTypes;
2206     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
2207         // build l-value
2208         builder.clearAccessChain();
2209         glslangArgs[a]->traverse(this);
2210         argTypes.push_back(convertGlslangToSpvType(glslangArgs[a]->getAsTyped()->getType()));
2211         // keep outputs as l-values, evaluate input-only as r-values
2212         if (qualifiers[a] != glslang::EvqConstReadOnly) {
2213             // save l-value
2214             lValues.push_back(builder.getAccessChain());
2215         } else {
2216             // process r-value
2217             rValues.push_back(builder.accessChainLoad(argTypes.back()));
2218         }
2219     }
2220
2221     // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
2222     // copy the original into that space.
2223     //
2224     // Also, build up the list of actual arguments to pass in for the call
2225     int lValueCount = 0;
2226     int rValueCount = 0;
2227     std::vector<spv::Id> spvArgs;
2228     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
2229         spv::Id arg;
2230         if (qualifiers[a] != glslang::EvqConstReadOnly) {
2231             // need space to hold the copy
2232             const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
2233             arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");
2234             if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
2235                 // need to copy the input into output space
2236                 builder.setAccessChain(lValues[lValueCount]);
2237                 spv::Id copy = builder.accessChainLoad(argTypes[a]);
2238                 builder.createStore(copy, arg);
2239             }
2240             ++lValueCount;
2241         } else {
2242             arg = rValues[rValueCount];
2243             ++rValueCount;
2244         }
2245         spvArgs.push_back(arg);
2246     }
2247
2248     // 3. Make the call.
2249     spv::Id result = builder.createFunctionCall(function, spvArgs);
2250
2251     // 4. Copy back out an "out" arguments.
2252     lValueCount = 0;
2253     for (int a = 0; a < (int)glslangArgs.size(); ++a) {
2254         if (qualifiers[a] != glslang::EvqConstReadOnly) {
2255             if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
2256                 spv::Id copy = builder.createLoad(spvArgs[a]);
2257                 builder.setAccessChain(lValues[lValueCount]);
2258                 builder.accessChainStore(copy);
2259             }
2260             ++lValueCount;
2261         }
2262     }
2263
2264     return result;
2265 }
2266
2267 // Translate AST operation to SPV operation, already having SPV-based operands/types.
2268 spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, 
2269                                                       spv::Id typeId, spv::Id left, spv::Id right,
2270                                                       glslang::TBasicType typeProxy, bool reduceComparison)
2271 {
2272     bool isUnsigned = typeProxy == glslang::EbtUint;
2273     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
2274
2275     spv::Op binOp = spv::OpNop;
2276     bool needMatchingVectors = true;  // for non-matrix ops, would a scalar need to smear to match a vector?
2277     bool comparison = false;
2278
2279     switch (op) {
2280     case glslang::EOpAdd:
2281     case glslang::EOpAddAssign:
2282         if (isFloat)
2283             binOp = spv::OpFAdd;
2284         else
2285             binOp = spv::OpIAdd;
2286         break;
2287     case glslang::EOpSub:
2288     case glslang::EOpSubAssign:
2289         if (isFloat)
2290             binOp = spv::OpFSub;
2291         else
2292             binOp = spv::OpISub;
2293         break;
2294     case glslang::EOpMul:
2295     case glslang::EOpMulAssign:
2296         if (isFloat)
2297             binOp = spv::OpFMul;
2298         else
2299             binOp = spv::OpIMul;
2300         break;
2301     case glslang::EOpVectorTimesScalar:
2302     case glslang::EOpVectorTimesScalarAssign:
2303         if (isFloat) {
2304             if (builder.isVector(right))
2305                 std::swap(left, right);
2306             assert(builder.isScalar(right));
2307             needMatchingVectors = false;
2308             binOp = spv::OpVectorTimesScalar;
2309         } else
2310             binOp = spv::OpIMul;
2311         break;
2312     case glslang::EOpVectorTimesMatrix:
2313     case glslang::EOpVectorTimesMatrixAssign:
2314         binOp = spv::OpVectorTimesMatrix;
2315         break;
2316     case glslang::EOpMatrixTimesVector:
2317         binOp = spv::OpMatrixTimesVector;
2318         break;
2319     case glslang::EOpMatrixTimesScalar:
2320     case glslang::EOpMatrixTimesScalarAssign:
2321         binOp = spv::OpMatrixTimesScalar;
2322         break;
2323     case glslang::EOpMatrixTimesMatrix:
2324     case glslang::EOpMatrixTimesMatrixAssign:
2325         binOp = spv::OpMatrixTimesMatrix;
2326         break;
2327     case glslang::EOpOuterProduct:
2328         binOp = spv::OpOuterProduct;
2329         needMatchingVectors = false;
2330         break;
2331
2332     case glslang::EOpDiv:
2333     case glslang::EOpDivAssign:
2334         if (isFloat)
2335             binOp = spv::OpFDiv;
2336         else if (isUnsigned)
2337             binOp = spv::OpUDiv;
2338         else
2339             binOp = spv::OpSDiv;
2340         break;
2341     case glslang::EOpMod:
2342     case glslang::EOpModAssign:
2343         if (isFloat)
2344             binOp = spv::OpFMod;
2345         else if (isUnsigned)
2346             binOp = spv::OpUMod;
2347         else
2348             binOp = spv::OpSMod;
2349         break;
2350     case glslang::EOpRightShift:
2351     case glslang::EOpRightShiftAssign:
2352         if (isUnsigned)
2353             binOp = spv::OpShiftRightLogical;
2354         else
2355             binOp = spv::OpShiftRightArithmetic;
2356         break;
2357     case glslang::EOpLeftShift:
2358     case glslang::EOpLeftShiftAssign:
2359         binOp = spv::OpShiftLeftLogical;
2360         break;
2361     case glslang::EOpAnd:
2362     case glslang::EOpAndAssign:
2363         binOp = spv::OpBitwiseAnd;
2364         break;
2365     case glslang::EOpLogicalAnd:
2366         needMatchingVectors = false;
2367         binOp = spv::OpLogicalAnd;
2368         break;
2369     case glslang::EOpInclusiveOr:
2370     case glslang::EOpInclusiveOrAssign:
2371         binOp = spv::OpBitwiseOr;
2372         break;
2373     case glslang::EOpLogicalOr:
2374         needMatchingVectors = false;
2375         binOp = spv::OpLogicalOr;
2376         break;
2377     case glslang::EOpExclusiveOr:
2378     case glslang::EOpExclusiveOrAssign:
2379         binOp = spv::OpBitwiseXor;
2380         break;
2381     case glslang::EOpLogicalXor:
2382         needMatchingVectors = false;
2383         binOp = spv::OpLogicalNotEqual;
2384         break;
2385
2386     case glslang::EOpLessThan:
2387     case glslang::EOpGreaterThan:
2388     case glslang::EOpLessThanEqual:
2389     case glslang::EOpGreaterThanEqual:
2390     case glslang::EOpEqual:
2391     case glslang::EOpNotEqual:
2392     case glslang::EOpVectorEqual:
2393     case glslang::EOpVectorNotEqual:
2394         comparison = true;
2395         break;
2396     default:
2397         break;
2398     }
2399
2400     // handle mapped binary operations (should be non-comparison)
2401     if (binOp != spv::OpNop) {
2402         assert(comparison == false);
2403         if (builder.isMatrix(left) || builder.isMatrix(right))
2404             return createBinaryMatrixOperation(binOp, precision, typeId, left, right);
2405
2406         // No matrix involved; make both operands be the same number of components, if needed
2407         if (needMatchingVectors)
2408             builder.promoteScalar(precision, left, right);
2409
2410         spv::Id id = builder.createBinOp(binOp, typeId, left, right);
2411         builder.setPrecision(id, precision);
2412
2413         return id;
2414     }
2415
2416     if (! comparison)
2417         return 0;
2418
2419     // Handle comparison instructions
2420
2421     if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
2422         assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);
2423
2424         return builder.createCompositeCompare(precision, left, right, op == glslang::EOpEqual);
2425     }
2426
2427     switch (op) {
2428     case glslang::EOpLessThan:
2429         if (isFloat)
2430             binOp = spv::OpFOrdLessThan;
2431         else if (isUnsigned)
2432             binOp = spv::OpULessThan;
2433         else
2434             binOp = spv::OpSLessThan;
2435         break;
2436     case glslang::EOpGreaterThan:
2437         if (isFloat)
2438             binOp = spv::OpFOrdGreaterThan;
2439         else if (isUnsigned)
2440             binOp = spv::OpUGreaterThan;
2441         else
2442             binOp = spv::OpSGreaterThan;
2443         break;
2444     case glslang::EOpLessThanEqual:
2445         if (isFloat)
2446             binOp = spv::OpFOrdLessThanEqual;
2447         else if (isUnsigned)
2448             binOp = spv::OpULessThanEqual;
2449         else
2450             binOp = spv::OpSLessThanEqual;
2451         break;
2452     case glslang::EOpGreaterThanEqual:
2453         if (isFloat)
2454             binOp = spv::OpFOrdGreaterThanEqual;
2455         else if (isUnsigned)
2456             binOp = spv::OpUGreaterThanEqual;
2457         else
2458             binOp = spv::OpSGreaterThanEqual;
2459         break;
2460     case glslang::EOpEqual:
2461     case glslang::EOpVectorEqual:
2462         if (isFloat)
2463             binOp = spv::OpFOrdEqual;
2464         else
2465             binOp = spv::OpIEqual;
2466         break;
2467     case glslang::EOpNotEqual:
2468     case glslang::EOpVectorNotEqual:
2469         if (isFloat)
2470             binOp = spv::OpFOrdNotEqual;
2471         else
2472             binOp = spv::OpINotEqual;
2473         break;
2474     default:
2475         break;
2476     }
2477
2478     if (binOp != spv::OpNop) {
2479         spv::Id id = builder.createBinOp(binOp, typeId, left, right);
2480         builder.setPrecision(id, precision);
2481
2482         return id;
2483     }
2484
2485     return 0;
2486 }
2487
2488 //
2489 // Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
2490 // These can be any of:
2491 //
2492 //   matrix * scalar
2493 //   scalar * matrix
2494 //   matrix * matrix     linear algebraic
2495 //   matrix * vector
2496 //   vector * matrix
2497 //   matrix * matrix     componentwise
2498 //   matrix op matrix    op in {+, -, /}
2499 //   matrix op scalar    op in {+, -, /}
2500 //   scalar op matrix    op in {+, -, /}
2501 //
2502 spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right)
2503 {
2504     bool firstClass = true;
2505
2506     // First, handle first-class matrix operations (* and matrix/scalar)
2507     switch (op) {
2508     case spv::OpFDiv:
2509         if (builder.isMatrix(left) && builder.isScalar(right)) {
2510             // turn matrix / scalar into a multiply...
2511             right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);
2512             op = spv::OpMatrixTimesScalar;
2513         } else
2514             firstClass = false;
2515         break;
2516     case spv::OpMatrixTimesScalar:
2517         if (builder.isMatrix(right))
2518             std::swap(left, right);
2519         assert(builder.isScalar(right));
2520         break;
2521     case spv::OpVectorTimesMatrix:
2522         assert(builder.isVector(left));
2523         assert(builder.isMatrix(right));
2524         break;
2525     case spv::OpMatrixTimesVector:
2526         assert(builder.isMatrix(left));
2527         assert(builder.isVector(right));
2528         break;
2529     case spv::OpMatrixTimesMatrix:
2530         assert(builder.isMatrix(left));
2531         assert(builder.isMatrix(right));
2532         break;
2533     default:
2534         firstClass = false;
2535         break;
2536     }
2537
2538     if (firstClass) {
2539         spv::Id id = builder.createBinOp(op, typeId, left, right);
2540         builder.setPrecision(id, precision);
2541
2542         return id;
2543     }
2544
2545     // Handle component-wise +, -, *, and / for all combinations of type.
2546     // The result type of all of them is the same type as the (a) matrix operand.
2547     // The algorithm is to:
2548     //   - break the matrix(es) into vectors
2549     //   - smear any scalar to a vector
2550     //   - do vector operations
2551     //   - make a matrix out the vector results
2552     switch (op) {
2553     case spv::OpFAdd:
2554     case spv::OpFSub:
2555     case spv::OpFDiv:
2556     case spv::OpFMul:
2557     {
2558         // one time set up...
2559         bool  leftMat = builder.isMatrix(left);
2560         bool rightMat = builder.isMatrix(right);
2561         unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);
2562         int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);
2563         spv::Id scalarType = builder.getScalarTypeId(typeId);
2564         spv::Id vecType = builder.makeVectorType(scalarType, numRows);
2565         std::vector<spv::Id> results;
2566         spv::Id smearVec = spv::NoResult;
2567         if (builder.isScalar(left))
2568             smearVec = builder.smearScalar(precision, left, vecType);
2569         else if (builder.isScalar(right))
2570             smearVec = builder.smearScalar(precision, right, vecType);
2571
2572         // do each vector op
2573         for (unsigned int c = 0; c < numCols; ++c) {
2574             std::vector<unsigned int> indexes;
2575             indexes.push_back(c);
2576             spv::Id  leftVec =  leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
2577             spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
2578             results.push_back(builder.createBinOp(op, vecType, leftVec, rightVec));
2579             builder.setPrecision(results.back(), precision);
2580         }
2581
2582         // put the pieces together
2583         spv::Id id = builder.createCompositeConstruct(typeId, results);
2584         builder.setPrecision(id, precision);
2585         return id;
2586     }
2587     default:
2588         assert(0);
2589         return spv::NoResult;
2590     }
2591 }
2592
2593 spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy)
2594 {
2595     spv::Op unaryOp = spv::OpNop;
2596     int libCall = -1;
2597     bool isUnsigned = typeProxy == glslang::EbtUint;
2598     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
2599
2600     switch (op) {
2601     case glslang::EOpNegative:
2602         if (isFloat)
2603             unaryOp = spv::OpFNegate;
2604         else
2605             unaryOp = spv::OpSNegate;
2606         break;
2607
2608     case glslang::EOpLogicalNot:
2609     case glslang::EOpVectorLogicalNot:
2610         unaryOp = spv::OpLogicalNot;
2611         break;
2612     case glslang::EOpBitwiseNot:
2613         unaryOp = spv::OpNot;
2614         break;
2615
2616     case glslang::EOpDeterminant:
2617         libCall = spv::GLSLstd450Determinant;
2618         break;
2619     case glslang::EOpMatrixInverse:
2620         libCall = spv::GLSLstd450MatrixInverse;
2621         break;
2622     case glslang::EOpTranspose:
2623         unaryOp = spv::OpTranspose;
2624         break;
2625
2626     case glslang::EOpRadians:
2627         libCall = spv::GLSLstd450Radians;
2628         break;
2629     case glslang::EOpDegrees:
2630         libCall = spv::GLSLstd450Degrees;
2631         break;
2632     case glslang::EOpSin:
2633         libCall = spv::GLSLstd450Sin;
2634         break;
2635     case glslang::EOpCos:
2636         libCall = spv::GLSLstd450Cos;
2637         break;
2638     case glslang::EOpTan:
2639         libCall = spv::GLSLstd450Tan;
2640         break;
2641     case glslang::EOpAcos:
2642         libCall = spv::GLSLstd450Acos;
2643         break;
2644     case glslang::EOpAsin:
2645         libCall = spv::GLSLstd450Asin;
2646         break;
2647     case glslang::EOpAtan:
2648         libCall = spv::GLSLstd450Atan;
2649         break;
2650
2651     case glslang::EOpAcosh:
2652         libCall = spv::GLSLstd450Acosh;
2653         break;
2654     case glslang::EOpAsinh:
2655         libCall = spv::GLSLstd450Asinh;
2656         break;
2657     case glslang::EOpAtanh:
2658         libCall = spv::GLSLstd450Atanh;
2659         break;
2660     case glslang::EOpTanh:
2661         libCall = spv::GLSLstd450Tanh;
2662         break;
2663     case glslang::EOpCosh:
2664         libCall = spv::GLSLstd450Cosh;
2665         break;
2666     case glslang::EOpSinh:
2667         libCall = spv::GLSLstd450Sinh;
2668         break;
2669
2670     case glslang::EOpLength:
2671         libCall = spv::GLSLstd450Length;
2672         break;
2673     case glslang::EOpNormalize:
2674         libCall = spv::GLSLstd450Normalize;
2675         break;
2676
2677     case glslang::EOpExp:
2678         libCall = spv::GLSLstd450Exp;
2679         break;
2680     case glslang::EOpLog:
2681         libCall = spv::GLSLstd450Log;
2682         break;
2683     case glslang::EOpExp2:
2684         libCall = spv::GLSLstd450Exp2;
2685         break;
2686     case glslang::EOpLog2:
2687         libCall = spv::GLSLstd450Log2;
2688         break;
2689     case glslang::EOpSqrt:
2690         libCall = spv::GLSLstd450Sqrt;
2691         break;
2692     case glslang::EOpInverseSqrt:
2693         libCall = spv::GLSLstd450InverseSqrt;
2694         break;
2695
2696     case glslang::EOpFloor:
2697         libCall = spv::GLSLstd450Floor;
2698         break;
2699     case glslang::EOpTrunc:
2700         libCall = spv::GLSLstd450Trunc;
2701         break;
2702     case glslang::EOpRound:
2703         libCall = spv::GLSLstd450Round;
2704         break;
2705     case glslang::EOpRoundEven:
2706         libCall = spv::GLSLstd450RoundEven;
2707         break;
2708     case glslang::EOpCeil:
2709         libCall = spv::GLSLstd450Ceil;
2710         break;
2711     case glslang::EOpFract:
2712         libCall = spv::GLSLstd450Fract;
2713         break;
2714
2715     case glslang::EOpIsNan:
2716         unaryOp = spv::OpIsNan;
2717         break;
2718     case glslang::EOpIsInf:
2719         unaryOp = spv::OpIsInf;
2720         break;
2721
2722     case glslang::EOpFloatBitsToInt:
2723     case glslang::EOpFloatBitsToUint:
2724     case glslang::EOpIntBitsToFloat:
2725     case glslang::EOpUintBitsToFloat:
2726         unaryOp = spv::OpBitcast;
2727         break;
2728
2729     case glslang::EOpPackSnorm2x16:
2730         libCall = spv::GLSLstd450PackSnorm2x16;
2731         break;
2732     case glslang::EOpUnpackSnorm2x16:
2733         libCall = spv::GLSLstd450UnpackSnorm2x16;
2734         break;
2735     case glslang::EOpPackUnorm2x16:
2736         libCall = spv::GLSLstd450PackUnorm2x16;
2737         break;
2738     case glslang::EOpUnpackUnorm2x16:
2739         libCall = spv::GLSLstd450UnpackUnorm2x16;
2740         break;
2741     case glslang::EOpPackHalf2x16:
2742         libCall = spv::GLSLstd450PackHalf2x16;
2743         break;
2744     case glslang::EOpUnpackHalf2x16:
2745         libCall = spv::GLSLstd450UnpackHalf2x16;
2746         break;
2747     case glslang::EOpPackSnorm4x8:
2748         libCall = spv::GLSLstd450PackSnorm4x8;
2749         break;
2750     case glslang::EOpUnpackSnorm4x8:
2751         libCall = spv::GLSLstd450UnpackSnorm4x8;
2752         break;
2753     case glslang::EOpPackUnorm4x8:
2754         libCall = spv::GLSLstd450PackUnorm4x8;
2755         break;
2756     case glslang::EOpUnpackUnorm4x8:
2757         libCall = spv::GLSLstd450UnpackUnorm4x8;
2758         break;
2759     case glslang::EOpPackDouble2x32:
2760         libCall = spv::GLSLstd450PackDouble2x32;
2761         break;
2762     case glslang::EOpUnpackDouble2x32:
2763         libCall = spv::GLSLstd450UnpackDouble2x32;
2764         break;
2765
2766     case glslang::EOpDPdx:
2767         unaryOp = spv::OpDPdx;
2768         break;
2769     case glslang::EOpDPdy:
2770         unaryOp = spv::OpDPdy;
2771         break;
2772     case glslang::EOpFwidth:
2773         unaryOp = spv::OpFwidth;
2774         break;
2775     case glslang::EOpDPdxFine:
2776         unaryOp = spv::OpDPdxFine;
2777         break;
2778     case glslang::EOpDPdyFine:
2779         unaryOp = spv::OpDPdyFine;
2780         break;
2781     case glslang::EOpFwidthFine:
2782         unaryOp = spv::OpFwidthFine;
2783         break;
2784     case glslang::EOpDPdxCoarse:
2785         unaryOp = spv::OpDPdxCoarse;
2786         break;
2787     case glslang::EOpDPdyCoarse:
2788         unaryOp = spv::OpDPdyCoarse;
2789         break;
2790     case glslang::EOpFwidthCoarse:
2791         unaryOp = spv::OpFwidthCoarse;
2792         break;
2793     case glslang::EOpInterpolateAtCentroid:
2794         libCall = spv::GLSLstd450InterpolateAtCentroid;
2795         break;
2796     case glslang::EOpAny:
2797         unaryOp = spv::OpAny;
2798         break;
2799     case glslang::EOpAll:
2800         unaryOp = spv::OpAll;
2801         break;
2802
2803     case glslang::EOpAbs:
2804         if (isFloat)
2805             libCall = spv::GLSLstd450FAbs;
2806         else
2807             libCall = spv::GLSLstd450SAbs;
2808         break;
2809     case glslang::EOpSign:
2810         if (isFloat)
2811             libCall = spv::GLSLstd450FSign;
2812         else
2813             libCall = spv::GLSLstd450SSign;
2814         break;
2815
2816     case glslang::EOpAtomicCounterIncrement:
2817     case glslang::EOpAtomicCounterDecrement:
2818     case glslang::EOpAtomicCounter:
2819     {
2820         // Handle all of the atomics in one place, in createAtomicOperation()
2821         std::vector<spv::Id> operands;
2822         operands.push_back(operand);
2823         return createAtomicOperation(op, precision, typeId, operands, typeProxy);
2824     }
2825
2826     case glslang::EOpImageLoad:
2827         unaryOp = spv::OpImageRead;
2828         break;
2829
2830     case glslang::EOpBitFieldReverse:
2831         unaryOp = spv::OpBitReverse;
2832         break;
2833     case glslang::EOpBitCount:
2834         unaryOp = spv::OpBitCount;
2835         break;
2836     case glslang::EOpFindLSB:
2837         libCall = spv::GLSLstd450FindILsb;
2838         break;
2839     case glslang::EOpFindMSB:
2840         if (isUnsigned)
2841             libCall = spv::GLSLstd450FindUMsb;
2842         else
2843             libCall = spv::GLSLstd450FindSMsb;
2844         break;
2845
2846     default:
2847         return 0;
2848     }
2849
2850     spv::Id id;
2851     if (libCall >= 0) {
2852         std::vector<spv::Id> args;
2853         args.push_back(operand);
2854         id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);
2855     } else
2856         id = builder.createUnaryOp(unaryOp, typeId, operand);
2857
2858     builder.setPrecision(id, precision);
2859
2860     return id;
2861 }
2862
2863 spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)
2864 {
2865     spv::Op convOp = spv::OpNop;
2866     spv::Id zero = 0;
2867     spv::Id one = 0;
2868
2869     int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
2870
2871     switch (op) {
2872     case glslang::EOpConvIntToBool:
2873     case glslang::EOpConvUintToBool:
2874         zero = builder.makeUintConstant(0);
2875         zero = makeSmearedConstant(zero, vectorSize);
2876         return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
2877
2878     case glslang::EOpConvFloatToBool:
2879         zero = builder.makeFloatConstant(0.0F);
2880         zero = makeSmearedConstant(zero, vectorSize);
2881         return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
2882
2883     case glslang::EOpConvDoubleToBool:
2884         zero = builder.makeDoubleConstant(0.0);
2885         zero = makeSmearedConstant(zero, vectorSize);
2886         return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
2887
2888     case glslang::EOpConvBoolToFloat:
2889         convOp = spv::OpSelect;
2890         zero = builder.makeFloatConstant(0.0);
2891         one  = builder.makeFloatConstant(1.0);
2892         break;
2893     case glslang::EOpConvBoolToDouble:
2894         convOp = spv::OpSelect;
2895         zero = builder.makeDoubleConstant(0.0);
2896         one  = builder.makeDoubleConstant(1.0);
2897         break;
2898     case glslang::EOpConvBoolToInt:
2899         zero = builder.makeIntConstant(0);
2900         one  = builder.makeIntConstant(1);
2901         convOp = spv::OpSelect;
2902         break;
2903     case glslang::EOpConvBoolToUint:
2904         zero = builder.makeUintConstant(0);
2905         one  = builder.makeUintConstant(1);
2906         convOp = spv::OpSelect;
2907         break;
2908
2909     case glslang::EOpConvIntToFloat:
2910     case glslang::EOpConvIntToDouble:
2911         convOp = spv::OpConvertSToF;
2912         break;
2913
2914     case glslang::EOpConvUintToFloat:
2915     case glslang::EOpConvUintToDouble:
2916         convOp = spv::OpConvertUToF;
2917         break;
2918
2919     case glslang::EOpConvDoubleToFloat:
2920     case glslang::EOpConvFloatToDouble:
2921         convOp = spv::OpFConvert;
2922         break;
2923
2924     case glslang::EOpConvFloatToInt:
2925     case glslang::EOpConvDoubleToInt:
2926         convOp = spv::OpConvertFToS;
2927         break;
2928
2929     case glslang::EOpConvUintToInt:
2930     case glslang::EOpConvIntToUint:
2931         convOp = spv::OpBitcast;
2932         break;
2933
2934     case glslang::EOpConvFloatToUint:
2935     case glslang::EOpConvDoubleToUint:
2936         convOp = spv::OpConvertFToU;
2937         break;
2938     default:
2939         break;
2940     }
2941
2942     spv::Id result = 0;
2943     if (convOp == spv::OpNop)
2944         return result;
2945
2946     if (convOp == spv::OpSelect) {
2947         zero = makeSmearedConstant(zero, vectorSize);
2948         one  = makeSmearedConstant(one, vectorSize);
2949         result = builder.createTriOp(convOp, destType, operand, one, zero);
2950     } else
2951         result = builder.createUnaryOp(convOp, destType, operand);
2952
2953     builder.setPrecision(result, precision);
2954
2955     return result;
2956 }
2957
2958 spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
2959 {
2960     if (vectorSize == 0)
2961         return constant;
2962
2963     spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
2964     std::vector<spv::Id> components;
2965     for (int c = 0; c < vectorSize; ++c)
2966         components.push_back(constant);
2967     return builder.makeCompositeConstant(vectorTypeId, components);
2968 }
2969
2970 // For glslang ops that map to SPV atomic opCodes
2971 spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
2972 {
2973     spv::Op opCode = spv::OpNop;
2974
2975     switch (op) {
2976     case glslang::EOpAtomicAdd:
2977     case glslang::EOpImageAtomicAdd:
2978         opCode = spv::OpAtomicIAdd;
2979         break;
2980     case glslang::EOpAtomicMin:
2981     case glslang::EOpImageAtomicMin:
2982         opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMin : spv::OpAtomicSMin;
2983         break;
2984     case glslang::EOpAtomicMax:
2985     case glslang::EOpImageAtomicMax:
2986         opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMax : spv::OpAtomicSMax;
2987         break;
2988     case glslang::EOpAtomicAnd:
2989     case glslang::EOpImageAtomicAnd:
2990         opCode = spv::OpAtomicAnd;
2991         break;
2992     case glslang::EOpAtomicOr:
2993     case glslang::EOpImageAtomicOr:
2994         opCode = spv::OpAtomicOr;
2995         break;
2996     case glslang::EOpAtomicXor:
2997     case glslang::EOpImageAtomicXor:
2998         opCode = spv::OpAtomicXor;
2999         break;
3000     case glslang::EOpAtomicExchange:
3001     case glslang::EOpImageAtomicExchange:
3002         opCode = spv::OpAtomicExchange;
3003         break;
3004     case glslang::EOpAtomicCompSwap:
3005     case glslang::EOpImageAtomicCompSwap:
3006         opCode = spv::OpAtomicCompareExchange;
3007         break;
3008     case glslang::EOpAtomicCounterIncrement:
3009         opCode = spv::OpAtomicIIncrement;
3010         break;
3011     case glslang::EOpAtomicCounterDecrement:
3012         opCode = spv::OpAtomicIDecrement;
3013         break;
3014     case glslang::EOpAtomicCounter:
3015         opCode = spv::OpAtomicLoad;
3016         break;
3017     default:
3018         assert(0);
3019         break;
3020     }
3021
3022     // Sort out the operands
3023     //  - mapping from glslang -> SPV
3024     //  - there are extra SPV operands with no glslang source
3025     //  - compare-exchange swaps the value and comparator
3026     //  - compare-exchange has an extra memory semantics
3027     std::vector<spv::Id> spvAtomicOperands;  // hold the spv operands
3028     auto opIt = operands.begin();            // walk the glslang operands
3029     spvAtomicOperands.push_back(*(opIt++));
3030     spvAtomicOperands.push_back(builder.makeUintConstant(spv::ScopeDevice));     // TBD: what is the correct scope?
3031     spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone)); // TBD: what are the correct memory semantics?
3032     if (opCode == spv::OpAtomicCompareExchange) {
3033         // There are 2 memory semantics for compare-exchange. And the operand order of "comparator" and "new value" in GLSL
3034         // differs from that in SPIR-V. Hence, special processing is required.
3035         spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone));
3036         spvAtomicOperands.push_back(*(opIt + 1));
3037         spvAtomicOperands.push_back(*opIt);
3038         opIt += 2;
3039     }
3040
3041     // Add the rest of the operands, skipping any that were dealt with above.
3042     for (; opIt != operands.end(); ++opIt)
3043         spvAtomicOperands.push_back(*opIt);
3044
3045     return builder.createOp(opCode, typeId, spvAtomicOperands);
3046 }
3047
3048 spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
3049 {
3050     bool isUnsigned = typeProxy == glslang::EbtUint;
3051     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
3052
3053     spv::Op opCode = spv::OpNop;
3054     int libCall = -1;
3055     size_t consumedOperands = operands.size();
3056     spv::Id typeId0 = 0;
3057     if (consumedOperands > 0)
3058         typeId0 = builder.getTypeId(operands[0]);
3059     spv::Id frexpIntType = 0;
3060
3061     switch (op) {
3062     case glslang::EOpMin:
3063         if (isFloat)
3064             libCall = spv::GLSLstd450FMin;
3065         else if (isUnsigned)
3066             libCall = spv::GLSLstd450UMin;
3067         else
3068             libCall = spv::GLSLstd450SMin;
3069         builder.promoteScalar(precision, operands.front(), operands.back());
3070         break;
3071     case glslang::EOpModf:
3072         libCall = spv::GLSLstd450Modf;
3073         break;
3074     case glslang::EOpMax:
3075         if (isFloat)
3076             libCall = spv::GLSLstd450FMax;
3077         else if (isUnsigned)
3078             libCall = spv::GLSLstd450UMax;
3079         else
3080             libCall = spv::GLSLstd450SMax;
3081         builder.promoteScalar(precision, operands.front(), operands.back());
3082         break;
3083     case glslang::EOpPow:
3084         libCall = spv::GLSLstd450Pow;
3085         break;
3086     case glslang::EOpDot:
3087         opCode = spv::OpDot;
3088         break;
3089     case glslang::EOpAtan:
3090         libCall = spv::GLSLstd450Atan2;
3091         break;
3092
3093     case glslang::EOpClamp:
3094         if (isFloat)
3095             libCall = spv::GLSLstd450FClamp;
3096         else if (isUnsigned)
3097             libCall = spv::GLSLstd450UClamp;
3098         else
3099             libCall = spv::GLSLstd450SClamp;
3100         builder.promoteScalar(precision, operands.front(), operands[1]);
3101         builder.promoteScalar(precision, operands.front(), operands[2]);
3102         break;
3103     case glslang::EOpMix:
3104         if (isFloat)
3105             libCall = spv::GLSLstd450FMix;
3106         else
3107             libCall = spv::GLSLstd450IMix;
3108         builder.promoteScalar(precision, operands.front(), operands.back());
3109         break;
3110     case glslang::EOpStep:
3111         libCall = spv::GLSLstd450Step;
3112         builder.promoteScalar(precision, operands.front(), operands.back());
3113         break;
3114     case glslang::EOpSmoothStep:
3115         libCall = spv::GLSLstd450SmoothStep;
3116         builder.promoteScalar(precision, operands[0], operands[2]);
3117         builder.promoteScalar(precision, operands[1], operands[2]);
3118         break;
3119
3120     case glslang::EOpDistance:
3121         libCall = spv::GLSLstd450Distance;
3122         break;
3123     case glslang::EOpCross:
3124         libCall = spv::GLSLstd450Cross;
3125         break;
3126     case glslang::EOpFaceForward:
3127         libCall = spv::GLSLstd450FaceForward;
3128         break;
3129     case glslang::EOpReflect:
3130         libCall = spv::GLSLstd450Reflect;
3131         break;
3132     case glslang::EOpRefract:
3133         libCall = spv::GLSLstd450Refract;
3134         break;
3135     case glslang::EOpInterpolateAtSample:
3136         libCall = spv::GLSLstd450InterpolateAtSample;
3137         break;
3138     case glslang::EOpInterpolateAtOffset:
3139         libCall = spv::GLSLstd450InterpolateAtOffset;
3140         break;
3141     case glslang::EOpAddCarry:
3142         opCode = spv::OpIAddCarry;
3143         typeId = builder.makeStructResultType(typeId0, typeId0);
3144         consumedOperands = 2;
3145         break;
3146     case glslang::EOpSubBorrow:
3147         opCode = spv::OpISubBorrow;
3148         typeId = builder.makeStructResultType(typeId0, typeId0);
3149         consumedOperands = 2;
3150         break;
3151     case glslang::EOpUMulExtended:
3152         opCode = spv::OpUMulExtended;
3153         typeId = builder.makeStructResultType(typeId0, typeId0);
3154         consumedOperands = 2;
3155         break;
3156     case glslang::EOpIMulExtended:
3157         opCode = spv::OpSMulExtended;
3158         typeId = builder.makeStructResultType(typeId0, typeId0);
3159         consumedOperands = 2;
3160         break;
3161     case glslang::EOpBitfieldExtract:
3162         if (isUnsigned)
3163             opCode = spv::OpBitFieldUExtract;
3164         else
3165             opCode = spv::OpBitFieldSExtract;
3166         break;
3167     case glslang::EOpBitfieldInsert:
3168         opCode = spv::OpBitFieldInsert;
3169         break;
3170
3171     case glslang::EOpFma:
3172         libCall = spv::GLSLstd450Fma;
3173         break;
3174     case glslang::EOpFrexp:
3175         libCall = spv::GLSLstd450FrexpStruct;
3176         if (builder.getNumComponents(operands[0]) == 1)
3177             frexpIntType = builder.makeIntegerType(32, true);
3178         else
3179             frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0]));
3180         typeId = builder.makeStructResultType(typeId0, frexpIntType);
3181         consumedOperands = 1;
3182         break;
3183     case glslang::EOpLdexp:
3184         libCall = spv::GLSLstd450Ldexp;
3185         break;
3186
3187     default:
3188         return 0;
3189     }
3190
3191     spv::Id id = 0;
3192     if (libCall >= 0) {
3193         // Use an extended instruction from the standard library.
3194         // Construct the call arguments, without modifying the original operands vector.
3195         // We might need the remaining arguments, e.g. in the EOpFrexp case.
3196         std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
3197         id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, callArguments);
3198     } else {
3199         switch (consumedOperands) {
3200         case 0:
3201             // should all be handled by visitAggregate and createNoArgOperation
3202             assert(0);
3203             return 0;
3204         case 1:
3205             // should all be handled by createUnaryOperation
3206             assert(0);
3207             return 0;
3208         case 2:
3209             id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
3210             break;
3211         default:
3212             // anything 3 or over doesn't have l-value operands, so all should be consumed
3213             assert(consumedOperands == operands.size());
3214             id = builder.createOp(opCode, typeId, operands);
3215             break;
3216         }
3217     }
3218
3219     // Decode the return types that were structures
3220     switch (op) {
3221     case glslang::EOpAddCarry:
3222     case glslang::EOpSubBorrow:
3223         builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
3224         id = builder.createCompositeExtract(id, typeId0, 0);
3225         break;
3226     case glslang::EOpUMulExtended:
3227     case glslang::EOpIMulExtended:
3228         builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
3229         builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
3230         break;
3231     case glslang::EOpFrexp:
3232         assert(operands.size() == 2);
3233         builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
3234         id = builder.createCompositeExtract(id, typeId0, 0);
3235         break;
3236     default:
3237         break;
3238     }
3239
3240     builder.setPrecision(id, precision);
3241
3242     return id;
3243 }
3244
3245 // Intrinsics with no arguments, no return value, and no precision.
3246 spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
3247 {
3248     // TODO: get the barrier operands correct
3249
3250     switch (op) {
3251     case glslang::EOpEmitVertex:
3252         builder.createNoResultOp(spv::OpEmitVertex);
3253         return 0;
3254     case glslang::EOpEndPrimitive:
3255         builder.createNoResultOp(spv::OpEndPrimitive);
3256         return 0;
3257     case glslang::EOpBarrier:
3258         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory);
3259         builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsMaskNone);
3260         return 0;
3261     case glslang::EOpMemoryBarrier:
3262         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory);
3263         return 0;
3264     case glslang::EOpMemoryBarrierAtomicCounter:
3265         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
3266         return 0;
3267     case glslang::EOpMemoryBarrierBuffer:
3268         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask);
3269         return 0;
3270     case glslang::EOpMemoryBarrierImage:
3271         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask);
3272         return 0;
3273     case glslang::EOpMemoryBarrierShared:
3274         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask);
3275         return 0;
3276     case glslang::EOpGroupMemoryBarrier:
3277         builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask);
3278         return 0;
3279     default:
3280         spv::MissingFunctionality("unknown operation with no arguments");
3281         return 0;
3282     }
3283 }
3284
3285 spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
3286 {
3287     auto iter = symbolValues.find(symbol->getId());
3288     spv::Id id;
3289     if (symbolValues.end() != iter) {
3290         id = iter->second;
3291         return id;
3292     }
3293
3294     // it was not found, create it
3295     id = createSpvVariable(symbol);
3296     symbolValues[symbol->getId()] = id;
3297
3298     if (! symbol->getType().isStruct()) {
3299         addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
3300         addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
3301         if (symbol->getQualifier().hasLocation())
3302             builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
3303         if (symbol->getQualifier().hasIndex())
3304             builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
3305         if (symbol->getQualifier().hasComponent())
3306             builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
3307         if (glslangIntermediate->getXfbMode()) {
3308             if (symbol->getQualifier().hasXfbStride())
3309                 builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride);
3310             if (symbol->getQualifier().hasXfbBuffer())
3311                 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
3312             if (symbol->getQualifier().hasXfbOffset())
3313                 builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
3314         }
3315     }
3316
3317     addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
3318     if (symbol->getQualifier().hasStream())
3319         builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
3320     if (symbol->getQualifier().hasSet())
3321         builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
3322     if (symbol->getQualifier().hasBinding())
3323         builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
3324     if (glslangIntermediate->getXfbMode()) {
3325         if (symbol->getQualifier().hasXfbStride())
3326             builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride);
3327         if (symbol->getQualifier().hasXfbBuffer())
3328             builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
3329     }
3330
3331     // built-in variable decorations
3332     spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);
3333     if (builtIn != spv::BadValue)
3334         builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
3335
3336     return id;
3337 }
3338
3339 // If 'dec' is valid, add no-operand decoration to an object
3340 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
3341 {
3342     if (dec != spv::BadValue)
3343         builder.addDecoration(id, dec);
3344 }
3345
3346 // If 'dec' is valid, add a one-operand decoration to an object
3347 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value)
3348 {
3349     if (dec != spv::BadValue)
3350         builder.addDecoration(id, dec, value);
3351 }
3352
3353 // If 'dec' is valid, add a no-operand decoration to a struct member
3354 void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
3355 {
3356     if (dec != spv::BadValue)
3357         builder.addMemberDecoration(id, (unsigned)member, dec);
3358 }
3359
3360 // Make a full tree of instructions to build a SPIR-V specialization constant,
3361 // or regularly constant if possible.
3362 //
3363 // TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
3364 //
3365 // Recursively walk the nodes.  The nodes form a tree whose leaves are
3366 // regular constants, which themselves are trees that createSpvConstant()
3367 // recursively walks.  So, this function walks the "top" of the tree:
3368 //  - emit specialization constant-building instructions for specConstant
3369 //  - when running into a non-spec-constant, switch to createSpvConstant()
3370 spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
3371 {
3372     assert(node.getQualifier().storage == glslang::EvqConst);
3373
3374     // hand off to the non-spec-constant path
3375     assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
3376     int nextConst = 0;
3377     return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), nextConst, false);
3378 }
3379
3380 // Use 'consts' as the flattened glslang source of scalar constants to recursively
3381 // build the aggregate SPIR-V constant.
3382 //
3383 // If there are not enough elements present in 'consts', 0 will be substituted;
3384 // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
3385 //
3386 spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
3387 {
3388     // vector of constants for SPIR-V
3389     std::vector<spv::Id> spvConsts;
3390
3391     // Type is used for struct and array constants
3392     spv::Id typeId = convertGlslangToSpvType(glslangType);
3393
3394     if (glslangType.isArray()) {
3395         glslang::TType elementType(glslangType, 0);
3396         for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
3397             spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
3398     } else if (glslangType.isMatrix()) {
3399         glslang::TType vectorType(glslangType, 0);
3400         for (int col = 0; col < glslangType.getMatrixCols(); ++col)
3401             spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
3402     } else if (glslangType.getStruct()) {
3403         glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
3404         for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
3405             spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
3406     } else if (glslangType.isVector()) {
3407         for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
3408             bool zero = nextConst >= consts.size();
3409             switch (glslangType.getBasicType()) {
3410             case glslang::EbtInt:
3411                 spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
3412                 break;
3413             case glslang::EbtUint:
3414                 spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
3415                 break;
3416             case glslang::EbtFloat:
3417                 spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
3418                 break;
3419             case glslang::EbtDouble:
3420                 spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
3421                 break;
3422             case glslang::EbtBool:
3423                 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
3424                 break;
3425             default:
3426                 assert(0);
3427                 break;
3428             }
3429             ++nextConst;
3430         }
3431     } else {
3432         // we have a non-aggregate (scalar) constant
3433         bool zero = nextConst >= consts.size();
3434         spv::Id scalar = 0;
3435         switch (glslangType.getBasicType()) {
3436         case glslang::EbtInt:
3437             scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
3438             break;
3439         case glslang::EbtUint:
3440             scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
3441             break;
3442         case glslang::EbtFloat:
3443             scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
3444             break;
3445         case glslang::EbtDouble:
3446             scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
3447             break;
3448         case glslang::EbtBool:
3449             scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
3450             break;
3451         default:
3452             assert(0);
3453             break;
3454         }
3455         ++nextConst;
3456         return scalar;
3457     }
3458
3459     return builder.makeCompositeConstant(typeId, spvConsts);
3460 }
3461
3462 // Return true if the node is a constant or symbol whose reading has no
3463 // non-trivial observable cost or effect.
3464 bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
3465 {
3466     // don't know what this is
3467     if (node == nullptr)
3468         return false;
3469
3470     // a constant is safe
3471     if (node->getAsConstantUnion() != nullptr)
3472         return true;
3473
3474     // not a symbol means non-trivial
3475     if (node->getAsSymbolNode() == nullptr)
3476         return false;
3477
3478     // a symbol, depends on what's being read
3479     switch (node->getType().getQualifier().storage) {
3480     case glslang::EvqTemporary:
3481     case glslang::EvqGlobal:
3482     case glslang::EvqIn:
3483     case glslang::EvqInOut:
3484     case glslang::EvqConst:
3485     case glslang::EvqConstReadOnly:
3486     case glslang::EvqUniform:
3487         return true;
3488     default:
3489         return false;
3490     }
3491
3492
3493 // A node is trivial if it is a single operation with no side effects.
3494 // Error on the side of saying non-trivial.
3495 // Return true if trivial.
3496 bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
3497 {
3498     if (node == nullptr)
3499         return false;
3500
3501     // symbols and constants are trivial
3502     if (isTrivialLeaf(node))
3503         return true;
3504
3505     // otherwise, it needs to be a simple operation or one or two leaf nodes
3506
3507     // not a simple operation
3508     const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();
3509     const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();
3510     if (binaryNode == nullptr && unaryNode == nullptr)
3511         return false;
3512
3513     // not on leaf nodes
3514     if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))
3515         return false;
3516
3517     if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {
3518         return false;
3519     }
3520
3521     switch (node->getAsOperator()->getOp()) {
3522     case glslang::EOpLogicalNot:
3523     case glslang::EOpConvIntToBool:
3524     case glslang::EOpConvUintToBool:
3525     case glslang::EOpConvFloatToBool:
3526     case glslang::EOpConvDoubleToBool:
3527     case glslang::EOpEqual:
3528     case glslang::EOpNotEqual:
3529     case glslang::EOpLessThan:
3530     case glslang::EOpGreaterThan:
3531     case glslang::EOpLessThanEqual:
3532     case glslang::EOpGreaterThanEqual:
3533     case glslang::EOpIndexDirect:
3534     case glslang::EOpIndexDirectStruct:
3535     case glslang::EOpLogicalXor:
3536     case glslang::EOpAny:
3537     case glslang::EOpAll:
3538         return true;
3539     default:
3540         return false;
3541     }
3542 }
3543
3544 // Emit short-circuiting code, where 'right' is never evaluated unless
3545 // the left side is true (for &&) or false (for ||).
3546 spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, glslang::TIntermTyped& right)
3547 {
3548     spv::Id boolTypeId = builder.makeBoolType();
3549
3550     // emit left operand
3551     builder.clearAccessChain();
3552     left.traverse(this);
3553     spv::Id leftId = builder.accessChainLoad(boolTypeId);
3554
3555     // Operands to accumulate OpPhi operands
3556     std::vector<spv::Id> phiOperands;
3557     // accumulate left operand's phi information
3558     phiOperands.push_back(leftId);
3559     phiOperands.push_back(builder.getBuildPoint()->getId());
3560
3561     // Make the two kinds of operation symmetric with a "!"
3562     //   || => emit "if (! left) result = right"
3563     //   && => emit "if (  left) result = right"
3564     //
3565     // TODO: this runtime "not" for || could be avoided by adding functionality
3566     // to 'builder' to have an "else" without an "then"
3567     if (op == glslang::EOpLogicalOr)
3568         leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);
3569
3570     // make an "if" based on the left value
3571     spv::Builder::If ifBuilder(leftId, builder);
3572
3573     // emit right operand as the "then" part of the "if"
3574     builder.clearAccessChain();
3575     right.traverse(this);
3576     spv::Id rightId = builder.accessChainLoad(boolTypeId);
3577
3578     // accumulate left operand's phi information
3579     phiOperands.push_back(rightId);
3580     phiOperands.push_back(builder.getBuildPoint()->getId());
3581
3582     // finish the "if"
3583     ifBuilder.makeEndIf();
3584
3585     // phi together the two results
3586     return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);
3587 }
3588
3589 };  // end anonymous namespace
3590
3591 namespace glslang {
3592
3593 void GetSpirvVersion(std::string& version)
3594 {
3595     const int bufSize = 100;
3596     char buf[bufSize];
3597     snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
3598     version = buf;
3599 }
3600
3601 // Write SPIR-V out to a binary file
3602 void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
3603 {
3604     std::ofstream out;
3605     out.open(baseName, std::ios::binary | std::ios::out);
3606     for (int i = 0; i < (int)spirv.size(); ++i) {
3607         unsigned int word = spirv[i];
3608         out.write((const char*)&word, 4);
3609     }
3610     out.close();
3611 }
3612
3613 //
3614 // Set up the glslang traversal
3615 //
3616 void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
3617 {
3618     TIntermNode* root = intermediate.getTreeRoot();
3619
3620     if (root == 0)
3621         return;
3622
3623     glslang::GetThreadPoolAllocator().push();
3624
3625     TGlslangToSpvTraverser it(&intermediate);
3626
3627     root->traverse(&it);
3628
3629     it.dumpSpv(spirv);
3630
3631     glslang::GetThreadPoolAllocator().pop();
3632 }
3633
3634 }; // end namespace glslang