Merge pull request #427 from wesleygriffin/master
[platform/upstream/glslang.git] / glslang / MachineIndependent / intermOut.cpp
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //Copyright (C) 2012-2016 LunarG, Inc.
4 //
5 //All rights reserved.
6 //
7 //Redistribution and use in source and binary forms, with or without
8 //modification, are permitted provided that the following conditions
9 //are met:
10 //
11 //    Redistributions of source code must retain the above copyright
12 //    notice, this list of conditions and the following disclaimer.
13 //
14 //    Redistributions in binary form must reproduce the above
15 //    copyright notice, this list of conditions and the following
16 //    disclaimer in the documentation and/or other materials provided
17 //    with the distribution.
18 //
19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20 //    contributors may be used to endorse or promote products derived
21 //    from this software without specific prior written permission.
22 //
23 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 //POSSIBILITY OF SUCH DAMAGE.
35 //
36
37 #include "localintermediate.h"
38 #include "../Include/InfoSink.h"
39
40 #ifdef _MSC_VER
41 #include <cfloat>
42 #else
43 #include <cmath>
44 #endif
45
46 namespace {
47
48 bool is_positive_infinity(double x) {
49 #ifdef _MSC_VER
50   return _fpclass(x) == _FPCLASS_PINF;
51 #else
52   return std::isinf(x) && (x >= 0);
53 #endif
54 }
55
56 }
57
58 namespace glslang {
59
60 //
61 // Two purposes:
62 // 1.  Show an example of how to iterate tree.  Functions can
63 //     also directly call Traverse() on children themselves to
64 //     have finer grained control over the process than shown here.
65 //     See the last function for how to get started.
66 // 2.  Print out a text based description of the tree.
67 //
68
69 //
70 // Use this class to carry along data from node to node in
71 // the traversal
72 //
73 class TOutputTraverser : public TIntermTraverser {
74 public:
75     TOutputTraverser(TInfoSink& i) : infoSink(i) { }
76
77     virtual bool visitBinary(TVisit, TIntermBinary* node);
78     virtual bool visitUnary(TVisit, TIntermUnary* node);
79     virtual bool visitAggregate(TVisit, TIntermAggregate* node);
80     virtual bool visitSelection(TVisit, TIntermSelection* node);
81     virtual void visitConstantUnion(TIntermConstantUnion* node);
82     virtual void visitSymbol(TIntermSymbol* node);
83     virtual bool visitLoop(TVisit, TIntermLoop* node);
84     virtual bool visitBranch(TVisit, TIntermBranch* node);
85     virtual bool visitSwitch(TVisit, TIntermSwitch* node);
86
87     TInfoSink& infoSink;
88 protected:
89     TOutputTraverser(TOutputTraverser&);
90     TOutputTraverser& operator=(TOutputTraverser&);
91 };
92
93 //
94 // Helper functions for printing, not part of traversing.
95 //
96
97 static void OutputTreeText(TInfoSink& infoSink, const TIntermNode* node, const int depth)
98 {
99     int i;
100
101     infoSink.debug << node->getLoc().string << ":";
102     if (node->getLoc().line)
103         infoSink.debug << node->getLoc().line;
104     else
105         infoSink.debug << "? ";
106
107     for (i = 0; i < depth; ++i)
108         infoSink.debug << "  ";
109 }
110
111 //
112 // The rest of the file are the traversal functions.  The last one
113 // is the one that starts the traversal.
114 //
115 // Return true from interior nodes to have the external traversal
116 // continue on to children.  If you process children yourself,
117 // return false.
118 //
119
120 bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
121 {
122     TInfoSink& out = infoSink;
123
124     OutputTreeText(out, node, depth);
125
126     switch (node->getOp()) {
127     case EOpAssign:                   out.debug << "move second child to first child";           break;
128     case EOpAddAssign:                out.debug << "add second child into first child";          break;
129     case EOpSubAssign:                out.debug << "subtract second child into first child";     break;
130     case EOpMulAssign:                out.debug << "multiply second child into first child";     break;
131     case EOpVectorTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
132     case EOpVectorTimesScalarAssign:  out.debug << "vector scale second child into first child"; break;
133     case EOpMatrixTimesScalarAssign:  out.debug << "matrix scale second child into first child"; break;
134     case EOpMatrixTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
135     case EOpDivAssign:                out.debug << "divide second child into first child";       break;
136     case EOpModAssign:                out.debug << "mod second child into first child";          break;
137     case EOpAndAssign:                out.debug << "and second child into first child";          break;
138     case EOpInclusiveOrAssign:        out.debug << "or second child into first child";           break;
139     case EOpExclusiveOrAssign:        out.debug << "exclusive or second child into first child"; break;
140     case EOpLeftShiftAssign:          out.debug << "left shift second child into first child";   break;
141     case EOpRightShiftAssign:         out.debug << "right shift second child into first child";  break;
142
143     case EOpIndexDirect:   out.debug << "direct index";   break;
144     case EOpIndexIndirect: out.debug << "indirect index"; break;
145     case EOpIndexDirectStruct:
146         out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
147         out.debug << ": direct index for structure";      break;
148     case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
149
150     case EOpAdd:    out.debug << "add";                     break;
151     case EOpSub:    out.debug << "subtract";                break;
152     case EOpMul:    out.debug << "component-wise multiply"; break;
153     case EOpDiv:    out.debug << "divide";                  break;
154     case EOpMod:    out.debug << "mod";                     break;
155     case EOpRightShift:  out.debug << "right-shift";  break;
156     case EOpLeftShift:   out.debug << "left-shift";   break;
157     case EOpAnd:         out.debug << "bitwise and";  break;
158     case EOpInclusiveOr: out.debug << "inclusive-or"; break;
159     case EOpExclusiveOr: out.debug << "exclusive-or"; break;
160     case EOpEqual:            out.debug << "Compare Equal";                 break;
161     case EOpNotEqual:         out.debug << "Compare Not Equal";             break;
162     case EOpLessThan:         out.debug << "Compare Less Than";             break;
163     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
164     case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
165     case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
166
167     case EOpVectorTimesScalar: out.debug << "vector-scale";          break;
168     case EOpVectorTimesMatrix: out.debug << "vector-times-matrix";   break;
169     case EOpMatrixTimesVector: out.debug << "matrix-times-vector";   break;
170     case EOpMatrixTimesScalar: out.debug << "matrix-scale";          break;
171     case EOpMatrixTimesMatrix: out.debug << "matrix-multiply";       break;
172
173     case EOpLogicalOr:  out.debug << "logical-or";   break;
174     case EOpLogicalXor: out.debug << "logical-xor"; break;
175     case EOpLogicalAnd: out.debug << "logical-and"; break;
176     default: out.debug << "<unknown op>";
177     }
178
179     out.debug << " (" << node->getCompleteString() << ")";
180
181     out.debug << "\n";
182
183     return true;
184 }
185
186 bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
187 {
188     TInfoSink& out = infoSink;
189
190     OutputTreeText(out, node, depth);
191
192     switch (node->getOp()) {
193     case EOpNegative:       out.debug << "Negate value";         break;
194     case EOpVectorLogicalNot:
195     case EOpLogicalNot:     out.debug << "Negate conditional";   break;
196     case EOpBitwiseNot:     out.debug << "Bitwise not";          break;
197
198     case EOpPostIncrement:  out.debug << "Post-Increment";       break;
199     case EOpPostDecrement:  out.debug << "Post-Decrement";       break;
200     case EOpPreIncrement:   out.debug << "Pre-Increment";        break;
201     case EOpPreDecrement:   out.debug << "Pre-Decrement";        break;
202
203     case EOpConvIntToBool:     out.debug << "Convert int to bool";     break;
204     case EOpConvUintToBool:    out.debug << "Convert uint to bool";    break;
205     case EOpConvFloatToBool:   out.debug << "Convert float to bool";   break;
206     case EOpConvDoubleToBool:  out.debug << "Convert double to bool";  break;
207     case EOpConvInt64ToBool:   out.debug << "Convert int64 to bool";   break;
208     case EOpConvUint64ToBool:  out.debug << "Convert uint64 to bool";  break;
209     case EOpConvIntToFloat:    out.debug << "Convert int to float";    break;
210     case EOpConvUintToFloat:   out.debug << "Convert uint to float";   break;
211     case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break;
212     case EOpConvInt64ToFloat:  out.debug << "Convert int64 to float";  break;
213     case EOpConvUint64ToFloat: out.debug << "Convert uint64 to float"; break;
214     case EOpConvBoolToFloat:   out.debug << "Convert bool to float";   break;
215     case EOpConvUintToInt:     out.debug << "Convert uint to int";     break;
216     case EOpConvFloatToInt:    out.debug << "Convert float to int";    break;
217     case EOpConvDoubleToInt:   out.debug << "Convert double to int";   break;
218     case EOpConvBoolToInt:     out.debug << "Convert bool to int";     break;
219     case EOpConvInt64ToInt:    out.debug << "Convert int64 to int";    break;
220     case EOpConvUint64ToInt:   out.debug << "Convert uint64 to int";   break;
221     case EOpConvIntToUint:     out.debug << "Convert int to uint";     break;
222     case EOpConvFloatToUint:   out.debug << "Convert float to uint";   break;
223     case EOpConvDoubleToUint:  out.debug << "Convert double to uint";  break;
224     case EOpConvBoolToUint:    out.debug << "Convert bool to uint";    break;
225     case EOpConvInt64ToUint:   out.debug << "Convert int64 to uint";   break;
226     case EOpConvUint64ToUint:  out.debug << "Convert uint64 to uint";  break;
227     case EOpConvIntToDouble:   out.debug << "Convert int to double";   break;
228     case EOpConvUintToDouble:  out.debug << "Convert uint to double";  break;
229     case EOpConvFloatToDouble: out.debug << "Convert float to double"; break;
230     case EOpConvBoolToDouble:  out.debug << "Convert bool to double";  break;
231     case EOpConvInt64ToDouble: out.debug << "Convert int64 to double"; break;
232     case EOpConvUint64ToDouble: out.debug << "Convert uint64 to double";  break;
233     case EOpConvBoolToInt64:   out.debug << "Convert bool to int64";   break;
234     case EOpConvIntToInt64:    out.debug << "Convert int to int64";    break;
235     case EOpConvUintToInt64:   out.debug << "Convert uint to int64";   break;
236     case EOpConvFloatToInt64:  out.debug << "Convert float to int64";  break;
237     case EOpConvDoubleToInt64: out.debug << "Convert double to int64"; break;
238     case EOpConvUint64ToInt64: out.debug << "Convert uint64 to int64"; break;
239     case EOpConvBoolToUint64:  out.debug << "Convert bool to uint64";  break;
240     case EOpConvIntToUint64:   out.debug << "Convert int to uint64";   break;
241     case EOpConvUintToUint64:  out.debug << "Convert uint to uint64";  break;
242     case EOpConvFloatToUint64: out.debug << "Convert float to uint64"; break;
243     case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
244     case EOpConvInt64ToUint64: out.debug << "Convert uint64 to uint64"; break;
245
246     case EOpRadians:        out.debug << "radians";              break;
247     case EOpDegrees:        out.debug << "degrees";              break;
248     case EOpSin:            out.debug << "sine";                 break;
249     case EOpCos:            out.debug << "cosine";               break;
250     case EOpTan:            out.debug << "tangent";              break;
251     case EOpAsin:           out.debug << "arc sine";             break;
252     case EOpAcos:           out.debug << "arc cosine";           break;
253     case EOpAtan:           out.debug << "arc tangent";          break;
254     case EOpSinh:           out.debug << "hyp. sine";            break;
255     case EOpCosh:           out.debug << "hyp. cosine";          break;
256     case EOpTanh:           out.debug << "hyp. tangent";         break;
257     case EOpAsinh:          out.debug << "arc hyp. sine";        break;
258     case EOpAcosh:          out.debug << "arc hyp. cosine";      break;
259     case EOpAtanh:          out.debug << "arc hyp. tangent";     break;
260
261     case EOpExp:            out.debug << "exp";                  break;
262     case EOpLog:            out.debug << "log";                  break;
263     case EOpExp2:           out.debug << "exp2";                 break;
264     case EOpLog2:           out.debug << "log2";                 break;
265     case EOpSqrt:           out.debug << "sqrt";                 break;
266     case EOpInverseSqrt:    out.debug << "inverse sqrt";         break;
267
268     case EOpAbs:            out.debug << "Absolute value";       break;
269     case EOpSign:           out.debug << "Sign";                 break;
270     case EOpFloor:          out.debug << "Floor";                break;
271     case EOpTrunc:          out.debug << "trunc";                break;
272     case EOpRound:          out.debug << "round";                break;
273     case EOpRoundEven:      out.debug << "roundEven";            break;
274     case EOpCeil:           out.debug << "Ceiling";              break;
275     case EOpFract:          out.debug << "Fraction";             break;
276
277     case EOpIsNan:          out.debug << "isnan";                break;
278     case EOpIsInf:          out.debug << "isinf";                break;
279
280     case EOpFloatBitsToInt: out.debug << "floatBitsToInt";       break;
281     case EOpFloatBitsToUint:out.debug << "floatBitsToUint";      break;
282     case EOpIntBitsToFloat: out.debug << "intBitsToFloat";       break;
283     case EOpUintBitsToFloat:out.debug << "uintBitsToFloat";      break;
284     case EOpDoubleBitsToInt64:  out.debug << "doubleBitsToInt64";  break;
285     case EOpDoubleBitsToUint64: out.debug << "doubleBitsToUint64"; break;
286     case EOpInt64BitsToDouble:  out.debug << "int64BitsToDouble";  break;
287     case EOpUint64BitsToDouble: out.debug << "uint64BitsToDouble"; break;
288     case EOpPackSnorm2x16:  out.debug << "packSnorm2x16";        break;
289     case EOpUnpackSnorm2x16:out.debug << "unpackSnorm2x16";      break;
290     case EOpPackUnorm2x16:  out.debug << "packUnorm2x16";        break;
291     case EOpUnpackUnorm2x16:out.debug << "unpackUnorm2x16";      break;
292     case EOpPackHalf2x16:   out.debug << "packHalf2x16";         break;
293     case EOpUnpackHalf2x16: out.debug << "unpackHalf2x16";       break;
294
295     case EOpPackSnorm4x8:     out.debug << "PackSnorm4x8";       break;
296     case EOpUnpackSnorm4x8:   out.debug << "UnpackSnorm4x8";     break;
297     case EOpPackUnorm4x8:     out.debug << "PackUnorm4x8";       break;
298     case EOpUnpackUnorm4x8:   out.debug << "UnpackUnorm4x8";     break;
299     case EOpPackDouble2x32:   out.debug << "PackDouble2x32";     break;
300     case EOpUnpackDouble2x32: out.debug << "UnpackDouble2x32";   break;
301
302     case EOpPackInt2x32:      out.debug << "packInt2x32";        break;
303     case EOpUnpackInt2x32:    out.debug << "unpackInt2x32";      break;
304     case EOpPackUint2x32:     out.debug << "packUint2x32";       break;
305     case EOpUnpackUint2x32:   out.debug << "unpackUint2x32";     break;
306
307     case EOpLength:         out.debug << "length";               break;
308     case EOpNormalize:      out.debug << "normalize";            break;
309     case EOpDPdx:           out.debug << "dPdx";                 break;
310     case EOpDPdy:           out.debug << "dPdy";                 break;
311     case EOpFwidth:         out.debug << "fwidth";               break;
312     case EOpDPdxFine:       out.debug << "dPdxFine";             break;
313     case EOpDPdyFine:       out.debug << "dPdyFine";             break;
314     case EOpFwidthFine:     out.debug << "fwidthFine";           break;
315     case EOpDPdxCoarse:     out.debug << "dPdxCoarse";           break;
316     case EOpDPdyCoarse:     out.debug << "dPdyCoarse";           break;
317     case EOpFwidthCoarse:   out.debug << "fwidthCoarse";         break;
318
319     case EOpInterpolateAtCentroid: out.debug << "interpolateAtCentroid";  break;
320
321     case EOpDeterminant:    out.debug << "determinant";          break;
322     case EOpMatrixInverse:  out.debug << "inverse";              break;
323     case EOpTranspose:      out.debug << "transpose";            break;
324
325     case EOpAny:            out.debug << "any";                  break;
326     case EOpAll:            out.debug << "all";                  break;
327
328     case EOpArrayLength:    out.debug << "array length";         break;
329
330     case EOpEmitStreamVertex:   out.debug << "EmitStreamVertex";   break;
331     case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break;
332
333     case EOpAtomicCounterIncrement: out.debug << "AtomicCounterIncrement";break;
334     case EOpAtomicCounterDecrement: out.debug << "AtomicCounterDecrement";break;
335     case EOpAtomicCounter:          out.debug << "AtomicCounter";         break;
336
337     case EOpTextureQuerySize:       out.debug << "textureSize";           break;
338     case EOpTextureQueryLod:        out.debug << "textureQueryLod";       break;
339     case EOpTextureQueryLevels:     out.debug << "textureQueryLevels";    break;
340     case EOpTextureQuerySamples:    out.debug << "textureSamples";        break;
341     case EOpImageQuerySize:         out.debug << "imageQuerySize";        break;
342     case EOpImageQuerySamples:      out.debug << "imageQuerySamples";     break;
343     case EOpImageLoad:              out.debug << "imageLoad";             break;
344
345     case EOpBitFieldReverse:        out.debug << "bitFieldReverse";       break;
346     case EOpBitCount:               out.debug << "bitCount";              break;
347     case EOpFindLSB:                out.debug << "findLSB";               break;
348     case EOpFindMSB:                out.debug << "findMSB";               break;
349
350     case EOpNoise:                  out.debug << "noise";                 break;
351
352     case EOpBallot:                 out.debug << "ballot";                break;
353     case EOpReadFirstInvocation:    out.debug << "readFirstInvocation";   break;
354
355     case EOpAnyInvocation:          out.debug << "anyInvocation";         break;
356     case EOpAllInvocations:         out.debug << "allInvocations";        break;
357     case EOpAllInvocationsEqual:    out.debug << "allInvocationsEqual";   break;
358
359     case EOpClip:                   out.debug << "clip";                  break;
360     case EOpIsFinite:               out.debug << "isfinite";              break;
361     case EOpLog10:                  out.debug << "log10";                 break;
362     case EOpRcp:                    out.debug << "rcp";                   break;
363     case EOpSaturate:               out.debug << "saturate";              break;
364
365 #ifdef AMD_EXTENSIONS
366     case EOpMinInvocations:             out.debug << "minInvocations";              break;
367     case EOpMaxInvocations:             out.debug << "maxInvocations";              break;
368     case EOpAddInvocations:             out.debug << "addInvocations";              break;
369     case EOpMinInvocationsNonUniform:   out.debug << "minInvocationsNonUniform";    break;
370     case EOpMaxInvocationsNonUniform:   out.debug << "maxInvocationsNonUniform";    break;
371     case EOpAddInvocationsNonUniform:   out.debug << "addInvocationsNonUniform";    break;
372     case EOpMbcnt:                      out.debug << "mbcnt";                       break;
373
374     case EOpCubeFaceIndex:          out.debug << "cubeFaceIndex";         break;
375     case EOpCubeFaceCoord:          out.debug << "cubeFaceCoord";         break;
376 #endif
377
378     default: out.debug.message(EPrefixError, "Bad unary op");
379     }
380
381     out.debug << " (" << node->getCompleteString() << ")";
382
383     out.debug << "\n";
384
385     return true;
386 }
387
388 bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
389 {
390     TInfoSink& out = infoSink;
391
392     if (node->getOp() == EOpNull) {
393         out.debug.message(EPrefixError, "node is still EOpNull!");
394         return true;
395     }
396
397     OutputTreeText(out, node, depth);
398
399     switch (node->getOp()) {
400     case EOpSequence:      out.debug << "Sequence\n";       return true;
401     case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true;
402     case EOpComma:         out.debug << "Comma";            break;
403     case EOpFunction:      out.debug << "Function Definition: " << node->getName(); break;
404     case EOpFunctionCall:  out.debug << "Function Call: "       << node->getName(); break;
405     case EOpParameters:    out.debug << "Function Parameters: ";                    break;
406
407     case EOpConstructFloat: out.debug << "Construct float"; break;
408     case EOpConstructDouble:out.debug << "Construct double"; break;
409     case EOpConstructVec2:  out.debug << "Construct vec2";  break;
410     case EOpConstructVec3:  out.debug << "Construct vec3";  break;
411     case EOpConstructVec4:  out.debug << "Construct vec4";  break;
412     case EOpConstructBool:  out.debug << "Construct bool";  break;
413     case EOpConstructBVec2: out.debug << "Construct bvec2"; break;
414     case EOpConstructBVec3: out.debug << "Construct bvec3"; break;
415     case EOpConstructBVec4: out.debug << "Construct bvec4"; break;
416     case EOpConstructInt:   out.debug << "Construct int";   break;
417     case EOpConstructIVec2: out.debug << "Construct ivec2"; break;
418     case EOpConstructIVec3: out.debug << "Construct ivec3"; break;
419     case EOpConstructIVec4: out.debug << "Construct ivec4"; break;
420     case EOpConstructUint:    out.debug << "Construct uint";    break;
421     case EOpConstructUVec2:   out.debug << "Construct uvec2";   break;
422     case EOpConstructUVec3:   out.debug << "Construct uvec3";   break;
423     case EOpConstructUVec4:   out.debug << "Construct uvec4";   break;
424     case EOpConstructInt64:   out.debug << "Construct int64_t"; break;
425     case EOpConstructI64Vec2: out.debug << "Construct i64vec2"; break;
426     case EOpConstructI64Vec3: out.debug << "Construct i64vec3"; break;
427     case EOpConstructI64Vec4: out.debug << "Construct i64vec4"; break;
428     case EOpConstructUint64:  out.debug << "Construct uint64_t"; break;
429     case EOpConstructU64Vec2: out.debug << "Construct u64vec2"; break;
430     case EOpConstructU64Vec3: out.debug << "Construct u64vec3"; break;
431     case EOpConstructU64Vec4: out.debug << "Construct u64vec4"; break;
432     case EOpConstructMat2x2:  out.debug << "Construct mat2";    break;
433     case EOpConstructMat2x3:  out.debug << "Construct mat2x3";  break;
434     case EOpConstructMat2x4:  out.debug << "Construct mat2x4";  break;
435     case EOpConstructMat3x2:  out.debug << "Construct mat3x2";  break;
436     case EOpConstructMat3x3:  out.debug << "Construct mat3";    break;
437     case EOpConstructMat3x4:  out.debug << "Construct mat3x4";  break;
438     case EOpConstructMat4x2:  out.debug << "Construct mat4x2";  break;
439     case EOpConstructMat4x3:  out.debug << "Construct mat4x3";  break;
440     case EOpConstructMat4x4:  out.debug << "Construct mat4";    break;
441     case EOpConstructDMat2x2: out.debug << "Construct dmat2";   break;
442     case EOpConstructDMat2x3: out.debug << "Construct dmat2x3"; break;
443     case EOpConstructDMat2x4: out.debug << "Construct dmat2x4"; break;
444     case EOpConstructDMat3x2: out.debug << "Construct dmat3x2"; break;
445     case EOpConstructDMat3x3: out.debug << "Construct dmat3";   break;
446     case EOpConstructDMat3x4: out.debug << "Construct dmat3x4"; break;
447     case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break;
448     case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
449     case EOpConstructDMat4x4: out.debug << "Construct dmat4";   break;
450     case EOpConstructStruct:  out.debug << "Construct structure";  break;
451     case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
452
453     case EOpLessThan:         out.debug << "Compare Less Than";             break;
454     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
455     case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
456     case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
457     case EOpVectorEqual:      out.debug << "Equal";                         break;
458     case EOpVectorNotEqual:   out.debug << "NotEqual";                      break;
459
460     case EOpMod:           out.debug << "mod";         break;
461     case EOpModf:          out.debug << "modf";        break;
462     case EOpPow:           out.debug << "pow";         break;
463
464     case EOpAtan:          out.debug << "arc tangent"; break;
465
466     case EOpMin:           out.debug << "min";         break;
467     case EOpMax:           out.debug << "max";         break;
468     case EOpClamp:         out.debug << "clamp";       break;
469     case EOpMix:           out.debug << "mix";         break;
470     case EOpStep:          out.debug << "step";        break;
471     case EOpSmoothStep:    out.debug << "smoothstep";  break;
472
473     case EOpDistance:      out.debug << "distance";                break;
474     case EOpDot:           out.debug << "dot-product";             break;
475     case EOpCross:         out.debug << "cross-product";           break;
476     case EOpFaceForward:   out.debug << "face-forward";            break;
477     case EOpReflect:       out.debug << "reflect";                 break;
478     case EOpRefract:       out.debug << "refract";                 break;
479     case EOpMul:           out.debug << "component-wise multiply"; break;
480     case EOpOuterProduct:  out.debug << "outer product";           break;
481
482     case EOpEmitVertex:    out.debug << "EmitVertex";              break;
483     case EOpEndPrimitive:  out.debug << "EndPrimitive";            break;
484
485     case EOpBarrier:                    out.debug << "Barrier";                    break;
486     case EOpMemoryBarrier:              out.debug << "MemoryBarrier";              break;
487     case EOpMemoryBarrierAtomicCounter: out.debug << "MemoryBarrierAtomicCounter"; break;
488     case EOpMemoryBarrierBuffer:        out.debug << "MemoryBarrierBuffer";        break;
489     case EOpMemoryBarrierImage:         out.debug << "MemoryBarrierImage";         break;
490     case EOpMemoryBarrierShared:        out.debug << "MemoryBarrierShared";        break;
491     case EOpGroupMemoryBarrier:         out.debug << "GroupMemoryBarrier";         break;
492
493     case EOpReadInvocation:             out.debug << "readInvocation";        break;
494
495 #ifdef AMD_EXTENSIONS
496     case EOpSwizzleInvocations:         out.debug << "swizzleInvocations";       break;
497     case EOpSwizzleInvocationsMasked:   out.debug << "swizzleInvocationsMasked"; break;
498     case EOpWriteInvocation:            out.debug << "writeInvocation";          break;
499
500     case EOpMin3:                       out.debug << "min3";                  break;
501     case EOpMax3:                       out.debug << "max3";                  break;
502     case EOpMid3:                       out.debug << "mid3";                  break;
503
504     case EOpTime:                       out.debug << "time";                  break;
505 #endif
506
507     case EOpAtomicAdd:                  out.debug << "AtomicAdd";             break;
508     case EOpAtomicMin:                  out.debug << "AtomicMin";             break;
509     case EOpAtomicMax:                  out.debug << "AtomicMax";             break;
510     case EOpAtomicAnd:                  out.debug << "AtomicAnd";             break;
511     case EOpAtomicOr:                   out.debug << "AtomicOr";              break;
512     case EOpAtomicXor:                  out.debug << "AtomicXor";             break;
513     case EOpAtomicExchange:             out.debug << "AtomicExchange";        break;
514     case EOpAtomicCompSwap:             out.debug << "AtomicCompSwap";        break;
515
516     case EOpImageQuerySize:             out.debug << "imageQuerySize";        break;
517     case EOpImageQuerySamples:          out.debug << "imageQuerySamples";     break;
518     case EOpImageLoad:                  out.debug << "imageLoad";             break;
519     case EOpImageStore:                 out.debug << "imageStore";            break;
520     case EOpImageAtomicAdd:             out.debug << "imageAtomicAdd";        break;
521     case EOpImageAtomicMin:             out.debug << "imageAtomicMin";        break;
522     case EOpImageAtomicMax:             out.debug << "imageAtomicMax";        break;
523     case EOpImageAtomicAnd:             out.debug << "imageAtomicAnd";        break;
524     case EOpImageAtomicOr:              out.debug << "imageAtomicOr";         break;
525     case EOpImageAtomicXor:             out.debug << "imageAtomicXor";        break;
526     case EOpImageAtomicExchange:        out.debug << "imageAtomicExchange";   break;
527     case EOpImageAtomicCompSwap:        out.debug << "imageAtomicCompSwap";   break;
528
529     case EOpTextureQuerySize:           out.debug << "textureSize";           break;
530     case EOpTextureQueryLod:            out.debug << "textureQueryLod";       break;
531     case EOpTextureQueryLevels:         out.debug << "textureQueryLevels";    break;
532     case EOpTextureQuerySamples:        out.debug << "textureSamples";        break;
533     case EOpTexture:                    out.debug << "texture";               break;
534     case EOpTextureProj:                out.debug << "textureProj";           break;
535     case EOpTextureLod:                 out.debug << "textureLod";            break;
536     case EOpTextureOffset:              out.debug << "textureOffset";         break;
537     case EOpTextureFetch:               out.debug << "textureFetch";          break;
538     case EOpTextureFetchOffset:         out.debug << "textureFetchOffset";    break;
539     case EOpTextureProjOffset:          out.debug << "textureProjOffset";     break;
540     case EOpTextureLodOffset:           out.debug << "textureLodOffset";      break;
541     case EOpTextureProjLod:             out.debug << "textureProjLod";        break;
542     case EOpTextureProjLodOffset:       out.debug << "textureProjLodOffset";  break;
543     case EOpTextureGrad:                out.debug << "textureGrad";           break;
544     case EOpTextureGradOffset:          out.debug << "textureGradOffset";     break;
545     case EOpTextureProjGrad:            out.debug << "textureProjGrad";       break;
546     case EOpTextureProjGradOffset:      out.debug << "textureProjGradOffset"; break;
547     case EOpTextureGather:              out.debug << "textureGather";         break;
548     case EOpTextureGatherOffset:        out.debug << "textureGatherOffset";   break;
549     case EOpTextureGatherOffsets:       out.debug << "textureGatherOffsets";  break;
550
551     case EOpAddCarry:                   out.debug << "addCarry";              break;
552     case EOpSubBorrow:                  out.debug << "subBorrow";             break;
553     case EOpUMulExtended:               out.debug << "uMulExtended";          break;
554     case EOpIMulExtended:               out.debug << "iMulExtended";          break;
555     case EOpBitfieldExtract:            out.debug << "bitfieldExtract";       break;
556     case EOpBitfieldInsert:             out.debug << "bitfieldInsert";        break;
557
558     case EOpFma:                        out.debug << "fma";                   break;
559     case EOpFrexp:                      out.debug << "frexp";                 break;
560     case EOpLdexp:                      out.debug << "ldexp";                 break;
561
562     case EOpInterpolateAtSample:   out.debug << "interpolateAtSample";    break;
563     case EOpInterpolateAtOffset:   out.debug << "interpolateAtOffset";    break;
564 #ifdef AMD_EXTENSIONS
565     case EOpInterpolateAtVertex:   out.debug << "interpolateAtVertex";    break;
566 #endif
567
568     case EOpSinCos:                     out.debug << "sincos";                break;
569     case EOpGenMul:                     out.debug << "mul";                   break;
570
571     case EOpAllMemoryBarrierWithGroupSync:    out.debug << "AllMemoryBarrierWithGroupSync";    break;
572     case EOpGroupMemoryBarrierWithGroupSync: out.debug << "GroupMemoryBarrierWithGroupSync"; break;
573     case EOpWorkgroupMemoryBarrier:           out.debug << "WorkgroupMemoryBarrier";           break;
574     case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break;
575
576     default: out.debug.message(EPrefixError, "Bad aggregation op");
577     }
578
579     if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
580         out.debug << " (" << node->getCompleteString() << ")";
581
582     out.debug << "\n";
583
584     return true;
585 }
586
587 bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
588 {
589     TInfoSink& out = infoSink;
590
591     OutputTreeText(out, node, depth);
592
593     out.debug << "Test condition and select";
594     out.debug << " (" << node->getCompleteString() << ")\n";
595
596     ++depth;
597
598     OutputTreeText(out, node, depth);
599     out.debug << "Condition\n";
600     node->getCondition()->traverse(this);
601
602     OutputTreeText(out, node, depth);
603     if (node->getTrueBlock()) {
604         out.debug << "true case\n";
605         node->getTrueBlock()->traverse(this);
606     } else
607         out.debug << "true case is null\n";
608
609     if (node->getFalseBlock()) {
610         OutputTreeText(out, node, depth);
611         out.debug << "false case\n";
612         node->getFalseBlock()->traverse(this);
613     }
614
615     --depth;
616
617     return false;
618 }
619
620 static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth)
621 {
622     int size = node->getType().computeNumComponents();
623
624     for (int i = 0; i < size; i++) {
625         OutputTreeText(out, node, depth);
626         switch (constUnion[i].getType()) {
627         case EbtBool:
628             if (constUnion[i].getBConst())
629                 out.debug << "true";
630             else
631                 out.debug << "false";
632
633             out.debug << " (" << "const bool" << ")";
634
635             out.debug << "\n";
636             break;
637         case EbtFloat:
638         case EbtDouble:
639             {
640                 const double value = constUnion[i].getDConst();
641                 // Print infinity in a portable way, for test stability.
642                 // Other cases may be needed in the future: negative infinity,
643                 // and NaNs.
644                 if (is_positive_infinity(value))
645                     out.debug << "inf\n";
646                 else {
647                     const int maxSize = 300;
648                     char buf[maxSize];
649                     snprintf(buf, maxSize, "%f", value);
650
651                     out.debug << buf << "\n";
652                 }
653             }
654             break;
655         case EbtInt:
656             {
657                 const int maxSize = 300;
658                 char buf[maxSize];
659                 snprintf(buf, maxSize, "%d (%s)", constUnion[i].getIConst(), "const int");
660
661                 out.debug << buf << "\n";
662             }
663             break;
664         case EbtUint:
665             {
666                 const int maxSize = 300;
667                 char buf[maxSize];
668                 snprintf(buf, maxSize, "%u (%s)", constUnion[i].getUConst(), "const uint");
669
670                 out.debug << buf << "\n";
671             }
672             break;
673         case EbtInt64:
674             {
675                 const int maxSize = 300;
676                 char buf[maxSize];
677                 snprintf(buf, maxSize, "%lld (%s)", constUnion[i].getI64Const(), "const int64_t");
678
679                 out.debug << buf << "\n";
680             }
681             break;
682         case EbtUint64:
683             {
684                 const int maxSize = 300;
685                 char buf[maxSize];
686                 snprintf(buf, maxSize, "%llu (%s)", constUnion[i].getU64Const(), "const uint64_t");
687
688                 out.debug << buf << "\n";
689             }
690             break;
691         default:
692             out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc());
693             break;
694         }
695     }
696 }
697
698 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
699 {
700     OutputTreeText(infoSink, node, depth);
701     infoSink.debug << "Constant:\n";
702
703     OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
704 }
705
706 void TOutputTraverser::visitSymbol(TIntermSymbol* node)
707 {
708     OutputTreeText(infoSink, node, depth);
709
710     infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n";
711
712     if (! node->getConstArray().empty())
713         OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
714     else if (node->getConstSubtree()) {
715         incrementDepth(node);
716         node->getConstSubtree()->traverse(this);
717         decrementDepth();
718     }
719 }
720
721 bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
722 {
723     TInfoSink& out = infoSink;
724
725     OutputTreeText(out, node, depth);
726
727     out.debug << "Loop with condition ";
728     if (! node->testFirst())
729         out.debug << "not ";
730     out.debug << "tested first\n";
731
732     ++depth;
733
734     OutputTreeText(infoSink, node, depth);
735     if (node->getTest()) {
736         out.debug << "Loop Condition\n";
737         node->getTest()->traverse(this);
738     } else
739         out.debug << "No loop condition\n";
740
741     OutputTreeText(infoSink, node, depth);
742     if (node->getBody()) {
743         out.debug << "Loop Body\n";
744         node->getBody()->traverse(this);
745     } else
746         out.debug << "No loop body\n";
747
748     if (node->getTerminal()) {
749         OutputTreeText(infoSink, node, depth);
750         out.debug << "Loop Terminal Expression\n";
751         node->getTerminal()->traverse(this);
752     }
753
754     --depth;
755
756     return false;
757 }
758
759 bool TOutputTraverser::visitBranch(TVisit /* visit*/, TIntermBranch* node)
760 {
761     TInfoSink& out = infoSink;
762
763     OutputTreeText(out, node, depth);
764
765     switch (node->getFlowOp()) {
766     case EOpKill:      out.debug << "Branch: Kill";           break;
767     case EOpBreak:     out.debug << "Branch: Break";          break;
768     case EOpContinue:  out.debug << "Branch: Continue";       break;
769     case EOpReturn:    out.debug << "Branch: Return";         break;
770     case EOpCase:      out.debug << "case: ";                 break;
771     case EOpDefault:   out.debug << "default: ";              break;
772     default:               out.debug << "Branch: Unknown Branch"; break;
773     }
774
775     if (node->getExpression()) {
776         out.debug << " with expression\n";
777         ++depth;
778         node->getExpression()->traverse(this);
779         --depth;
780     } else
781         out.debug << "\n";
782
783     return false;
784 }
785
786 bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
787 {
788     TInfoSink& out = infoSink;
789
790     OutputTreeText(out, node, depth);
791     out.debug << "switch\n";
792
793     OutputTreeText(out, node, depth);
794     out.debug << "condition\n";
795     ++depth;
796     node->getCondition()->traverse(this);
797
798     --depth;
799     OutputTreeText(out, node, depth);
800     out.debug << "body\n";
801     ++depth;
802     node->getBody()->traverse(this);
803
804     --depth;
805
806     return false;
807 }
808
809 //
810 // This function is the one to call externally to start the traversal.
811 // Individual functions can be initialized to 0 to skip processing of that
812 // type of node.  It's children will still be processed.
813 //
814 void TIntermediate::output(TInfoSink& infoSink, bool tree)
815 {
816     infoSink.debug << "Shader version: " << version << "\n";
817     if (requestedExtensions.size() > 0) {
818         for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt)
819             infoSink.debug << "Requested " << *extIt << "\n";
820     }
821
822     if (xfbMode)
823         infoSink.debug << "in xfb mode\n";
824
825     switch (language) {
826     case EShLangVertex:
827         break;
828
829     case EShLangTessControl:
830         infoSink.debug << "vertices = " << vertices << "\n";
831         break;
832
833     case EShLangTessEvaluation:
834         infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
835         infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n";
836         infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n";
837         if (pointMode)
838             infoSink.debug << "using point mode\n";
839         break;
840
841     case EShLangGeometry:
842         infoSink.debug << "invocations = " << invocations << "\n";
843         infoSink.debug << "max_vertices = " << vertices << "\n";
844         infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
845         infoSink.debug << "output primitive = " << TQualifier::getGeometryString(outputPrimitive) << "\n";
846         break;
847
848     case EShLangFragment:
849         if (pixelCenterInteger)
850             infoSink.debug << "gl_FragCoord pixel center is integer\n";
851         if (originUpperLeft)
852             infoSink.debug << "gl_FragCoord origin is upper left\n";
853         if (earlyFragmentTests)
854             infoSink.debug << "using early_fragment_tests\n";
855         if (depthLayout != EldNone)
856             infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
857         if (blendEquations != 0) {
858             infoSink.debug << "using";
859             // blendEquations is a mask, decode it
860             for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
861                 if (blendEquations & (1 << be))
862                     infoSink.debug << " " << TQualifier::getBlendEquationString(be);
863             }
864             infoSink.debug << "\n";
865         }
866         break;
867
868     case EShLangCompute:
869         infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n";
870         {
871             if (localSizeSpecId[0] != TQualifier::layoutNotSet ||
872                 localSizeSpecId[1] != TQualifier::layoutNotSet ||
873                 localSizeSpecId[2] != TQualifier::layoutNotSet) {
874                 infoSink.debug << "local_size ids = (" <<
875                     localSizeSpecId[0] << ", " <<
876                     localSizeSpecId[1] << ", " <<
877                     localSizeSpecId[2] << ")\n";
878             }
879         }
880         break;
881
882     default:
883         break;
884     }
885
886     if (treeRoot == 0 || ! tree)
887         return;
888
889     TOutputTraverser it(infoSink);
890
891     treeRoot->traverse(&it);
892 }
893
894 } // end namespace glslang