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