glslang: Fix over 100 warnings from MSVC warning level 4.
[platform/upstream/glslang.git] / SPIRV / GlslangToSpv.cpp
1 //\r
2 //Copyright (C) 2014 LunarG, Inc.\r
3 //\r
4 //All rights reserved.\r
5 //\r
6 //Redistribution and use in source and binary forms, with or without\r
7 //modification, are permitted provided that the following conditions\r
8 //are met:\r
9 //\r
10 //    Redistributions of source code must retain the above copyright\r
11 //    notice, this list of conditions and the following disclaimer.\r
12 //\r
13 //    Redistributions in binary form must reproduce the above\r
14 //    copyright notice, this list of conditions and the following\r
15 //    disclaimer in the documentation and/or other materials provided\r
16 //    with the distribution.\r
17 //\r
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its\r
19 //    contributors may be used to endorse or promote products derived\r
20 //    from this software without specific prior written permission.\r
21 //\r
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
33 //POSSIBILITY OF SUCH DAMAGE.\r
34 \r
35 //\r
36 // Author: John Kessenich, LunarG\r
37 //\r
38 // Visit the nodes in the glslang intermediate tree representation to\r
39 // translate them to SPIR-V.\r
40 //\r
41 \r
42 #include "spirv.h"\r
43 #include "GlslangToSpv.h"\r
44 #include "SpvBuilder.h"\r
45 #include "GLSL450Lib.h"\r
46 \r
47 // Glslang includes\r
48 #include "glslang/MachineIndependent/localintermediate.h"\r
49 #include "glslang/MachineIndependent/SymbolTable.h"\r
50 \r
51 #include <string>\r
52 #include <map>\r
53 #include <list>\r
54 #include <vector>\r
55 #include <stack>\r
56 #include <fstream>\r
57 \r
58 namespace {\r
59 \r
60 const int GlslangMagic = 0x51a;\r
61 \r
62 //\r
63 // The main holder of information for translating glslang to SPIR-V.\r
64 //\r
65 // Derives from the AST walking base class.\r
66 //\r
67 class TGlslangToSpvTraverser : public glslang::TIntermTraverser {\r
68 public:\r
69     TGlslangToSpvTraverser(const glslang::TIntermediate*);\r
70     virtual ~TGlslangToSpvTraverser();\r
71 \r
72     bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);\r
73     bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);\r
74     void visitConstantUnion(glslang::TIntermConstantUnion*);\r
75     bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);\r
76     bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);\r
77     void visitSymbol(glslang::TIntermSymbol* symbol);\r
78     bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);\r
79     bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);\r
80     bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);\r
81 \r
82     void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }\r
83 \r
84 protected:\r
85     spv::Id createSpvVariable(const glslang::TIntermSymbol*);\r
86     spv::Id getSampledType(const glslang::TSampler&);\r
87     spv::Id convertGlslangToSpvType(const glslang::TType& type);\r
88 \r
89     bool isShaderEntrypoint(const glslang::TIntermAggregate* node);\r
90     void makeFunctions(const glslang::TIntermSequence&);\r
91     void makeGlobalInitializers(const glslang::TIntermSequence&);\r
92     void visitFunctions(const glslang::TIntermSequence&);\r
93     void handleFunctionEntry(const glslang::TIntermAggregate* node);\r
94     void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);\r
95     spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);\r
96     spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);\r
97 \r
98     spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);\r
99     spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);\r
100     spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);\r
101     spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);\r
102     spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);\r
103     spv::Id createNoArgOperation(glslang::TOperator op);\r
104     spv::Id getSymbolId(const glslang::TIntermSymbol* node);\r
105     void addDecoration(spv::Id id, spv::Decoration dec);\r
106     void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);\r
107     spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);\r
108 \r
109     spv::Function* shaderEntry;\r
110     int sequenceDepth;\r
111 \r
112     // There is a 1:1 mapping between a spv builder and a module; this is thread safe\r
113     spv::Builder builder;\r
114     bool inMain;\r
115     bool mainTerminated;\r
116     bool linkageOnly;\r
117     const glslang::TIntermediate* glslangIntermediate;\r
118     spv::Id stdBuiltins;\r
119 \r
120     std::map<int, spv::Id> symbolValues;\r
121     std::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\r
122     std::map<std::string, spv::Function*> functionMap;\r
123     std::map<const glslang::TTypeList*, spv::Id> structMap;\r
124     std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper;  // for mapping glslang block indices to spv indices (e.g., due to hidden members)\r
125     std::stack<bool> breakForLoop;  // false means break for switch\r
126     std::stack<glslang::TIntermTyped*> loopTerminal;  // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };\r
127 };\r
128 \r
129 //\r
130 // Helper functions for translating glslang representations to SPIR-V enumerants.\r
131 //\r
132 \r
133 // Translate glslang language (stage) to SPIR-V execution model.\r
134 spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)\r
135 {\r
136     switch (stage) {\r
137     case EShLangVertex:           return spv::ExecutionModelVertex;\r
138     case EShLangTessControl:      return spv::ExecutionModelTessellationControl;\r
139     case EShLangTessEvaluation:   return spv::ExecutionModelTessellationEvaluation;\r
140     case EShLangGeometry:         return spv::ExecutionModelGeometry;\r
141     case EShLangFragment:         return spv::ExecutionModelFragment;\r
142     case EShLangCompute:          return spv::ExecutionModelGLCompute;\r
143     default:\r
144         spv::MissingFunctionality("GLSL stage");\r
145         return spv::ExecutionModelFragment;\r
146     }\r
147 }\r
148 \r
149 // Translate glslang type to SPIR-V storage class.\r
150 spv::StorageClass TranslateStorageClass(const glslang::TType& type)\r
151 {\r
152     if (type.getQualifier().isPipeInput())\r
153         return spv::StorageClassInput;\r
154     else if (type.getQualifier().isPipeOutput())\r
155         return spv::StorageClassOutput;\r
156     else if (type.getQualifier().isUniformOrBuffer()) {\r
157         if (type.getBasicType() == glslang::EbtBlock)\r
158             return spv::StorageClassUniform;\r
159         else\r
160             return spv::StorageClassUniformConstant;\r
161         // TODO: how are we distuingishing between default and non-default non-writable uniforms?  Do default uniforms even exist?\r
162     } else {\r
163         switch (type.getQualifier().storage) {\r
164         case glslang::EvqShared:        return spv::StorageClassWorkgroupLocal;  break;\r
165         case glslang::EvqGlobal:        return spv::StorageClassPrivateGlobal;\r
166         case glslang::EvqConstReadOnly: return spv::StorageClassFunction;\r
167         case glslang::EvqTemporary:     return spv::StorageClassFunction;\r
168         default: \r
169             spv::MissingFunctionality("unknown glslang storage class");\r
170             return spv::StorageClassFunction;\r
171         }\r
172     }\r
173 }\r
174 \r
175 // Translate glslang sampler type to SPIR-V dimensionality.\r
176 spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)\r
177 {\r
178     switch (sampler.dim) {\r
179     case glslang::Esd1D:     return spv::Dim1D;\r
180     case glslang::Esd2D:     return spv::Dim2D;\r
181     case glslang::Esd3D:     return spv::Dim3D;\r
182     case glslang::EsdCube:   return spv::DimCube;\r
183     case glslang::EsdRect:   return spv::DimRect;\r
184     case glslang::EsdBuffer: return spv::DimBuffer;\r
185     default:\r
186         spv::MissingFunctionality("unknown sampler dimension");\r
187         return spv::Dim2D;\r
188     }\r
189 }\r
190 \r
191 // Translate glslang type to SPIR-V precision decorations.\r
192 spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)\r
193 {\r
194     switch (type.getQualifier().precision) {\r
195     case glslang::EpqLow:    return spv::DecorationPrecisionLow;\r
196     case glslang::EpqMedium: return spv::DecorationPrecisionMedium;\r
197     case glslang::EpqHigh:   return spv::DecorationPrecisionHigh;\r
198     default:\r
199         return spv::NoPrecision;\r
200     }\r
201 }\r
202 \r
203 // Translate glslang type to SPIR-V block decorations.\r
204 spv::Decoration TranslateBlockDecoration(const glslang::TType& type)\r
205 {\r
206     if (type.getBasicType() == glslang::EbtBlock) {\r
207         switch (type.getQualifier().storage) {\r
208         case glslang::EvqUniform:      return spv::DecorationBlock;\r
209         case glslang::EvqBuffer:       return spv::DecorationBufferBlock;\r
210         case glslang::EvqVaryingIn:    return spv::DecorationBlock;\r
211         case glslang::EvqVaryingOut:   return spv::DecorationBlock;\r
212         default:\r
213             spv::MissingFunctionality("kind of block");\r
214             break;\r
215         }\r
216     }\r
217 \r
218     return (spv::Decoration)spv::BadValue;\r
219 }\r
220 \r
221 // Translate glslang type to SPIR-V layout decorations.\r
222 spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)\r
223 {\r
224     if (type.isMatrix()) {\r
225         switch (type.getQualifier().layoutMatrix) {\r
226         case glslang::ElmRowMajor:\r
227             return spv::DecorationRowMajor;\r
228         default:\r
229             return spv::DecorationColMajor;\r
230         }\r
231     } else {\r
232         switch (type.getBasicType()) {\r
233         default:\r
234             return (spv::Decoration)spv::BadValue;\r
235             break;\r
236         case glslang::EbtBlock:\r
237             switch (type.getQualifier().storage) {\r
238             case glslang::EvqUniform:\r
239             case glslang::EvqBuffer:\r
240                 switch (type.getQualifier().layoutPacking) {\r
241                 case glslang::ElpShared:  return spv::DecorationGLSLShared;\r
242                 case glslang::ElpStd140:  return spv::DecorationGLSLStd140;\r
243                 case glslang::ElpStd430:  return spv::DecorationGLSLStd430;\r
244                 case glslang::ElpPacked:  return spv::DecorationGLSLPacked;\r
245                 default:\r
246                     spv::MissingFunctionality("uniform block layout");\r
247                     return spv::DecorationGLSLShared;\r
248                 }\r
249             case glslang::EvqVaryingIn:\r
250             case glslang::EvqVaryingOut:\r
251                 if (type.getQualifier().layoutPacking != glslang::ElpNone)\r
252                     spv::MissingFunctionality("in/out block layout");\r
253                 return (spv::Decoration)spv::BadValue;\r
254             default:\r
255                 spv::MissingFunctionality("block storage qualification");\r
256                 return (spv::Decoration)spv::BadValue;\r
257             }\r
258         }\r
259     }\r
260 }\r
261 \r
262 // Translate glslang type to SPIR-V interpolation decorations.\r
263 spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)\r
264 {\r
265     if (type.getQualifier().smooth)\r
266         return spv::DecorationSmooth;\r
267     if (type.getQualifier().nopersp)\r
268         return spv::DecorationNoperspective;\r
269     else if (type.getQualifier().patch)\r
270         return spv::DecorationPatch;\r
271     else if (type.getQualifier().flat)\r
272         return spv::DecorationFlat;\r
273     else if (type.getQualifier().centroid)\r
274         return spv::DecorationCentroid;\r
275     else if (type.getQualifier().sample)\r
276         return spv::DecorationSample;\r
277     else\r
278         return (spv::Decoration)spv::BadValue;\r
279 }\r
280 \r
281 // If glslang type is invaraiant, return SPIR-V invariant decoration.\r
282 spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)\r
283 {\r
284     if (type.getQualifier().invariant)\r
285         return spv::DecorationInvariant;\r
286     else\r
287         return (spv::Decoration)spv::BadValue;\r
288 }\r
289 \r
290 // Translate glslang built-in variable to SPIR-V built in decoration.\r
291 spv::BuiltIn TranslateBuiltInDecoration(const glslang::TIntermSymbol& node)\r
292 {\r
293     const glslang::TString& name = node.getName();\r
294     if (name.compare(0, 3, "gl_") != 0)\r
295         return (spv::BuiltIn)spv::BadValue;\r
296 \r
297     switch (node.getQualifier().storage) {\r
298     case glslang::EvqPosition:   return spv::BuiltInPosition;\r
299     case glslang::EvqPointSize:  return spv::BuiltInPointSize;\r
300     case glslang::EvqClipVertex: return spv::BuiltInClipVertex;\r
301     case glslang::EvqVertexId:   return spv::BuiltInVertexId;\r
302     case glslang::EvqInstanceId: return spv::BuiltInInstanceId;\r
303     case glslang::EvqFragCoord:  return spv::BuiltInFragCoord;\r
304     case glslang::EvqPointCoord: return spv::BuiltInPointCoord;\r
305     case glslang::EvqFace:       return spv::BuiltInFrontFacing;\r
306     case glslang::EvqFragColor:  return spv::BuiltInFragColor;\r
307     case glslang::EvqFragDepth:  return spv::BuiltInFragDepth;\r
308     default:\r
309         if (name == "gl_ClipDistance")\r
310             return spv::BuiltInClipDistance;\r
311         else if (name == "gl_PrimitiveID" || name == "gl_PrimitiveIDIn")\r
312             return spv::BuiltInPrimitiveId;\r
313         else if (name == "gl_InvocationID")\r
314             return spv::BuiltInInvocationId;\r
315         else if (name == "gl_Layer")\r
316             return spv::BuiltInLayer;\r
317         else if (name == "gl_ViewportIndex")\r
318             return spv::BuiltInViewportIndex;\r
319         else if (name == "gl_TessLevelOuter")\r
320             return spv::BuiltInTessLevelOuter;\r
321         else if (name == "gl_TessLevelInner")\r
322             return spv::BuiltInTessLevelInner;\r
323         else if (name == "gl_TessCoord")\r
324             return spv::BuiltInTessCoord;\r
325         else if (name == "gl_PatchVerticesIn")\r
326             return spv::BuiltInPatchVertices;\r
327         else if (name == "gl_SampleID")\r
328             return spv::BuiltInSampleId;\r
329         else if (name == "gl_SamplePosition")\r
330             return spv::BuiltInSamplePosition;\r
331         else if (name == "gl_SampleMask" || name == "gl_SampleMaskIn")\r
332             return spv::BuiltInSampleMask;\r
333 \r
334         // Compute shader:\r
335         else if (name == "gl_NumWorkGroups")\r
336             return spv::BuiltInNumWorkgroups;\r
337         else if (name == "gl_WorkGroupSize")\r
338             return spv::BuiltInWorkgroupSize;\r
339         else if (name == "gl_WorkGroupID")\r
340             return spv::BuiltInWorkgroupId;\r
341         else if (name == "gl_LocalInvocationID")\r
342             return spv::BuiltInLocalInvocationId;\r
343         else if (name == "gl_GlobalInvocationID")\r
344             return spv::BuiltInGlobalInvocationId;\r
345         else if (name == "gl_LocalInvocationIndexID")\r
346             return spv::BuiltInLocalInvocationIndex;\r
347         break;\r
348     }\r
349 \r
350     return (spv::BuiltIn)spv::BadValue;\r
351 }\r
352 \r
353 //\r
354 // Implement the TGlslangToSpvTraverser class.\r
355 //\r
356 \r
357 TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)\r
358     : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),\r
359       builder(GlslangMagic),\r
360       inMain(false), mainTerminated(false), linkageOnly(false),\r
361       glslangIntermediate(glslangIntermediate)\r
362 {\r
363     spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());\r
364 \r
365     builder.clearAccessChain();\r
366     builder.setSource(spv::SourceLanguageGLSL, glslangIntermediate->getVersion());\r
367     stdBuiltins = builder.import("GLSL.std.450");\r
368     builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);\r
369     shaderEntry = builder.makeMain();\r
370     builder.addEntryPoint(executionModel, shaderEntry);\r
371 \r
372     // Add the source extensions\r
373     const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();\r
374     for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)\r
375         builder.addSourceExtension(it->c_str());\r
376 \r
377     // Add the top-level modes for this shader.\r
378 \r
379     if (glslangIntermediate->getXfbMode())\r
380         builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);\r
381 \r
382     spv::ExecutionMode mode;\r
383     switch (glslangIntermediate->getStage()) {\r
384     case EShLangVertex:\r
385         break;\r
386 \r
387     case EShLangTessControl:\r
388         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());\r
389         break;\r
390 \r
391     case EShLangTessEvaluation:\r
392         switch (glslangIntermediate->getInputPrimitive()) {\r
393         case glslang::ElgTriangles:           mode = spv::ExecutionModeInputTriangles;     break;\r
394         case glslang::ElgQuads:               mode = spv::ExecutionModeInputQuads;         break;\r
395         case glslang::ElgIsolines:            mode = spv::ExecutionModeInputIsolines;      break;\r
396         default:                              mode = (spv::ExecutionMode)spv::BadValue;    break;\r
397         }\r
398         if (mode != spv::BadValue)\r
399             builder.addExecutionMode(shaderEntry, mode);\r
400 \r
401         // TODO\r
402         //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());\r
403         //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());\r
404         //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());\r
405         break;\r
406 \r
407     case EShLangGeometry:\r
408         switch (glslangIntermediate->getInputPrimitive()) {\r
409         case glslang::ElgPoints:             mode = spv::ExecutionModeInputPoints;             break;\r
410         case glslang::ElgLines:              mode = spv::ExecutionModeInputLines;              break;\r
411         case glslang::ElgLinesAdjacency:     mode = spv::ExecutionModeInputLinesAdjacency;     break;\r
412         case glslang::ElgTriangles:          mode = spv::ExecutionModeInputTriangles;          break;\r
413         case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;\r
414         default:                             mode = (spv::ExecutionMode)spv::BadValue;         break;\r
415         }\r
416         if (mode != spv::BadValue)\r
417             builder.addExecutionMode(shaderEntry, mode);\r
418         builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());\r
419 \r
420         switch (glslangIntermediate->getOutputPrimitive()) {\r
421         case glslang::ElgPoints:        mode = spv::ExecutionModeOutputPoints;                 break;\r
422         case glslang::ElgLineStrip:     mode = spv::ExecutionModeOutputLineStrip;              break;\r
423         case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip;          break;\r
424         default:                        mode = (spv::ExecutionMode)spv::BadValue;              break;\r
425         }\r
426         if (mode != spv::BadValue)\r
427             builder.addExecutionMode(shaderEntry, mode);\r
428         builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());\r
429         break;\r
430 \r
431     case EShLangFragment:\r
432         if (glslangIntermediate->getPixelCenterInteger())\r
433             builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);\r
434         if (glslangIntermediate->getOriginUpperLeft())\r
435             builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);\r
436         break;\r
437 \r
438     case EShLangCompute:\r
439         break;\r
440 \r
441     default:\r
442         break;\r
443     }\r
444 \r
445 }\r
446 \r
447 TGlslangToSpvTraverser::~TGlslangToSpvTraverser()\r
448 {\r
449     if (! mainTerminated) {\r
450         spv::Block* lastMainBlock = shaderEntry->getLastBlock();\r
451         builder.setBuildPoint(lastMainBlock);\r
452         builder.leaveFunction(true);\r
453     }\r
454 }\r
455 \r
456 //\r
457 // Implement the traversal functions.\r
458 //\r
459 // Return true from interior nodes to have the external traversal\r
460 // continue on to children.  Return false if children were\r
461 // already processed.\r
462 //\r
463 \r
464 //\r
465 // Symbols can turn into \r
466 //  - uniform/input reads\r
467 //  - output writes\r
468 //  - complex lvalue base setups:  foo.bar[3]....  , where we see foo and start up an access chain\r
469 //  - something simple that degenerates into the last bullet\r
470 //\r
471 void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)\r
472 {\r
473     // getSymbolId() will set up all the IO decorations on the first call.\r
474     // Formal function parameters were mapped during makeFunctions().\r
475     spv::Id id = getSymbolId(symbol);\r
476     \r
477     if (! linkageOnly) {\r
478         // Prepare to generate code for the access\r
479 \r
480         // L-value chains will be computed left to right.  We're on the symbol now,\r
481         // which is the left-most part of the access chain, so now is "clear" time,\r
482         // followed by setting the base.\r
483         builder.clearAccessChain();\r
484 \r
485         // For now, we consider all user variables as being in memory, so they are pointers,\r
486         // except for "const in" arguments to a function, which are an intermediate object.\r
487         // See comments in handleUserFunctionCall().\r
488         glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;\r
489         if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())\r
490             builder.setAccessChainRValue(id);\r
491         else\r
492             builder.setAccessChainLValue(id);\r
493     }\r
494 }\r
495 \r
496 bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)\r
497 {\r
498     // First, handle special cases\r
499     switch (node->getOp()) {\r
500     case glslang::EOpAssign:\r
501     case glslang::EOpAddAssign:\r
502     case glslang::EOpSubAssign:\r
503     case glslang::EOpMulAssign:\r
504     case glslang::EOpVectorTimesMatrixAssign:\r
505     case glslang::EOpVectorTimesScalarAssign:\r
506     case glslang::EOpMatrixTimesScalarAssign:\r
507     case glslang::EOpMatrixTimesMatrixAssign:\r
508     case glslang::EOpDivAssign:\r
509     case glslang::EOpModAssign:\r
510     case glslang::EOpAndAssign:\r
511     case glslang::EOpInclusiveOrAssign:\r
512     case glslang::EOpExclusiveOrAssign:\r
513     case glslang::EOpLeftShiftAssign:\r
514     case glslang::EOpRightShiftAssign:\r
515         // A bin-op assign "a += b" means the same thing as "a = a + b"\r
516         // where a is evaluated before b. For a simple assignment, GLSL\r
517         // says to evaluate the left before the right.  So, always, left\r
518         // node then right node.\r
519         {\r
520             // get the left l-value, save it away\r
521             builder.clearAccessChain();\r
522             node->getLeft()->traverse(this);\r
523             spv::Builder::AccessChain lValue = builder.getAccessChain();\r
524 \r
525             // evaluate the right\r
526             builder.clearAccessChain();\r
527             node->getRight()->traverse(this);\r
528             spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
529 \r
530             if (node->getOp() != glslang::EOpAssign) {\r
531                 // the left is also an r-value\r
532                 builder.setAccessChain(lValue);\r
533                 spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));\r
534 \r
535                 // do the operation\r
536                 rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()), \r
537                                                convertGlslangToSpvType(node->getType()), leftRValue, rValue,\r
538                                                node->getType().getBasicType());\r
539 \r
540                 // these all need their counterparts in createBinaryOperation()\r
541                 if (rValue == 0)\r
542                     spv::MissingFunctionality("createBinaryOperation");\r
543             }\r
544 \r
545             // store the result\r
546             builder.setAccessChain(lValue);\r
547             builder.accessChainStore(rValue);\r
548 \r
549             // assignments are expressions having an rValue after they are evaluated...\r
550             builder.clearAccessChain();\r
551             builder.setAccessChainRValue(rValue);\r
552         }\r
553         return false;\r
554     case glslang::EOpIndexDirect:\r
555     case glslang::EOpIndexDirectStruct:\r
556         {\r
557             // Get the left part of the access chain.\r
558             node->getLeft()->traverse(this);\r
559 \r
560             // Add the next element in the chain\r
561 \r
562             int index = 0;\r
563             if (node->getRight()->getAsConstantUnion() == 0)\r
564                 spv::MissingFunctionality("direct index without a constant node");\r
565             else \r
566                 index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
567 \r
568             if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {\r
569                 // This may be, e.g., an anonymous block-member selection, which generally need\r
570                 // index remapping due to hidden members in anonymous blocks.\r
571                 std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];\r
572                 if (remapper.size() == 0)\r
573                     spv::MissingFunctionality("block without member remapping");\r
574                 else\r
575                     index = remapper[index];\r
576             }\r
577 \r
578             if (! node->getLeft()->getType().isArray() &&\r
579                 node->getLeft()->getType().isVector() &&\r
580                 node->getOp() == glslang::EOpIndexDirect) {\r
581                 // This is essentially a hard-coded vector swizzle of size 1,\r
582                 // so short circuit the access-chain stuff with a swizzle.\r
583                 std::vector<unsigned> swizzle;\r
584                 swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());\r
585                 builder.accessChainPushSwizzle(swizzle, node->getLeft()->getVectorSize(), convertGlslangToSpvType(node->getType()));\r
586             } else {\r
587                 // normal case for indexing array or structure or block\r
588                 builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));\r
589             }\r
590         }\r
591         return false;\r
592     case glslang::EOpIndexIndirect:\r
593         {\r
594             // Structure or array or vector indirection.\r
595             // Will use native SPIR-V access-chain for struct and array indirection;\r
596             // matrices are arrays of vectors, so will also work for a matrix.\r
597             // Will use the access chain's 'component' for variable index into a vector.\r
598 \r
599             // This adapter is building access chains left to right.\r
600             // Set up the access chain to the left.\r
601             node->getLeft()->traverse(this);\r
602 \r
603             // save it so that computing the right side doesn't trash it\r
604             spv::Builder::AccessChain partial = builder.getAccessChain();\r
605 \r
606             // compute the next index in the chain\r
607             builder.clearAccessChain();\r
608             node->getRight()->traverse(this);\r
609             spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
610 \r
611             // restore the saved access chain\r
612             builder.setAccessChain(partial);\r
613 \r
614             if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())\r
615                 builder.accessChainPushComponent(index);\r
616             else\r
617                 builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));\r
618         }\r
619         return false;\r
620     case glslang::EOpVectorSwizzle:\r
621         {\r
622             node->getLeft()->traverse(this);\r
623             glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();\r
624             std::vector<unsigned> swizzle;\r
625             for (int i = 0; i < (int)swizzleSequence.size(); ++i)\r
626                 swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());\r
627             builder.accessChainPushSwizzle(swizzle, node->getLeft()->getVectorSize(), convertGlslangToSpvType(node->getType()));\r
628         }\r
629         return false;\r
630     default:\r
631         break;\r
632     }\r
633 \r
634     // Assume generic binary op...\r
635 \r
636     // Get the operands\r
637     builder.clearAccessChain();\r
638     node->getLeft()->traverse(this);\r
639     spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));\r
640 \r
641     builder.clearAccessChain();\r
642     node->getRight()->traverse(this);\r
643     spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));\r
644 \r
645     spv::Id result;\r
646     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
647 \r
648     result = createBinaryOperation(node->getOp(), precision, \r
649                                    convertGlslangToSpvType(node->getType()), left, right,\r
650                                    node->getLeft()->getType().getBasicType());\r
651 \r
652     if (! result) {\r
653         spv::MissingFunctionality("glslang binary operation");\r
654     } else {\r
655         builder.clearAccessChain();\r
656         builder.setAccessChainRValue(result);\r
657 \r
658         return false;\r
659     }\r
660 \r
661     return true;\r
662 }\r
663 \r
664 bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)\r
665 {\r
666     builder.clearAccessChain();\r
667     node->getOperand()->traverse(this);\r
668     spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));\r
669 \r
670     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
671 \r
672     // it could be a conversion\r
673     spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);\r
674 \r
675     // if not, then possibly an operation\r
676     if (! result)\r
677         result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);\r
678 \r
679     if (result) {\r
680         builder.clearAccessChain();\r
681         builder.setAccessChainRValue(result);\r
682 \r
683         return false; // done with this node\r
684     }\r
685 \r
686     // it must be a special case, check...\r
687     switch (node->getOp()) {\r
688     case glslang::EOpPostIncrement:\r
689     case glslang::EOpPostDecrement:\r
690     case glslang::EOpPreIncrement:\r
691     case glslang::EOpPreDecrement:\r
692         {\r
693             // we need the integer value "1" or the floating point "1.0" to add/subtract\r
694             spv::Id one = node->getBasicType() == glslang::EbtFloat ?\r
695                                      builder.makeFloatConstant(1.0F) :\r
696                                      builder.makeIntConstant(1);\r
697             glslang::TOperator op;\r
698             if (node->getOp() == glslang::EOpPreIncrement ||\r
699                 node->getOp() == glslang::EOpPostIncrement)\r
700                 op = glslang::EOpAdd;\r
701             else\r
702                 op = glslang::EOpSub;\r
703 \r
704             spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()), \r
705                                                      convertGlslangToSpvType(node->getType()), operand, one, \r
706                                                      node->getType().getBasicType());\r
707             if (result == 0)\r
708                 spv::MissingFunctionality("createBinaryOperation for unary");\r
709 \r
710             // The result of operation is always stored, but conditionally the\r
711             // consumed result.  The consumed result is always an r-value.\r
712             builder.accessChainStore(result);\r
713             builder.clearAccessChain();\r
714             if (node->getOp() == glslang::EOpPreIncrement ||\r
715                 node->getOp() == glslang::EOpPreDecrement)\r
716                 builder.setAccessChainRValue(result);\r
717             else\r
718                 builder.setAccessChainRValue(operand);\r
719         }\r
720 \r
721         return false;\r
722 \r
723     case glslang::EOpEmitStreamVertex:\r
724         builder.createNoResultOp(spv::OpEmitStreamVertex, operand);\r
725         return false;\r
726     case glslang::EOpEndStreamPrimitive:\r
727         builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);\r
728         return false;\r
729 \r
730     default:\r
731         spv::MissingFunctionality("glslang unary");\r
732         break;\r
733     }\r
734 \r
735     return true;\r
736 }\r
737 \r
738 bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)\r
739 {\r
740     spv::Id result;\r
741     glslang::TOperator binOp = glslang::EOpNull;\r
742     bool reduceComparison = true;\r
743     bool isMatrix = false;\r
744     bool noReturnValue = false;\r
745 \r
746     assert(node->getOp());\r
747 \r
748     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
749 \r
750     switch (node->getOp()) {\r
751     case glslang::EOpSequence:\r
752     {\r
753         if (preVisit)\r
754             ++sequenceDepth;\r
755         else\r
756             --sequenceDepth;\r
757 \r
758         if (sequenceDepth == 1) {\r
759             // If this is the parent node of all the functions, we want to see them\r
760             // early, so all call points have actual SPIR-V functions to reference.\r
761             // In all cases, still let the traverser visit the children for us.\r
762             makeFunctions(node->getAsAggregate()->getSequence());\r
763 \r
764             // Also, we want all globals initializers to go into the entry of main(), before\r
765             // anything else gets there, so visit out of order, doing them all now.\r
766             makeGlobalInitializers(node->getAsAggregate()->getSequence());\r
767 \r
768             // Initializers are done, don't want to visit again, but functions link objects need to be processed,\r
769             // so do them manually.\r
770             visitFunctions(node->getAsAggregate()->getSequence());\r
771 \r
772             return false;\r
773         }\r
774 \r
775         return true;\r
776     }\r
777     case glslang::EOpLinkerObjects:\r
778     {\r
779         if (visit == glslang::EvPreVisit)\r
780             linkageOnly = true;\r
781         else\r
782             linkageOnly = false;\r
783 \r
784         return true;\r
785     }\r
786     case glslang::EOpComma:\r
787     {\r
788         // processing from left to right naturally leaves the right-most\r
789         // lying around in the access chain\r
790         glslang::TIntermSequence& glslangOperands = node->getSequence();\r
791         for (int i = 0; i < (int)glslangOperands.size(); ++i)\r
792             glslangOperands[i]->traverse(this);\r
793 \r
794         return false;\r
795     }\r
796     case glslang::EOpFunction:\r
797         if (visit == glslang::EvPreVisit) {\r
798             if (isShaderEntrypoint(node)) {\r
799                 inMain = true;\r
800                 builder.setBuildPoint(shaderEntry->getLastBlock());\r
801             } else {\r
802                 handleFunctionEntry(node);\r
803             }\r
804         } else {\r
805             if (inMain)\r
806                 mainTerminated = true;\r
807             builder.leaveFunction(inMain);\r
808             inMain = false;\r
809         }\r
810 \r
811         return true;\r
812     case glslang::EOpParameters:\r
813         // Parameters will have been consumed by EOpFunction processing, but not\r
814         // the body, so we still visited the function node's children, making this\r
815         // child redundant.\r
816         return false;\r
817     case glslang::EOpFunctionCall:\r
818     {\r
819         if (node->isUserDefined())\r
820             result = handleUserFunctionCall(node);\r
821         else\r
822             result = handleBuiltInFunctionCall(node);\r
823 \r
824         if (! result) {\r
825             spv::MissingFunctionality("glslang function call");\r
826             glslang::TConstUnionArray emptyConsts;\r
827             int nextConst = 0;\r
828             result = createSpvConstant(node->getType(), emptyConsts, nextConst);\r
829         }\r
830         builder.clearAccessChain();\r
831         builder.setAccessChainRValue(result);\r
832 \r
833         return false;\r
834     }\r
835     case glslang::EOpConstructMat2x2:\r
836     case glslang::EOpConstructMat2x3:\r
837     case glslang::EOpConstructMat2x4:\r
838     case glslang::EOpConstructMat3x2:\r
839     case glslang::EOpConstructMat3x3:\r
840     case glslang::EOpConstructMat3x4:\r
841     case glslang::EOpConstructMat4x2:\r
842     case glslang::EOpConstructMat4x3:\r
843     case glslang::EOpConstructMat4x4:\r
844     case glslang::EOpConstructDMat2x2:\r
845     case glslang::EOpConstructDMat2x3:\r
846     case glslang::EOpConstructDMat2x4:\r
847     case glslang::EOpConstructDMat3x2:\r
848     case glslang::EOpConstructDMat3x3:\r
849     case glslang::EOpConstructDMat3x4:\r
850     case glslang::EOpConstructDMat4x2:\r
851     case glslang::EOpConstructDMat4x3:\r
852     case glslang::EOpConstructDMat4x4:\r
853         isMatrix = true;\r
854         // fall through\r
855     case glslang::EOpConstructFloat:\r
856     case glslang::EOpConstructVec2:\r
857     case glslang::EOpConstructVec3:\r
858     case glslang::EOpConstructVec4:\r
859     case glslang::EOpConstructDouble:\r
860     case glslang::EOpConstructDVec2:\r
861     case glslang::EOpConstructDVec3:\r
862     case glslang::EOpConstructDVec4:\r
863     case glslang::EOpConstructBool:\r
864     case glslang::EOpConstructBVec2:\r
865     case glslang::EOpConstructBVec3:\r
866     case glslang::EOpConstructBVec4:\r
867     case glslang::EOpConstructInt:\r
868     case glslang::EOpConstructIVec2:\r
869     case glslang::EOpConstructIVec3:\r
870     case glslang::EOpConstructIVec4:\r
871     case glslang::EOpConstructUint:\r
872     case glslang::EOpConstructUVec2:\r
873     case glslang::EOpConstructUVec3:\r
874     case glslang::EOpConstructUVec4:\r
875     case glslang::EOpConstructStruct:\r
876     {\r
877         std::vector<spv::Id> arguments;\r
878         translateArguments(node->getSequence(), arguments);\r
879         spv::Id resultTypeId = convertGlslangToSpvType(node->getType());\r
880         spv::Id constructed;\r
881         if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {\r
882             std::vector<spv::Id> constituents;\r
883             for (int c = 0; c < (int)arguments.size(); ++c)\r
884                 constituents.push_back(arguments[c]);\r
885             constructed = builder.createCompositeConstruct(resultTypeId, constituents);\r
886         } else {\r
887             if (isMatrix)\r
888                 constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);\r
889             else\r
890                 constructed = builder.createConstructor(precision, arguments, resultTypeId);\r
891         }\r
892 \r
893         builder.clearAccessChain();\r
894         builder.setAccessChainRValue(constructed);\r
895 \r
896         return false;\r
897     }\r
898 \r
899     // These six are component-wise compares with component-wise results.\r
900     // Forward on to createBinaryOperation(), requesting a vector result.\r
901     case glslang::EOpLessThan:\r
902     case glslang::EOpGreaterThan:\r
903     case glslang::EOpLessThanEqual:\r
904     case glslang::EOpGreaterThanEqual:\r
905     case glslang::EOpVectorEqual:\r
906     case glslang::EOpVectorNotEqual:\r
907     {\r
908         // Map the operation to a binary\r
909         binOp = node->getOp();\r
910         reduceComparison = false;\r
911         switch (node->getOp()) {\r
912         case glslang::EOpVectorEqual:     binOp = glslang::EOpVectorEqual;      break;\r
913         case glslang::EOpVectorNotEqual:  binOp = glslang::EOpVectorNotEqual;   break;\r
914         default:                          binOp = node->getOp();                break;\r
915         }\r
916 \r
917         break;\r
918     }\r
919     case glslang::EOpMul:\r
920         // compontent-wise matrix multiply      \r
921         binOp = glslang::EOpMul;\r
922         break;\r
923     case glslang::EOpOuterProduct:\r
924         // two vectors multiplied to make a matrix\r
925         binOp = glslang::EOpOuterProduct;\r
926         break;\r
927     case glslang::EOpDot:\r
928     {\r
929         // for scalar dot product, use multiply        \r
930         glslang::TIntermSequence& glslangOperands = node->getSequence();\r
931         if (! glslangOperands[0]->getAsTyped()->isVector())\r
932             binOp = glslang::EOpMul;\r
933         break;\r
934     }\r
935     case glslang::EOpMod:\r
936         // when an aggregate, this is the floating-point mod built-in function,\r
937         // which can be emitted by the one in createBinaryOperation()\r
938         binOp = glslang::EOpMod;\r
939         break;\r
940     case glslang::EOpArrayLength:\r
941     {\r
942         glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();\r
943         assert(typedNode);\r
944         spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());\r
945 \r
946         builder.clearAccessChain();\r
947         builder.setAccessChainRValue(length);\r
948 \r
949         return false;\r
950     }\r
951     case glslang::EOpEmitVertex:\r
952     case glslang::EOpEndPrimitive:\r
953     case glslang::EOpBarrier:\r
954     case glslang::EOpMemoryBarrier:\r
955     case glslang::EOpMemoryBarrierAtomicCounter:\r
956     case glslang::EOpMemoryBarrierBuffer:\r
957     case glslang::EOpMemoryBarrierImage:\r
958     case glslang::EOpMemoryBarrierShared:\r
959     case glslang::EOpGroupMemoryBarrier:\r
960         noReturnValue = true;\r
961         // These all have 0 operands and will naturally finish up in the code below for 0 operands\r
962         break;\r
963 \r
964     default:\r
965         break;\r
966     }\r
967 \r
968     //\r
969     // See if it maps to a regular operation.\r
970     //\r
971 \r
972     if (binOp != glslang::EOpNull) {\r
973         glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();\r
974         glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();\r
975         assert(left && right);\r
976 \r
977         builder.clearAccessChain();\r
978         left->traverse(this);\r
979         spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));\r
980 \r
981         builder.clearAccessChain();\r
982         right->traverse(this);\r
983         spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));\r
984 \r
985         result = createBinaryOperation(binOp, precision, \r
986                                        convertGlslangToSpvType(node->getType()), leftId, rightId, \r
987                                        left->getType().getBasicType(), reduceComparison);\r
988 \r
989         // code above should only make binOp that exists in createBinaryOperation\r
990         if (result == 0)\r
991             spv::MissingFunctionality("createBinaryOperation for aggregate");\r
992 \r
993         builder.clearAccessChain();\r
994         builder.setAccessChainRValue(result);\r
995 \r
996         return false;\r
997     }\r
998 \r
999     glslang::TIntermSequence& glslangOperands = node->getSequence();\r
1000     std::vector<spv::Id> operands;\r
1001     for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {\r
1002         builder.clearAccessChain();\r
1003         glslangOperands[arg]->traverse(this);\r
1004 \r
1005         // special case l-value operands; there are just a few\r
1006         bool lvalue = false;\r
1007         switch (node->getOp()) {\r
1008         //case glslang::EOpFrexp:\r
1009         case glslang::EOpModf:\r
1010             if (arg == 1)\r
1011                 lvalue = true;\r
1012             break;\r
1013         //case glslang::EOpUAddCarry:\r
1014         //case glslang::EOpUSubBorrow:\r
1015         //case glslang::EOpUMulExtended:\r
1016         default:\r
1017             break;\r
1018         }\r
1019         if (lvalue)\r
1020             operands.push_back(builder.accessChainGetLValue());\r
1021         else\r
1022             operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));\r
1023     }\r
1024     switch (glslangOperands.size()) {\r
1025     case 0:\r
1026         result = createNoArgOperation(node->getOp());\r
1027         break;\r
1028     case 1:\r
1029         result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);\r
1030         break;\r
1031     default:\r
1032         result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);\r
1033         break;\r
1034     }\r
1035 \r
1036     if (noReturnValue)\r
1037         return false;\r
1038 \r
1039     if (! result) {\r
1040         spv::MissingFunctionality("glslang aggregate");\r
1041         return true;\r
1042     } else {\r
1043         builder.clearAccessChain();\r
1044         builder.setAccessChainRValue(result);\r
1045         return false;\r
1046     }\r
1047 }\r
1048 \r
1049 bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)\r
1050 {\r
1051     // This path handles both if-then-else and ?:\r
1052     // The if-then-else has a node type of void, while\r
1053     // ?: has a non-void node type\r
1054     spv::Id result = 0;\r
1055     if (node->getBasicType() != glslang::EbtVoid) {\r
1056         // don't handle this as just on-the-fly temporaries, because there will be two names\r
1057         // and better to leave SSA to later passes\r
1058         result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));\r
1059     }\r
1060 \r
1061     // emit the condition before doing anything with selection\r
1062     node->getCondition()->traverse(this);\r
1063 \r
1064     // make an "if" based on the value created by the condition\r
1065     spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);\r
1066 \r
1067     if (node->getTrueBlock()) {\r
1068         // emit the "then" statement\r
1069         node->getTrueBlock()->traverse(this);\r
1070         if (result)\r
1071             builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);\r
1072     }\r
1073 \r
1074     if (node->getFalseBlock()) {\r
1075         ifBuilder.makeBeginElse();\r
1076         // emit the "else" statement\r
1077         node->getFalseBlock()->traverse(this);\r
1078         if (result)\r
1079             builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);\r
1080     }\r
1081 \r
1082     ifBuilder.makeEndIf();\r
1083 \r
1084     if (result) {\r
1085         // GLSL only has r-values as the result of a :?, but\r
1086         // if we have an l-value, that can be more efficient if it will\r
1087         // become the base of a complex r-value expression, because the\r
1088         // next layer copies r-values into memory to use the access-chain mechanism\r
1089         builder.clearAccessChain();\r
1090         builder.setAccessChainLValue(result);\r
1091     }\r
1092 \r
1093     return false;\r
1094 }\r
1095 \r
1096 bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)\r
1097 {\r
1098     // emit and get the condition before doing anything with switch\r
1099     node->getCondition()->traverse(this);\r
1100     spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));\r
1101 \r
1102     // browse the children to sort out code segments\r
1103     int defaultSegment = -1;\r
1104     std::vector<TIntermNode*> codeSegments;\r
1105     glslang::TIntermSequence& sequence = node->getBody()->getSequence();\r
1106     std::vector<int> caseValues;\r
1107     std::vector<int> valueIndexToSegment(sequence.size());  // note: probably not all are used, it is an overestimate\r
1108     for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {\r
1109         TIntermNode* child = *c;\r
1110         if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)\r
1111             defaultSegment = codeSegments.size();\r
1112         else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {\r
1113             valueIndexToSegment[caseValues.size()] = codeSegments.size();\r
1114             caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());\r
1115         } else\r
1116             codeSegments.push_back(child);\r
1117     }\r
1118 \r
1119     // handle the case where the last code segment is missing, due to no code \r
1120     // statements between the last case and the end of the switch statement\r
1121     if ((int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1])\r
1122         codeSegments.push_back(0);\r
1123 \r
1124     // make the switch statement\r
1125     std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call\r
1126     builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);\r
1127 \r
1128     // emit all the code in the segments\r
1129     breakForLoop.push(false);\r
1130     for (unsigned int s = 0; s < codeSegments.size(); ++s) {\r
1131         builder.nextSwitchSegment(segmentBlocks, s);\r
1132         if (codeSegments[s])\r
1133             codeSegments[s]->traverse(this);\r
1134         else\r
1135             builder.addSwitchBreak();\r
1136     }\r
1137     breakForLoop.pop();\r
1138 \r
1139     builder.endSwitch(segmentBlocks);\r
1140 \r
1141     return false;\r
1142 }\r
1143 \r
1144 void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)\r
1145 {\r
1146     int nextConst = 0;\r
1147     spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);\r
1148 \r
1149     builder.clearAccessChain();\r
1150     builder.setAccessChainRValue(constant);\r
1151 }\r
1152 \r
1153 bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)\r
1154 {\r
1155     // body emission needs to know what the for-loop terminal is when it sees a "continue"\r
1156     loopTerminal.push(node->getTerminal());\r
1157 \r
1158     builder.makeNewLoop();\r
1159 \r
1160     bool bodyOut = false;\r
1161     if (! node->testFirst()) {\r
1162         if (node->getBody()) {\r
1163             breakForLoop.push(true);\r
1164             node->getBody()->traverse(this);\r
1165             breakForLoop.pop();\r
1166         }\r
1167         bodyOut = true;\r
1168     }\r
1169 \r
1170     if (node->getTest()) {\r
1171         node->getTest()->traverse(this);\r
1172         // the AST only contained the test computation, not the branch, we have to add it\r
1173         spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));\r
1174         builder.createLoopHeaderBranch(condition);\r
1175     }\r
1176 \r
1177     if (! bodyOut && node->getBody()) {\r
1178         breakForLoop.push(true);\r
1179         node->getBody()->traverse(this);\r
1180         breakForLoop.pop();\r
1181     }\r
1182 \r
1183     if (loopTerminal.top())\r
1184         loopTerminal.top()->traverse(this);\r
1185 \r
1186     builder.closeLoop();\r
1187 \r
1188     loopTerminal.pop();\r
1189 \r
1190     return false;\r
1191 }\r
1192 \r
1193 bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)\r
1194 {\r
1195     if (node->getExpression())\r
1196         node->getExpression()->traverse(this);\r
1197 \r
1198     switch (node->getFlowOp()) {\r
1199     case glslang::EOpKill:\r
1200         builder.makeDiscard();\r
1201         break;\r
1202     case glslang::EOpBreak:\r
1203         if (breakForLoop.top())\r
1204             builder.createLoopExit();\r
1205         else\r
1206             builder.addSwitchBreak();\r
1207         break;\r
1208     case glslang::EOpContinue:\r
1209         if (loopTerminal.top())\r
1210             loopTerminal.top()->traverse(this);\r
1211         builder.createLoopBackEdge();\r
1212         break;\r
1213     case glslang::EOpReturn:\r
1214         if (inMain)\r
1215             builder.makeMainReturn();\r
1216         else if (node->getExpression())\r
1217             builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));\r
1218         else\r
1219             builder.makeReturn();\r
1220 \r
1221         builder.clearAccessChain();\r
1222         break;\r
1223 \r
1224     default:\r
1225         spv::MissingFunctionality("branch type");\r
1226         break;\r
1227     }\r
1228 \r
1229     return false;\r
1230 }\r
1231 \r
1232 spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)\r
1233 {\r
1234     // First, steer off constants, which are not SPIR-V variables, but \r
1235     // can still have a mapping to a SPIR-V Id.\r
1236     if (node->getQualifier().storage == glslang::EvqConst) {\r
1237         int nextConst = 0;\r
1238         return createSpvConstant(node->getType(), node->getConstArray(), nextConst);\r
1239     }\r
1240 \r
1241     // Now, handle actual variables\r
1242     spv::StorageClass storageClass = TranslateStorageClass(node->getType());\r
1243     spv::Id spvType = convertGlslangToSpvType(node->getType());\r
1244 \r
1245     const char* name = node->getName().c_str();\r
1246     if (glslang::IsAnonymous(name))\r
1247         name = "";\r
1248 \r
1249     if (storageClass == spv::BadValue)\r
1250         return builder.createVariable(spv::StorageClassFunction, spvType, name);\r
1251     else\r
1252         return builder.createVariable(storageClass, spvType, name);\r
1253 }\r
1254 \r
1255 // Return type Id of the sampled type.\r
1256 spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)\r
1257 {\r
1258     switch (sampler.type) {\r
1259         case glslang::EbtFloat:    return builder.makeFloatType(32);\r
1260         case glslang::EbtInt:      return builder.makeIntType(32);\r
1261         case glslang::EbtUint:     return builder.makeUintType(32);\r
1262         default:\r
1263             spv::MissingFunctionality("sampled type");\r
1264             return builder.makeFloatType(32);\r
1265     }\r
1266 }\r
1267 \r
1268 // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.\r
1269 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)\r
1270 {\r
1271     spv::Id spvType = 0;\r
1272 \r
1273     switch (type.getBasicType()) {\r
1274     case glslang::EbtVoid:\r
1275         spvType = builder.makeVoidType();\r
1276         if (type.isArray())\r
1277             spv::MissingFunctionality("array of void");\r
1278         break;\r
1279     case glslang::EbtFloat:\r
1280         spvType = builder.makeFloatType(32);\r
1281         break;\r
1282     case glslang::EbtDouble:\r
1283         spvType = builder.makeFloatType(64);\r
1284         break;\r
1285     case glslang::EbtBool:\r
1286         spvType = builder.makeBoolType();\r
1287         break;\r
1288     case glslang::EbtInt:\r
1289         spvType = builder.makeIntType(32);\r
1290         break;\r
1291     case glslang::EbtUint:\r
1292         spvType = builder.makeUintType(32);\r
1293         break;\r
1294     case glslang::EbtSampler:\r
1295         {\r
1296             const glslang::TSampler& sampler = type.getSampler();\r
1297             spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler), \r
1298                                           sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,\r
1299                                           sampler.arrayed, sampler.shadow, sampler.ms);\r
1300         }\r
1301         break;\r
1302     case glslang::EbtStruct:\r
1303     case glslang::EbtBlock:\r
1304         {\r
1305             // If we've seen this struct type, return it\r
1306             const glslang::TTypeList* glslangStruct = type.getStruct();\r
1307             std::vector<spv::Id> structFields;\r
1308             spvType = structMap[glslangStruct];\r
1309             if (spvType)\r
1310                 break;\r
1311 \r
1312             // else, we haven't seen it...\r
1313 \r
1314             // Create a vector of struct types for SPIR-V to consume\r
1315             int memberDelta = 0;  // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks\r
1316             if (type.getBasicType() == glslang::EbtBlock)\r
1317                 memberRemapper[glslangStruct].resize(glslangStruct->size());\r
1318             for (int i = 0; i < (int)glslangStruct->size(); i++) {\r
1319                 glslang::TType& glslangType = *(*glslangStruct)[i].type;\r
1320                 if (glslangType.hiddenMember()) {\r
1321                     ++memberDelta;\r
1322                     if (type.getBasicType() == glslang::EbtBlock)\r
1323                         memberRemapper[glslangStruct][i] = -1;\r
1324                 } else {\r
1325                     if (type.getBasicType() == glslang::EbtBlock)\r
1326                         memberRemapper[glslangStruct][i] = i - memberDelta;\r
1327                     structFields.push_back(convertGlslangToSpvType(glslangType));\r
1328                 }\r
1329             }\r
1330 \r
1331             // Make the SPIR-V type\r
1332             spvType = builder.makeStructType(structFields, type.getTypeName().c_str());\r
1333             structMap[glslangStruct] = spvType;\r
1334 \r
1335             // Name and decorate the non-hidden members\r
1336             for (int i = 0; i < (int)glslangStruct->size(); i++) {\r
1337                 glslang::TType& glslangType = *(*glslangStruct)[i].type;\r
1338                 int member = i;\r
1339                 if (type.getBasicType() == glslang::EbtBlock)\r
1340                     member = memberRemapper[glslangStruct][i];\r
1341                 // using -1 above to indicate a hidden member\r
1342                 if (member >= 0) {\r
1343                     builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());\r
1344                     addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));\r
1345                     addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));\r
1346                     addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));\r
1347                     addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));\r
1348                     if (glslangType.getQualifier().hasLocation())\r
1349                         builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);\r
1350                     if (glslangType.getQualifier().hasComponent())\r
1351                         builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);\r
1352                     if (glslangType.getQualifier().hasXfbOffset())\r
1353                         builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);\r
1354                 }\r
1355             }\r
1356 \r
1357             // Decorate the structure\r
1358             addDecoration(spvType, TranslateLayoutDecoration(type));\r
1359             addDecoration(spvType, TranslateBlockDecoration(type));\r
1360             if (type.getQualifier().hasStream())\r
1361                 builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);\r
1362             if (glslangIntermediate->getXfbMode()) {\r
1363                 if (type.getQualifier().hasXfbStride())\r
1364                     builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);\r
1365                 if (type.getQualifier().hasXfbBuffer())\r
1366                     builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);\r
1367             }\r
1368         }\r
1369         break;\r
1370     default:\r
1371         spv::MissingFunctionality("basic type");\r
1372         break;\r
1373     }\r
1374 \r
1375     if (type.isMatrix())\r
1376         spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());\r
1377     else {\r
1378         // If this variable has a vector element count greater than 1, create a SPIR-V vector\r
1379         if (type.getVectorSize() > 1)\r
1380             spvType = builder.makeVectorType(spvType, type.getVectorSize());\r
1381     }\r
1382 \r
1383     if (type.isArray()) {\r
1384         unsigned arraySize;\r
1385         if (! type.isExplicitlySizedArray()) {\r
1386             spv::MissingFunctionality("Unsized array");\r
1387             arraySize = 8;\r
1388         } else\r
1389             arraySize = type.getArraySize();\r
1390         spvType = builder.makeArrayType(spvType, arraySize);\r
1391     }\r
1392 \r
1393     return spvType;\r
1394 }\r
1395 \r
1396 bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)\r
1397 {\r
1398     return node->getName() == "main(";\r
1399 }\r
1400 \r
1401 // Make all the functions, skeletally, without actually visiting their bodies.\r
1402 void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)\r
1403 {\r
1404     for (int f = 0; f < (int)glslFunctions.size(); ++f) {\r
1405         glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();\r
1406         if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))\r
1407             continue;\r
1408 \r
1409         // We're on a user function.  Set up the basic interface for the function now,\r
1410         // so that it's available to call.\r
1411         // Translating the body will happen later.\r
1412         //\r
1413         // Typically (except for a "const in" parameter), an address will be passed to the \r
1414         // function.  What it is an address of varies:\r
1415         //\r
1416         // - "in" parameters not marked as "const" can be written to without modifying the argument,\r
1417         //  so that write needs to be to a copy, hence the address of a copy works.\r
1418         //\r
1419         // - "const in" parameters can just be the r-value, as no writes need occur.\r
1420         //\r
1421         // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has\r
1422         // copy-in/copy-out semantics.  They can be handled though with a pointer to a copy.\r
1423 \r
1424         std::vector<spv::Id> paramTypes;\r
1425         glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();\r
1426 \r
1427         for (int p = 0; p < (int)parameters.size(); ++p) {\r
1428             const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();\r
1429             spv::Id typeId = convertGlslangToSpvType(paramType);\r
1430             if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)\r
1431                 typeId = builder.makePointer(spv::StorageClassFunction, typeId);\r
1432             else\r
1433                 constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());\r
1434             paramTypes.push_back(typeId);\r
1435         }\r
1436 \r
1437         spv::Block* functionBlock;\r
1438         spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),\r
1439                                                               paramTypes, &functionBlock);\r
1440 \r
1441         // Track function to emit/call later\r
1442         functionMap[glslFunction->getName().c_str()] = function;\r
1443 \r
1444         // Set the parameter id's\r
1445         for (int p = 0; p < (int)parameters.size(); ++p) {\r
1446             symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);\r
1447             // give a name too\r
1448             builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());\r
1449         }\r
1450     }\r
1451 }\r
1452 \r
1453 // Process all the initializers, while skipping the functions and link objects\r
1454 void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)\r
1455 {\r
1456     builder.setBuildPoint(shaderEntry->getLastBlock());\r
1457     for (int i = 0; i < (int)initializers.size(); ++i) {\r
1458         glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();\r
1459         if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {\r
1460 \r
1461             // We're on a top-level node that's not a function.  Treat as an initializer, whose\r
1462             // code goes into the beginning of main.\r
1463             initializer->traverse(this);\r
1464         }\r
1465     }\r
1466 }\r
1467 \r
1468 // Process all the functions, while skipping initializers.\r
1469 void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)\r
1470 {\r
1471     for (int f = 0; f < (int)glslFunctions.size(); ++f) {\r
1472         glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();\r
1473         if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))\r
1474             node->traverse(this);\r
1475     }\r
1476 }\r
1477 \r
1478 void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)\r
1479 {\r
1480     // SPIR-V functions should already be in the functionMap from the prepass \r
1481     // that called makeFunctions().\r
1482     spv::Function* function = functionMap[node->getName().c_str()];\r
1483     spv::Block* functionBlock = function->getEntryBlock();\r
1484     builder.setBuildPoint(functionBlock);\r
1485 }\r
1486 \r
1487 void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)\r
1488 {\r
1489     for (int i = 0; i < (int)glslangArguments.size(); ++i) {\r
1490         builder.clearAccessChain();\r
1491         glslangArguments[i]->traverse(this);\r
1492         arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));\r
1493     }\r
1494 }\r
1495 \r
1496 spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)\r
1497 {\r
1498     std::vector<spv::Id> arguments;\r
1499     translateArguments(node->getSequence(), arguments);\r
1500 \r
1501     std::vector<spv::Id> argTypes;\r
1502     for (int a = 0; a < (int)arguments.size(); ++a)\r
1503         argTypes.push_back(builder.getTypeId(arguments[a]));\r
1504 \r
1505     spv::Decoration precision = TranslatePrecisionDecoration(node->getType());\r
1506 \r
1507     if (node->getName() == "ftransform(") {\r
1508         spv::MissingFunctionality("ftransform()");\r
1509         //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),\r
1510         //                                                             "gl_Vertex_sim");\r
1511         //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),\r
1512         //                                                             "gl_ModelViewProjectionMatrix_sim");\r
1513         return 0;\r
1514     }\r
1515 \r
1516     if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {\r
1517         const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();\r
1518         spv::Builder::TextureParameters params = { };\r
1519         params.sampler = arguments[0];\r
1520 \r
1521         // special case size query\r
1522         if (node->getName().find("textureSize", 0) != std::string::npos) {\r
1523             if (arguments.size() > 1) {\r
1524                 params.lod = arguments[1];\r
1525                 return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);\r
1526             } else\r
1527                 return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);\r
1528         }\r
1529 \r
1530         // special case the number of samples query\r
1531         if (node->getName().find("textureSamples", 0) != std::string::npos)\r
1532             return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);\r
1533 \r
1534         // special case the other queries\r
1535         if (node->getName().find("Query", 0) != std::string::npos) {\r
1536             if (node->getName().find("Levels", 0) != std::string::npos)\r
1537                 return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);\r
1538             else if (node->getName().find("Lod", 0) != std::string::npos) {\r
1539                 params.coords = arguments[1];\r
1540                 return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);\r
1541             } else\r
1542                 spv::MissingFunctionality("glslang texture query");\r
1543         }\r
1544 \r
1545         // This is no longer a query....\r
1546 \r
1547         bool lod = node->getName().find("Lod", 0) != std::string::npos;\r
1548         bool proj = node->getName().find("Proj", 0) != std::string::npos;\r
1549         bool offsets = node->getName().find("Offsets", 0) != std::string::npos;\r
1550         bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;\r
1551         bool fetch = node->getName().find("Fetch", 0) != std::string::npos;\r
1552         bool gather = node->getName().find("Gather", 0) != std::string::npos;\r
1553         bool grad = node->getName().find("Grad", 0) != std::string::npos;\r
1554 \r
1555         if (fetch)\r
1556             spv::MissingFunctionality("texel fetch");\r
1557         if (gather)\r
1558             spv::MissingFunctionality("texture gather");\r
1559 \r
1560         // check for bias argument\r
1561         bool bias = false;\r
1562         if (! lod && ! gather && ! grad && ! fetch) {\r
1563             int nonBiasArgCount = 2;\r
1564             if (offset)\r
1565                 ++nonBiasArgCount;\r
1566             if (grad)\r
1567                 nonBiasArgCount += 2;\r
1568 \r
1569             if ((int)arguments.size() > nonBiasArgCount)\r
1570                 bias = true;\r
1571         }\r
1572 \r
1573         bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;\r
1574 \r
1575         // set the rest of the arguments\r
1576         params.coords = arguments[1];\r
1577         int extraArgs = 0;\r
1578         if (cubeCompare)\r
1579             params.Dref = arguments[2];\r
1580         if (lod) {\r
1581             params.lod = arguments[2];\r
1582             ++extraArgs;\r
1583         }\r
1584         if (grad) {\r
1585             params.gradX = arguments[2 + extraArgs];\r
1586             params.gradY = arguments[3 + extraArgs];\r
1587             extraArgs += 2;\r
1588         }\r
1589         //if (gather && compare) {\r
1590         //    params.compare = arguments[2 + extraArgs];\r
1591         //    ++extraArgs;\r
1592         //}\r
1593         if (offset | offsets) {\r
1594             params.offset = arguments[2 + extraArgs];\r
1595             ++extraArgs;\r
1596         }\r
1597         if (bias) {\r
1598             params.bias = arguments[2 + extraArgs];\r
1599             ++extraArgs;\r
1600         }\r
1601 \r
1602         return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);\r
1603     }\r
1604 \r
1605     spv::MissingFunctionality("built-in function call");\r
1606 \r
1607     return 0;\r
1608 }\r
1609 \r
1610 spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)\r
1611 {\r
1612     // Grab the function's pointer from the previously created function\r
1613     spv::Function* function = functionMap[node->getName().c_str()];\r
1614     if (! function)\r
1615         return 0;\r
1616 \r
1617     const glslang::TIntermSequence& glslangArgs = node->getSequence();\r
1618     const glslang::TQualifierList& qualifiers = node->getQualifierList();\r
1619 \r
1620     //  See comments in makeFunctions() for details about the semantics for parameter passing.\r
1621     //\r
1622     // These imply we need a four step process:\r
1623     // 1. Evaluate the arguments\r
1624     // 2. Allocate and make copies of in, out, and inout arguments\r
1625     // 3. Make the call\r
1626     // 4. Copy back the results\r
1627 \r
1628     // 1. Evaluate the arguments\r
1629     std::vector<spv::Builder::AccessChain> lValues;\r
1630     std::vector<spv::Id> rValues;\r
1631     for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
1632         // build l-value\r
1633         builder.clearAccessChain();\r
1634         glslangArgs[a]->traverse(this);\r
1635         // keep outputs as l-values, evaluate input-only as r-values\r
1636         if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
1637             // save l-value\r
1638             lValues.push_back(builder.getAccessChain());\r
1639         } else {\r
1640             // process r-value\r
1641             rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));\r
1642         }\r
1643     }\r
1644 \r
1645     // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"\r
1646     // copy the original into that space.\r
1647     //\r
1648     // Also, build up the list of actual arguments to pass in for the call\r
1649     int lValueCount = 0;\r
1650     int rValueCount = 0;\r
1651     std::vector<spv::Id> spvArgs;\r
1652     for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
1653         spv::Id arg;\r
1654         if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
1655             // need space to hold the copy\r
1656             const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();\r
1657             arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");\r
1658             if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {\r
1659                 // need to copy the input into output space\r
1660                 builder.setAccessChain(lValues[lValueCount]);\r
1661                 spv::Id copy = builder.accessChainLoad(spv::NoPrecision);  // TODO: get precision\r
1662                 builder.createStore(copy, arg);\r
1663             }\r
1664             ++lValueCount;\r
1665         } else {\r
1666             arg = rValues[rValueCount];\r
1667             ++rValueCount;\r
1668         }\r
1669         spvArgs.push_back(arg);\r
1670     }\r
1671 \r
1672     // 3. Make the call.\r
1673     spv::Id result = builder.createFunctionCall(function, spvArgs);\r
1674 \r
1675     // 4. Copy back out an "out" arguments.\r
1676     lValueCount = 0;\r
1677     for (int a = 0; a < (int)glslangArgs.size(); ++a) {\r
1678         if (qualifiers[a] != glslang::EvqConstReadOnly) {\r
1679             if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {\r
1680                 spv::Id copy = builder.createLoad(spvArgs[a]);\r
1681                 builder.setAccessChain(lValues[lValueCount]);\r
1682                 builder.accessChainStore(copy);\r
1683             }\r
1684             ++lValueCount;\r
1685         }\r
1686     }\r
1687 \r
1688     return result;\r
1689 }\r
1690 \r
1691 spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision, \r
1692                                                         spv::Id typeId, spv::Id left, spv::Id right,\r
1693                                                         glslang::TBasicType typeProxy, bool reduceComparison)\r
1694 {\r
1695     bool isUnsigned = typeProxy == glslang::EbtUint;\r
1696     bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;\r
1697 \r
1698     spv::Op binOp = spv::OpNop;\r
1699     bool needsPromotion = true;\r
1700     bool comparison = false;\r
1701 \r
1702     switch (op) {\r
1703     case glslang::EOpAdd:\r
1704     case glslang::EOpAddAssign:\r
1705         if (isFloat)\r
1706             binOp = spv::OpFAdd;\r
1707         else\r
1708             binOp = spv::OpIAdd;\r
1709         break;\r
1710     case glslang::EOpSub:\r
1711     case glslang::EOpSubAssign:\r
1712         if (isFloat)\r
1713             binOp = spv::OpFSub;\r
1714         else\r
1715             binOp = spv::OpISub;\r
1716         break;\r
1717     case glslang::EOpMul:\r
1718     case glslang::EOpMulAssign:\r
1719         if (isFloat)\r
1720             binOp = spv::OpFMul;\r
1721         else\r
1722             binOp = spv::OpIMul;\r
1723         break;\r
1724     case glslang::EOpVectorTimesScalar:\r
1725     case glslang::EOpVectorTimesScalarAssign:\r
1726         binOp = spv::OpVectorTimesScalar;\r
1727         needsPromotion = false;\r
1728         break;\r
1729     case glslang::EOpVectorTimesMatrix:\r
1730     case glslang::EOpVectorTimesMatrixAssign:\r
1731         binOp = spv::OpVectorTimesMatrix;\r
1732         break;\r
1733     case glslang::EOpMatrixTimesVector:\r
1734         binOp = spv::OpMatrixTimesVector;\r
1735         break;\r
1736     case glslang::EOpMatrixTimesScalar:\r
1737     case glslang::EOpMatrixTimesScalarAssign:\r
1738         binOp = spv::OpMatrixTimesScalar;\r
1739         break;\r
1740     case glslang::EOpMatrixTimesMatrix:\r
1741     case glslang::EOpMatrixTimesMatrixAssign:\r
1742         binOp = spv::OpMatrixTimesMatrix;\r
1743         break;\r
1744     case glslang::EOpOuterProduct:\r
1745         binOp = spv::OpOuterProduct;\r
1746         needsPromotion = false;\r
1747         break;\r
1748 \r
1749     case glslang::EOpDiv:\r
1750     case glslang::EOpDivAssign:\r
1751         if (isFloat)\r
1752             binOp = spv::OpFDiv;\r
1753         else if (isUnsigned)\r
1754             binOp = spv::OpUDiv;\r
1755         else\r
1756             binOp = spv::OpSDiv;\r
1757         break;\r
1758     case glslang::EOpMod:\r
1759     case glslang::EOpModAssign:\r
1760         if (isFloat)\r
1761             binOp = spv::OpFMod;\r
1762         else if (isUnsigned)\r
1763             binOp = spv::OpUMod;\r
1764         else\r
1765             binOp = spv::OpSMod;\r
1766         break;\r
1767     case glslang::EOpRightShift:\r
1768     case glslang::EOpRightShiftAssign:\r
1769         if (isUnsigned)\r
1770             binOp = spv::OpShiftRightLogical;\r
1771         else\r
1772             binOp = spv::OpShiftRightArithmetic;\r
1773         break;\r
1774     case glslang::EOpLeftShift:\r
1775     case glslang::EOpLeftShiftAssign:\r
1776         binOp = spv::OpShiftLeftLogical;\r
1777         break;\r
1778     case glslang::EOpAnd:\r
1779     case glslang::EOpAndAssign:\r
1780         binOp = spv::OpBitwiseAnd;\r
1781         break;\r
1782     case glslang::EOpLogicalAnd:\r
1783         needsPromotion = false;\r
1784         binOp = spv::OpLogicalAnd;\r
1785         break;\r
1786     case glslang::EOpInclusiveOr:\r
1787     case glslang::EOpInclusiveOrAssign:\r
1788         binOp = spv::OpBitwiseOr;\r
1789         break;\r
1790     case glslang::EOpLogicalOr:\r
1791         needsPromotion = false;\r
1792         binOp = spv::OpLogicalOr;\r
1793         break;\r
1794     case glslang::EOpExclusiveOr:\r
1795     case glslang::EOpExclusiveOrAssign:\r
1796         binOp = spv::OpBitwiseXor;\r
1797         break;\r
1798     case glslang::EOpLogicalXor:\r
1799         needsPromotion = false;\r
1800         binOp = spv::OpLogicalXor;\r
1801         break;\r
1802 \r
1803     case glslang::EOpLessThan:\r
1804     case glslang::EOpGreaterThan:\r
1805     case glslang::EOpLessThanEqual:\r
1806     case glslang::EOpGreaterThanEqual:\r
1807     case glslang::EOpEqual:\r
1808     case glslang::EOpNotEqual:\r
1809     case glslang::EOpVectorEqual:\r
1810     case glslang::EOpVectorNotEqual:\r
1811         comparison = true;\r
1812         break;\r
1813     default:\r
1814         break;\r
1815     }\r
1816 \r
1817     if (binOp != spv::OpNop) {\r
1818         if (builder.isMatrix(left) || builder.isMatrix(right)) {\r
1819             switch (binOp) {\r
1820             case spv::OpMatrixTimesScalar:\r
1821             case spv::OpVectorTimesMatrix:\r
1822             case spv::OpMatrixTimesVector:\r
1823             case spv::OpMatrixTimesMatrix:\r
1824                 break;\r
1825             case spv::OpFDiv:\r
1826                 // turn it into a multiply...\r
1827                 assert(builder.isMatrix(left) && builder.isScalar(right));\r
1828                 right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);\r
1829                 binOp = spv::OpFMul;\r
1830                 break;\r
1831             default:\r
1832                 spv::MissingFunctionality("binary operation on matrix");\r
1833                 break;\r
1834             }\r
1835 \r
1836             spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
1837             builder.setPrecision(id, precision);\r
1838 \r
1839             return id;\r
1840         }\r
1841 \r
1842         // No matrix involved; make both operands be the same number of components, if needed\r
1843         if (needsPromotion)\r
1844             builder.promoteScalar(precision, left, right);\r
1845 \r
1846         spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
1847         builder.setPrecision(id, precision);\r
1848 \r
1849         return id;\r
1850     }\r
1851 \r
1852     if (! comparison)\r
1853         return 0;\r
1854 \r
1855     // Comparison instructions\r
1856 \r
1857     if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {\r
1858         assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);\r
1859 \r
1860         return builder.createCompare(precision, left, right, op == glslang::EOpEqual);\r
1861     }\r
1862 \r
1863     switch (op) {\r
1864     case glslang::EOpLessThan:\r
1865         if (isFloat)\r
1866             binOp = spv::OpFOrdLessThan;\r
1867         else if (isUnsigned)\r
1868             binOp = spv::OpULessThan;\r
1869         else\r
1870             binOp = spv::OpSLessThan;\r
1871         break;\r
1872     case glslang::EOpGreaterThan:\r
1873         if (isFloat)\r
1874             binOp = spv::OpFOrdGreaterThan;\r
1875         else if (isUnsigned)\r
1876             binOp = spv::OpUGreaterThan;\r
1877         else\r
1878             binOp = spv::OpSGreaterThan;\r
1879         break;\r
1880     case glslang::EOpLessThanEqual:\r
1881         if (isFloat)\r
1882             binOp = spv::OpFOrdLessThanEqual;\r
1883         else if (isUnsigned)\r
1884             binOp = spv::OpULessThanEqual;\r
1885         else\r
1886             binOp = spv::OpSLessThanEqual;\r
1887         break;\r
1888     case glslang::EOpGreaterThanEqual:\r
1889         if (isFloat)\r
1890             binOp = spv::OpFOrdGreaterThanEqual;\r
1891         else if (isUnsigned)\r
1892             binOp = spv::OpUGreaterThanEqual;\r
1893         else\r
1894             binOp = spv::OpSGreaterThanEqual;\r
1895         break;\r
1896     case glslang::EOpEqual:\r
1897     case glslang::EOpVectorEqual:\r
1898         if (isFloat)\r
1899             binOp = spv::OpFOrdEqual;\r
1900         else\r
1901             binOp = spv::OpIEqual;\r
1902         break;\r
1903     case glslang::EOpNotEqual:\r
1904     case glslang::EOpVectorNotEqual:\r
1905         if (isFloat)\r
1906             binOp = spv::OpFOrdNotEqual;\r
1907         else\r
1908             binOp = spv::OpINotEqual;\r
1909         break;\r
1910     default:\r
1911         break;\r
1912     }\r
1913 \r
1914     if (binOp != spv::OpNop) {\r
1915         spv::Id id = builder.createBinOp(binOp, typeId, left, right);\r
1916         builder.setPrecision(id, precision);\r
1917 \r
1918         return id;\r
1919     }\r
1920 \r
1921     return 0;\r
1922 }\r
1923 \r
1924 spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)\r
1925 {\r
1926     spv::Op unaryOp = spv::OpNop;\r
1927     int libCall = -1;\r
1928 \r
1929     switch (op) {\r
1930     case glslang::EOpNegative:\r
1931         if (isFloat)\r
1932             unaryOp = spv::OpFNegate;\r
1933         else\r
1934             unaryOp = spv::OpSNegate;\r
1935         break;\r
1936 \r
1937     case glslang::EOpLogicalNot:\r
1938     case glslang::EOpVectorLogicalNot:\r
1939     case glslang::EOpBitwiseNot:\r
1940         unaryOp = spv::OpNot;\r
1941         break;\r
1942     \r
1943     case glslang::EOpDeterminant:\r
1944         libCall = GLSL_STD_450::Determinant;\r
1945         break;\r
1946     case glslang::EOpMatrixInverse:\r
1947         libCall = GLSL_STD_450::MatrixInverse;\r
1948         break;\r
1949     case glslang::EOpTranspose:\r
1950         unaryOp = spv::OpTranspose;\r
1951         break;\r
1952 \r
1953     case glslang::EOpRadians:\r
1954         libCall = GLSL_STD_450::Radians;\r
1955         break;\r
1956     case glslang::EOpDegrees:\r
1957         libCall = GLSL_STD_450::Degrees;\r
1958         break;\r
1959     case glslang::EOpSin:\r
1960         libCall = GLSL_STD_450::Sin;\r
1961         break;\r
1962     case glslang::EOpCos:\r
1963         libCall = GLSL_STD_450::Cos;\r
1964         break;\r
1965     case glslang::EOpTan:\r
1966         libCall = GLSL_STD_450::Tan;\r
1967         break;\r
1968     case glslang::EOpAcos:\r
1969         libCall = GLSL_STD_450::Acos;\r
1970         break;\r
1971     case glslang::EOpAsin:\r
1972         libCall = GLSL_STD_450::Asin;\r
1973         break;\r
1974     case glslang::EOpAtan:\r
1975         libCall = GLSL_STD_450::Atan;\r
1976         break;\r
1977 \r
1978     case glslang::EOpAcosh:\r
1979         libCall = GLSL_STD_450::Acosh;\r
1980         break;\r
1981     case glslang::EOpAsinh:\r
1982         libCall = GLSL_STD_450::Asinh;\r
1983         break;\r
1984     case glslang::EOpAtanh:\r
1985         libCall = GLSL_STD_450::Atanh;\r
1986         break;\r
1987     case glslang::EOpTanh:\r
1988         libCall = GLSL_STD_450::Tanh;\r
1989         break;\r
1990     case glslang::EOpCosh:\r
1991         libCall = GLSL_STD_450::Cosh;\r
1992         break;\r
1993     case glslang::EOpSinh:\r
1994         libCall = GLSL_STD_450::Sinh;\r
1995         break;\r
1996 \r
1997     case glslang::EOpLength:\r
1998         libCall = GLSL_STD_450::Length;\r
1999         break;\r
2000     case glslang::EOpNormalize:\r
2001         libCall = GLSL_STD_450::Normalize;\r
2002         break;\r
2003 \r
2004     case glslang::EOpExp:\r
2005         libCall = GLSL_STD_450::Exp;\r
2006         break;\r
2007     case glslang::EOpLog:\r
2008         libCall = GLSL_STD_450::Log;\r
2009         break;\r
2010     case glslang::EOpExp2:\r
2011         libCall = GLSL_STD_450::Exp2;\r
2012         break;\r
2013     case glslang::EOpLog2:\r
2014         libCall = GLSL_STD_450::Log2;\r
2015         break;\r
2016     case glslang::EOpSqrt:\r
2017         libCall = GLSL_STD_450::Sqrt;\r
2018         break;\r
2019     case glslang::EOpInverseSqrt:\r
2020         libCall = GLSL_STD_450::InverseSqrt;\r
2021         break;\r
2022 \r
2023     case glslang::EOpFloor:\r
2024         libCall = GLSL_STD_450::Floor;\r
2025         break;\r
2026     case glslang::EOpTrunc:\r
2027         libCall = GLSL_STD_450::Trunc;\r
2028         break;\r
2029     case glslang::EOpRound:\r
2030         libCall = GLSL_STD_450::Round;\r
2031         break;\r
2032     case glslang::EOpRoundEven:\r
2033         libCall = GLSL_STD_450::RoundEven;\r
2034         break;\r
2035     case glslang::EOpCeil:\r
2036         libCall = GLSL_STD_450::Ceil;\r
2037         break;\r
2038     case glslang::EOpFract:\r
2039         libCall = GLSL_STD_450::Fract;\r
2040         break;\r
2041 \r
2042     case glslang::EOpIsNan:\r
2043         unaryOp = spv::OpIsNan;\r
2044         break;\r
2045     case glslang::EOpIsInf:\r
2046         unaryOp = spv::OpIsInf;\r
2047         break;\r
2048 \r
2049     case glslang::EOpFloatBitsToInt:\r
2050         libCall = GLSL_STD_450::FloatBitsToInt;\r
2051         break;\r
2052     case glslang::EOpFloatBitsToUint:\r
2053         libCall = GLSL_STD_450::FloatBitsToUint;\r
2054         break;\r
2055     case glslang::EOpIntBitsToFloat:\r
2056         libCall = GLSL_STD_450::IntBitsToFloat;\r
2057         break;\r
2058     case glslang::EOpUintBitsToFloat:\r
2059         libCall = GLSL_STD_450::UintBitsToFloat;\r
2060         break;\r
2061     case glslang::EOpPackSnorm2x16:\r
2062         libCall = GLSL_STD_450::PackSnorm2x16;\r
2063         break;\r
2064     case glslang::EOpUnpackSnorm2x16:\r
2065         libCall = GLSL_STD_450::UnpackSnorm2x16;\r
2066         break;\r
2067     case glslang::EOpPackUnorm2x16:\r
2068         libCall = GLSL_STD_450::PackUnorm2x16;\r
2069         break;\r
2070     case glslang::EOpUnpackUnorm2x16:\r
2071         libCall = GLSL_STD_450::UnpackUnorm2x16;\r
2072         break;\r
2073     case glslang::EOpPackHalf2x16:\r
2074         libCall = GLSL_STD_450::PackHalf2x16;\r
2075         break;\r
2076     case glslang::EOpUnpackHalf2x16:\r
2077         libCall = GLSL_STD_450::UnpackHalf2x16;\r
2078         break;\r
2079 \r
2080     case glslang::EOpDPdx:\r
2081         unaryOp = spv::OpDPdx;\r
2082         break;\r
2083     case glslang::EOpDPdy:\r
2084         unaryOp = spv::OpDPdy;\r
2085         break;\r
2086     case glslang::EOpFwidth:\r
2087         unaryOp = spv::OpFwidth;\r
2088         break;\r
2089     case glslang::EOpDPdxFine:\r
2090         unaryOp = spv::OpDPdxFine;\r
2091         break;\r
2092     case glslang::EOpDPdyFine:\r
2093         unaryOp = spv::OpDPdyFine;\r
2094         break;\r
2095     case glslang::EOpFwidthFine:\r
2096         unaryOp = spv::OpFwidthFine;\r
2097         break;\r
2098     case glslang::EOpDPdxCoarse:\r
2099         unaryOp = spv::OpDPdxCoarse;\r
2100         break;\r
2101     case glslang::EOpDPdyCoarse:\r
2102         unaryOp = spv::OpDPdyCoarse;\r
2103         break;\r
2104     case glslang::EOpFwidthCoarse:\r
2105         unaryOp = spv::OpFwidthCoarse;\r
2106         break;\r
2107 \r
2108     case glslang::EOpAny:\r
2109         unaryOp = spv::OpAny;\r
2110         break;\r
2111     case glslang::EOpAll:\r
2112         unaryOp = spv::OpAll;\r
2113         break;\r
2114 \r
2115     case glslang::EOpAbs:\r
2116         libCall = GLSL_STD_450::Abs;\r
2117         break;\r
2118     case glslang::EOpSign:\r
2119         libCall = GLSL_STD_450::Sign;\r
2120         break;\r
2121 \r
2122     default:\r
2123         return 0;\r
2124     }\r
2125 \r
2126     spv::Id id;\r
2127     if (libCall >= 0) {\r
2128         std::vector<spv::Id> args;\r
2129         args.push_back(operand);\r
2130         id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);\r
2131     } else\r
2132         id = builder.createUnaryOp(unaryOp, typeId, operand);\r
2133 \r
2134     builder.setPrecision(id, precision);\r
2135 \r
2136     return id;\r
2137 }\r
2138 \r
2139 spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)\r
2140 {\r
2141     spv::Op convOp = spv::OpNop;\r
2142     spv::Id zero = 0;\r
2143     spv::Id one = 0;\r
2144 \r
2145     int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;\r
2146 \r
2147     switch (op) {\r
2148     case glslang::EOpConvIntToBool:\r
2149     case glslang::EOpConvUintToBool:\r
2150         zero = builder.makeUintConstant(0);\r
2151         zero = makeSmearedConstant(zero, vectorSize);\r
2152         return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);\r
2153 \r
2154     case glslang::EOpConvFloatToBool:\r
2155         zero = builder.makeFloatConstant(0.0F);\r
2156         zero = makeSmearedConstant(zero, vectorSize);\r
2157         return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);\r
2158 \r
2159     case glslang::EOpConvDoubleToBool:\r
2160         zero = builder.makeDoubleConstant(0.0);\r
2161         zero = makeSmearedConstant(zero, vectorSize);\r
2162         return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);\r
2163 \r
2164     case glslang::EOpConvBoolToFloat:\r
2165         convOp = spv::OpSelect;\r
2166         zero = builder.makeFloatConstant(0.0);\r
2167         one  = builder.makeFloatConstant(1.0);\r
2168         break;\r
2169     case glslang::EOpConvBoolToDouble:\r
2170         convOp = spv::OpSelect;\r
2171         zero = builder.makeDoubleConstant(0.0);\r
2172         one  = builder.makeDoubleConstant(1.0);\r
2173         break;\r
2174     case glslang::EOpConvBoolToInt:\r
2175         zero = builder.makeIntConstant(0);\r
2176         one  = builder.makeIntConstant(1);\r
2177         convOp = spv::OpSelect;\r
2178         break;\r
2179     case glslang::EOpConvBoolToUint:\r
2180         zero = builder.makeUintConstant(0);\r
2181         one  = builder.makeUintConstant(1);\r
2182         convOp = spv::OpSelect;\r
2183         break;\r
2184 \r
2185     case glslang::EOpConvIntToFloat:\r
2186     case glslang::EOpConvIntToDouble:\r
2187         convOp = spv::OpConvertSToF;\r
2188         break;\r
2189 \r
2190     case glslang::EOpConvUintToFloat:\r
2191     case glslang::EOpConvUintToDouble:\r
2192         convOp = spv::OpConvertUToF;\r
2193         break;\r
2194         \r
2195     case glslang::EOpConvDoubleToFloat:\r
2196     case glslang::EOpConvFloatToDouble:\r
2197         convOp = spv::OpFConvert;\r
2198         break;\r
2199 \r
2200     case glslang::EOpConvFloatToInt:\r
2201     case glslang::EOpConvDoubleToInt:\r
2202         convOp = spv::OpConvertFToS;\r
2203         break;\r
2204 \r
2205     case glslang::EOpConvUintToInt:\r
2206     case glslang::EOpConvIntToUint:\r
2207         convOp = spv::OpBitcast;\r
2208         break;\r
2209 \r
2210     case glslang::EOpConvFloatToUint:\r
2211     case glslang::EOpConvDoubleToUint:\r
2212         convOp = spv::OpConvertFToU;\r
2213         break;\r
2214     default:\r
2215         break;\r
2216     }\r
2217 \r
2218     spv::Id result = 0;\r
2219     if (convOp == spv::OpNop)\r
2220         return result;\r
2221 \r
2222     if (convOp == spv::OpSelect) {\r
2223         zero = makeSmearedConstant(zero, vectorSize);\r
2224         one  = makeSmearedConstant(one, vectorSize);\r
2225         result = builder.createTriOp(convOp, destType, operand, one, zero); \r
2226     } else\r
2227         result = builder.createUnaryOp(convOp, destType, operand);\r
2228 \r
2229     builder.setPrecision(result, precision);\r
2230 \r
2231     return result;\r
2232 }\r
2233 \r
2234 spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)\r
2235 {\r
2236     if (vectorSize == 0)\r
2237         return constant;\r
2238 \r
2239     spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);\r
2240     std::vector<spv::Id> components;\r
2241     for (int c = 0; c < vectorSize; ++c)\r
2242         components.push_back(constant);\r
2243     return builder.makeCompositeConstant(vectorTypeId, components);\r
2244 }\r
2245 \r
2246 spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)\r
2247 {\r
2248     spv::Op opCode = spv::OpNop;\r
2249     int libCall = -1;\r
2250 \r
2251     switch (op) {\r
2252     case glslang::EOpMin:\r
2253         libCall = GLSL_STD_450::Min;\r
2254         break;\r
2255     case glslang::EOpModf:\r
2256         libCall = GLSL_STD_450::Modf;\r
2257         break;\r
2258     case glslang::EOpMax:\r
2259         libCall = GLSL_STD_450::Max;\r
2260         break;\r
2261     case glslang::EOpPow:\r
2262         libCall = GLSL_STD_450::Pow;\r
2263         break;\r
2264     case glslang::EOpDot:\r
2265         opCode = spv::OpDot;\r
2266         break;\r
2267     case glslang::EOpAtan:\r
2268         libCall = GLSL_STD_450::Atan2;\r
2269         break;\r
2270 \r
2271     case glslang::EOpClamp:\r
2272         libCall = GLSL_STD_450::Clamp;\r
2273         break;\r
2274     case glslang::EOpMix:\r
2275         libCall = GLSL_STD_450::Mix;\r
2276         break;\r
2277     case glslang::EOpStep:\r
2278         libCall = GLSL_STD_450::Step;\r
2279         break;\r
2280     case glslang::EOpSmoothStep:\r
2281         libCall = GLSL_STD_450::SmoothStep;\r
2282         break;\r
2283 \r
2284     case glslang::EOpDistance:\r
2285         libCall = GLSL_STD_450::Distance;\r
2286         break;\r
2287     case glslang::EOpCross:\r
2288         libCall = GLSL_STD_450::Cross;\r
2289         break;\r
2290     case glslang::EOpFaceForward:\r
2291         libCall = GLSL_STD_450::FaceForward;\r
2292         break;\r
2293     case glslang::EOpReflect:\r
2294         libCall = GLSL_STD_450::Reflect;\r
2295         break;\r
2296     case glslang::EOpRefract:\r
2297         libCall = GLSL_STD_450::Refract;\r
2298         break;\r
2299     default:\r
2300         return 0;\r
2301     }\r
2302 \r
2303     spv::Id id = 0;\r
2304     if (libCall >= 0)\r
2305         id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);\r
2306     else {\r
2307         switch (operands.size()) {\r
2308         case 0:\r
2309             // should all be handled by visitAggregate and createNoArgOperation\r
2310             assert(0);\r
2311             return 0;\r
2312         case 1:\r
2313             // should all be handled by createUnaryOperation\r
2314             assert(0);\r
2315             return 0;\r
2316         case 2:\r
2317             id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);\r
2318             break;\r
2319         case 3:\r
2320             id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);\r
2321             break;\r
2322         default:\r
2323             // These do not exist yet\r
2324             assert(0 && "operation with more than 3 operands");\r
2325             break;\r
2326         }\r
2327     }\r
2328 \r
2329     builder.setPrecision(id, precision);\r
2330 \r
2331     return id;\r
2332 }\r
2333 \r
2334 // Intrinsics with no arguments, no return value, and no precision.\r
2335 spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)\r
2336 {\r
2337     // TODO: get the barrier operands correct\r
2338 \r
2339     switch (op) {\r
2340     case glslang::EOpEmitVertex:\r
2341         builder.createNoResultOp(spv::OpEmitVertex);\r
2342         return 0;\r
2343     case glslang::EOpEndPrimitive:\r
2344         builder.createNoResultOp(spv::OpEndPrimitive);\r
2345         return 0;\r
2346     case glslang::EOpBarrier:\r
2347         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);\r
2348         builder.createControlBarrier(spv::ExecutionScopeDevice);\r
2349         return 0;\r
2350     case glslang::EOpMemoryBarrier:\r
2351         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);\r
2352         return 0;\r
2353     case glslang::EOpMemoryBarrierAtomicCounter:\r
2354         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);\r
2355         return 0;\r
2356     case glslang::EOpMemoryBarrierBuffer:\r
2357         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);\r
2358         return 0;\r
2359     case glslang::EOpMemoryBarrierImage:\r
2360         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);\r
2361         return 0;\r
2362     case glslang::EOpMemoryBarrierShared:\r
2363         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);\r
2364         return 0;\r
2365     case glslang::EOpGroupMemoryBarrier:\r
2366         builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);\r
2367         return 0;\r
2368     default:\r
2369         spv::MissingFunctionality("operation with no arguments");\r
2370         return 0;\r
2371     }\r
2372 }\r
2373 \r
2374 spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)\r
2375 {\r
2376     std::map<int, spv::Id>::iterator iter;\r
2377     iter = symbolValues.find(symbol->getId());\r
2378     spv::Id id;\r
2379     if (symbolValues.end() != iter) {\r
2380         id = iter->second;\r
2381         return id;\r
2382     }\r
2383 \r
2384     // it was not found, create it\r
2385     id = createSpvVariable(symbol);\r
2386     symbolValues[symbol->getId()] = id;\r
2387 \r
2388     if (! symbol->getType().isStruct()) {\r
2389         addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));\r
2390         addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));\r
2391         if (symbol->getQualifier().hasLocation())\r
2392             builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);\r
2393         if (symbol->getQualifier().hasIndex())\r
2394             builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);\r
2395         if (symbol->getQualifier().hasComponent())\r
2396             builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);\r
2397         if (glslangIntermediate->getXfbMode()) {\r
2398             if (symbol->getQualifier().hasXfbStride())\r
2399                 builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);\r
2400             if (symbol->getQualifier().hasXfbBuffer())\r
2401                 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);\r
2402             if (symbol->getQualifier().hasXfbOffset())\r
2403                 builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);\r
2404         }\r
2405     }\r
2406 \r
2407     addDecoration(id, TranslateInvariantDecoration(symbol->getType()));\r
2408     if (symbol->getQualifier().hasStream())\r
2409         builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);\r
2410     if (symbol->getQualifier().hasSet())\r
2411         builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);\r
2412     if (symbol->getQualifier().hasBinding())\r
2413         builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);\r
2414     if (glslangIntermediate->getXfbMode()) {\r
2415         if (symbol->getQualifier().hasXfbStride())\r
2416             builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);\r
2417         if (symbol->getQualifier().hasXfbBuffer())\r
2418             builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);\r
2419     }\r
2420 \r
2421     // built-in variable decorations\r
2422     int num = TranslateBuiltInDecoration(*symbol);\r
2423     if (num != spv::BadValue)\r
2424         builder.addDecoration(id, spv::DecorationBuiltIn, num);\r
2425 \r
2426     if (linkageOnly)\r
2427         builder.addDecoration(id, spv::DecorationNoStaticUse);\r
2428 \r
2429     return id;\r
2430 }\r
2431 \r
2432 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)\r
2433 {\r
2434     if (dec != spv::BadValue)\r
2435         builder.addDecoration(id, dec);\r
2436 }\r
2437 \r
2438 void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)\r
2439 {\r
2440     if (dec != spv::BadValue)\r
2441         builder.addMemberDecoration(id, (unsigned)member, dec);\r
2442 }\r
2443 \r
2444 // Use 'consts' as the flattened glslang source of scalar constants to recursively\r
2445 // build the aggregate SPIR-V constant.\r
2446 //\r
2447 // If there are not enough elements present in 'consts', 0 will be substituted;\r
2448 // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.\r
2449 //\r
2450 spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)\r
2451 {\r
2452     // vector of constants for SPIR-V\r
2453     std::vector<spv::Id> spvConsts;\r
2454 \r
2455     // Type is used for struct and array constants\r
2456     spv::Id typeId = convertGlslangToSpvType(glslangType);\r
2457 \r
2458     if (glslangType.isArray()) {\r
2459         glslang::TType elementType;\r
2460         elementType.shallowCopy(glslangType);   // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original\r
2461         elementType.dereference();\r
2462         for (int i = 0; i < glslangType.getArraySize(); ++i)\r
2463             spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));\r
2464     } else if (glslangType.isMatrix()) {\r
2465         glslang::TType vectorType;\r
2466         vectorType.shallowCopy(glslangType);\r
2467         vectorType.dereference();\r
2468         for (int col = 0; col < glslangType.getMatrixCols(); ++col)\r
2469             spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));\r
2470     } else if (glslangType.getStruct()) {\r
2471         glslang::TVector<glslang::TTypeLoc>::const_iterator iter;\r
2472         for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)\r
2473             spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));\r
2474     } else if (glslangType.isVector()) {\r
2475         for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {\r
2476             bool zero = nextConst >= consts.size();\r
2477             switch (glslangType.getBasicType()) {\r
2478             case glslang::EbtInt:\r
2479                 spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));\r
2480                 break;\r
2481             case glslang::EbtUint:\r
2482                 spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));\r
2483                 break;\r
2484             case glslang::EbtFloat:\r
2485                 spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));\r
2486                 break;\r
2487             case glslang::EbtDouble:\r
2488                 spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));\r
2489                 break;\r
2490             case glslang::EbtBool:\r
2491                 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));\r
2492                 break;\r
2493             default:\r
2494                 spv::MissingFunctionality("constant vector type");\r
2495                 break;\r
2496             }\r
2497             ++nextConst;\r
2498         }\r
2499     } else {\r
2500         // we have a non-aggregate (scalar) constant\r
2501         bool zero = nextConst >= consts.size();\r
2502         spv::Id scalar = 0;\r
2503         switch (glslangType.getBasicType()) {\r
2504         case glslang::EbtInt:\r
2505             scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());\r
2506             break;\r
2507         case glslang::EbtUint:\r
2508             scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());\r
2509             break;\r
2510         case glslang::EbtFloat:\r
2511             scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());\r
2512             break;\r
2513         case glslang::EbtDouble:\r
2514             scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());\r
2515             break;\r
2516         case glslang::EbtBool:\r
2517             scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());\r
2518             break;\r
2519         default:\r
2520             spv::MissingFunctionality("constant scalar type");\r
2521             break;\r
2522         }\r
2523         ++nextConst;\r
2524         return scalar;\r
2525     }\r
2526 \r
2527     return builder.makeCompositeConstant(typeId, spvConsts);\r
2528 }\r
2529 \r
2530 };  // end anonymous namespace\r
2531 \r
2532 namespace glslang {\r
2533 \r
2534 // Write SPIR-V out to a binary file\r
2535 void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)\r
2536 {\r
2537     std::ofstream out;\r
2538     std::string fileName(baseName);\r
2539     fileName.append(".spv");\r
2540     out.open(fileName.c_str(), std::ios::binary | std::ios::out);\r
2541     for (int i = 0; i < (int)spirv.size(); ++i) {\r
2542         unsigned int word = spirv[i];\r
2543         out.write((const char*)&word, 4);\r
2544     }\r
2545     out.close();\r
2546 }\r
2547 \r
2548 //\r
2549 // Set up the glslang traversal\r
2550 //\r
2551 void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)\r
2552 {\r
2553     TIntermNode* root = intermediate.getTreeRoot();\r
2554 \r
2555     if (root == 0)\r
2556         return;\r
2557 \r
2558     glslang::GetThreadPoolAllocator().push();\r
2559 \r
2560     TGlslangToSpvTraverser it(&intermediate);\r
2561 \r
2562     root->traverse(&it);\r
2563 \r
2564     it.dumpSpv(spirv);\r
2565 \r
2566     glslang::GetThreadPoolAllocator().pop();\r
2567 }\r
2568 \r
2569 }; // end namespace glslang\r