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