glslang: Fix over 100 warnings from MSVC warning level 4.
[platform/upstream/glslang.git] / glslang / MachineIndependent / intermOut.cpp
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //Copyright (C) 2012-2013 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 namespace glslang {
41
42 //
43 // Two purposes:
44 // 1.  Show an example of how to iterate tree.  Functions can
45 //     also directly call Traverse() on children themselves to
46 //     have finer grained control over the process than shown here.
47 //     See the last function for how to get started.
48 // 2.  Print out a text based description of the tree.
49 //
50
51 //
52 // Use this class to carry along data from node to node in
53 // the traversal
54 //
55 class TOutputTraverser : public TIntermTraverser {
56 public:
57     TOutputTraverser(TInfoSink& i) : infoSink(i) { }
58
59     virtual bool visitBinary(TVisit, TIntermBinary* node);
60     virtual bool visitUnary(TVisit, TIntermUnary* node);
61     virtual bool visitAggregate(TVisit, TIntermAggregate* node);
62     virtual bool visitSelection(TVisit, TIntermSelection* node);
63     virtual void visitConstantUnion(TIntermConstantUnion* node);
64     virtual void visitSymbol(TIntermSymbol* node);
65     virtual bool visitLoop(TVisit, TIntermLoop* node);
66     virtual bool visitBranch(TVisit, TIntermBranch* node);
67     virtual bool visitSwitch(TVisit, TIntermSwitch* node);
68
69     TInfoSink& infoSink;
70 protected:
71     TOutputTraverser(TOutputTraverser&);
72     TOutputTraverser& operator=(TOutputTraverser&);
73 };
74
75 //
76 // Helper functions for printing, not part of traversing.
77 //
78
79 void OutputTreeText(TInfoSink& infoSink, const TIntermNode* node, const int depth)
80 {
81     int i;
82
83     infoSink.debug << node->getLoc().string << ":";
84     if (node->getLoc().line)
85         infoSink.debug << node->getLoc().line;
86     else
87         infoSink.debug << "? ";
88
89     for (i = 0; i < depth; ++i)
90         infoSink.debug << "  ";
91 }
92
93 //
94 // The rest of the file are the traversal functions.  The last one
95 // is the one that starts the traversal.
96 //
97 // Return true from interior nodes to have the external traversal
98 // continue on to children.  If you process children yourself,
99 // return false.
100 //
101
102 bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
103 {
104     TInfoSink& out = infoSink;
105
106     OutputTreeText(out, node, depth);
107
108     switch (node->getOp()) {
109     case EOpAssign:                   out.debug << "move second child to first child";           break;
110     case EOpAddAssign:                out.debug << "add second child into first child";          break;
111     case EOpSubAssign:                out.debug << "subtract second child into first child";     break;
112     case EOpMulAssign:                out.debug << "multiply second child into first child";     break;
113     case EOpVectorTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
114     case EOpVectorTimesScalarAssign:  out.debug << "vector scale second child into first child"; break;
115     case EOpMatrixTimesScalarAssign:  out.debug << "matrix scale second child into first child"; break;
116     case EOpMatrixTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
117     case EOpDivAssign:                out.debug << "divide second child into first child";       break;
118     case EOpModAssign:                out.debug << "mod second child into first child";          break;
119     case EOpAndAssign:                out.debug << "and second child into first child";          break;
120     case EOpInclusiveOrAssign:        out.debug << "or second child into first child";           break;
121     case EOpExclusiveOrAssign:        out.debug << "exclusive or second child into first child"; break;
122     case EOpLeftShiftAssign:          out.debug << "left shift second child into first child";   break;
123     case EOpRightShiftAssign:         out.debug << "right shift second child into first child";  break;
124
125     case EOpIndexDirect:   out.debug << "direct index";   break;
126     case EOpIndexIndirect: out.debug << "indirect index"; break;
127     case EOpIndexDirectStruct:
128         out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
129         out.debug << ": direct index for structure";      break;
130     case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
131
132     case EOpAdd:    out.debug << "add";                     break;
133     case EOpSub:    out.debug << "subtract";                break;
134     case EOpMul:    out.debug << "component-wise multiply"; break;
135     case EOpDiv:    out.debug << "divide";                  break;
136     case EOpMod:    out.debug << "mod";                     break;
137     case EOpRightShift:  out.debug << "right-shift";  break;
138     case EOpLeftShift:   out.debug << "left-shift";   break;
139     case EOpAnd:         out.debug << "bitwise and";  break;
140     case EOpInclusiveOr: out.debug << "inclusive-or"; break;
141     case EOpExclusiveOr: out.debug << "exclusive-or"; break;
142     case EOpEqual:            out.debug << "Compare Equal";                 break;
143     case EOpNotEqual:         out.debug << "Compare Not Equal";             break;
144     case EOpLessThan:         out.debug << "Compare Less Than";             break;
145     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
146     case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
147     case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
148
149     case EOpVectorTimesScalar: out.debug << "vector-scale";          break;
150     case EOpVectorTimesMatrix: out.debug << "vector-times-matrix";   break;
151     case EOpMatrixTimesVector: out.debug << "matrix-times-vector";   break;
152     case EOpMatrixTimesScalar: out.debug << "matrix-scale";          break;
153     case EOpMatrixTimesMatrix: out.debug << "matrix-multiply";       break;
154
155     case EOpLogicalOr:  out.debug << "logical-or";   break;
156     case EOpLogicalXor: out.debug << "logical-xor"; break;
157     case EOpLogicalAnd: out.debug << "logical-and"; break;
158     default: out.debug << "<unknown op>";
159     }
160
161     out.debug << " (" << node->getCompleteString() << ")";
162
163     out.debug << "\n";
164
165     return true;
166 }
167
168 bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
169 {
170     TInfoSink& out = infoSink;
171
172     OutputTreeText(out, node, depth);
173
174     switch (node->getOp()) {
175     case EOpNegative:       out.debug << "Negate value";         break;
176     case EOpVectorLogicalNot:
177     case EOpLogicalNot:     out.debug << "Negate conditional";   break;
178     case EOpBitwiseNot:     out.debug << "Bitwise not";          break;
179
180     case EOpPostIncrement:  out.debug << "Post-Increment";       break;
181     case EOpPostDecrement:  out.debug << "Post-Decrement";       break;
182     case EOpPreIncrement:   out.debug << "Pre-Increment";        break;
183     case EOpPreDecrement:   out.debug << "Pre-Decrement";        break;
184
185     case EOpConvIntToBool:     out.debug << "Convert int to bool";     break;
186     case EOpConvUintToBool:    out.debug << "Convert uint to bool";    break;
187     case EOpConvFloatToBool:   out.debug << "Convert float to bool";   break;
188     case EOpConvDoubleToBool:  out.debug << "Convert double to bool";  break;
189     case EOpConvIntToFloat:    out.debug << "Convert int to float";    break;
190     case EOpConvUintToFloat:   out.debug << "Convert uint to float";   break;
191     case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break;
192     case EOpConvBoolToFloat:   out.debug << "Convert bool to float";   break;
193     case EOpConvUintToInt:     out.debug << "Convert uint to int";     break;
194     case EOpConvFloatToInt:    out.debug << "Convert float to int";    break;
195     case EOpConvDoubleToInt:   out.debug << "Convert double to int";   break;
196     case EOpConvBoolToInt:     out.debug << "Convert bool to int";     break;
197     case EOpConvIntToUint:     out.debug << "Convert int to uint";     break;
198     case EOpConvFloatToUint:   out.debug << "Convert float to uint";   break;
199     case EOpConvDoubleToUint:  out.debug << "Convert double to uint";  break;
200     case EOpConvBoolToUint:    out.debug << "Convert bool to uint";    break;
201     case EOpConvIntToDouble:   out.debug << "Convert int to double";   break;
202     case EOpConvUintToDouble:  out.debug << "Convert uint to double";  break;
203     case EOpConvFloatToDouble: out.debug << "Convert float to double"; break;
204     case EOpConvBoolToDouble:  out.debug << "Convert bool to double";  break;
205
206     case EOpRadians:        out.debug << "radians";              break;
207     case EOpDegrees:        out.debug << "degrees";              break;
208     case EOpSin:            out.debug << "sine";                 break;
209     case EOpCos:            out.debug << "cosine";               break;
210     case EOpTan:            out.debug << "tangent";              break;
211     case EOpAsin:           out.debug << "arc sine";             break;
212     case EOpAcos:           out.debug << "arc cosine";           break;
213     case EOpAtan:           out.debug << "arc tangent";          break;
214     case EOpSinh:           out.debug << "hyp. sine";            break;
215     case EOpCosh:           out.debug << "hyp. cosine";          break;
216     case EOpTanh:           out.debug << "hyp. tangent";         break;
217     case EOpAsinh:          out.debug << "arc hyp. sine";        break;
218     case EOpAcosh:          out.debug << "arc hyp. cosine";      break;
219     case EOpAtanh:          out.debug << "arc hyp. tangent";     break;
220
221     case EOpExp:            out.debug << "exp";                  break;
222     case EOpLog:            out.debug << "log";                  break;
223     case EOpExp2:           out.debug << "exp2";                 break;
224     case EOpLog2:           out.debug << "log2";                 break;
225     case EOpSqrt:           out.debug << "sqrt";                 break;
226     case EOpInverseSqrt:    out.debug << "inverse sqrt";         break;
227
228     case EOpAbs:            out.debug << "Absolute value";       break;
229     case EOpSign:           out.debug << "Sign";                 break;
230     case EOpFloor:          out.debug << "Floor";                break;
231     case EOpTrunc:          out.debug << "trunc";                break;
232     case EOpRound:          out.debug << "round";                break;
233     case EOpRoundEven:      out.debug << "roundEven";            break;
234     case EOpCeil:           out.debug << "Ceiling";              break;
235     case EOpFract:          out.debug << "Fraction";             break;
236
237     case EOpIsNan:          out.debug << "isnan";                break;
238     case EOpIsInf:          out.debug << "isinf";                break;
239
240     case EOpFloatBitsToInt: out.debug << "floatBitsToInt";       break;
241     case EOpFloatBitsToUint:out.debug << "floatBitsToUint";      break;
242     case EOpIntBitsToFloat: out.debug << "intBitsToFloat";       break;
243     case EOpUintBitsToFloat:out.debug << "uintBitsToFloat";      break;
244     case EOpPackSnorm2x16:  out.debug << "packSnorm2x16";        break;
245     case EOpUnpackSnorm2x16:out.debug << "unpackSnorm2x16";      break;
246     case EOpPackUnorm2x16:  out.debug << "packUnorm2x16";        break;
247     case EOpUnpackUnorm2x16:out.debug << "unpackUnorm2x16";      break;
248     case EOpPackHalf2x16:   out.debug << "packHalf2x16";         break;
249     case EOpUnpackHalf2x16: out.debug << "unpackHalf2x16";       break;
250
251     case EOpLength:         out.debug << "length";               break;
252     case EOpNormalize:      out.debug << "normalize";            break;
253     case EOpDPdx:           out.debug << "dPdx";                 break;
254     case EOpDPdy:           out.debug << "dPdy";                 break;
255     case EOpFwidth:         out.debug << "fwidth";               break;
256     case EOpDPdxFine:       out.debug << "dPdxFine";             break;
257     case EOpDPdyFine:       out.debug << "dPdyFine";             break;
258     case EOpFwidthFine:     out.debug << "fwidthFine";           break;
259     case EOpDPdxCoarse:     out.debug << "dPdxCoarse";           break;
260     case EOpDPdyCoarse:     out.debug << "dPdyCoarse";           break;
261     case EOpFwidthCoarse:   out.debug << "fwidthCoarse";         break;
262     case EOpDeterminant:    out.debug << "determinant";          break;
263     case EOpMatrixInverse:  out.debug << "inverse";              break;
264     case EOpTranspose:      out.debug << "transpose";            break;
265
266     case EOpAny:            out.debug << "any";                  break;
267     case EOpAll:            out.debug << "all";                  break;
268
269     case EOpArrayLength:    out.debug << "array length";         break;
270
271     case EOpEmitStreamVertex:   out.debug << "EmitStreamVertex";   break;
272     case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break;
273
274     default: out.debug.message(EPrefixError, "Bad unary op");
275     }
276
277     out.debug << " (" << node->getCompleteString() << ")";
278
279     out.debug << "\n";
280
281     return true;
282 }
283
284 bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
285 {
286     TInfoSink& out = infoSink;
287
288     if (node->getOp() == EOpNull) {
289         out.debug.message(EPrefixError, "node is still EOpNull!");
290         return true;
291     }
292
293     OutputTreeText(out, node, depth);
294
295     switch (node->getOp()) {
296     case EOpSequence:      out.debug << "Sequence\n";       return true;
297     case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true;
298     case EOpComma:         out.debug << "Comma";            break;
299     case EOpFunction:      out.debug << "Function Definition: " << node->getName(); break;
300     case EOpFunctionCall:  out.debug << "Function Call: "       << node->getName(); break;
301     case EOpParameters:    out.debug << "Function Parameters: ";                    break;
302
303     case EOpConstructFloat: out.debug << "Construct float"; break;
304     case EOpConstructDouble:out.debug << "Construct double"; break;
305     case EOpConstructVec2:  out.debug << "Construct vec2";  break;
306     case EOpConstructVec3:  out.debug << "Construct vec3";  break;
307     case EOpConstructVec4:  out.debug << "Construct vec4";  break;
308     case EOpConstructBool:  out.debug << "Construct bool";  break;
309     case EOpConstructBVec2: out.debug << "Construct bvec2"; break;
310     case EOpConstructBVec3: out.debug << "Construct bvec3"; break;
311     case EOpConstructBVec4: out.debug << "Construct bvec4"; break;
312     case EOpConstructInt:   out.debug << "Construct int";   break;
313     case EOpConstructIVec2: out.debug << "Construct ivec2"; break;
314     case EOpConstructIVec3: out.debug << "Construct ivec3"; break;
315     case EOpConstructIVec4: out.debug << "Construct ivec4"; break;
316     case EOpConstructUint:    out.debug << "Construct uint";    break;
317     case EOpConstructUVec2:   out.debug << "Construct uvec2";   break;
318     case EOpConstructUVec3:   out.debug << "Construct uvec3";   break;
319     case EOpConstructUVec4:   out.debug << "Construct uvec4";   break;
320     case EOpConstructMat2x2:  out.debug << "Construct mat2";    break;
321     case EOpConstructMat2x3:  out.debug << "Construct mat2x3";  break;
322     case EOpConstructMat2x4:  out.debug << "Construct mat2x4";  break;
323     case EOpConstructMat3x2:  out.debug << "Construct mat3x2";  break;
324     case EOpConstructMat3x3:  out.debug << "Construct mat3";    break;
325     case EOpConstructMat3x4:  out.debug << "Construct mat3x4";  break;
326     case EOpConstructMat4x2:  out.debug << "Construct mat4x2";  break;
327     case EOpConstructMat4x3:  out.debug << "Construct mat4x3";  break;
328     case EOpConstructMat4x4:  out.debug << "Construct mat4";    break;
329     case EOpConstructDMat2x2: out.debug << "Construct dmat2";   break;
330     case EOpConstructDMat2x3: out.debug << "Construct dmat2x3"; break;
331     case EOpConstructDMat2x4: out.debug << "Construct dmat2x4"; break;
332     case EOpConstructDMat3x2: out.debug << "Construct dmat3x2"; break;
333     case EOpConstructDMat3x3: out.debug << "Construct dmat3";   break;
334     case EOpConstructDMat3x4: out.debug << "Construct dmat3x4"; break;
335     case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break;
336     case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
337     case EOpConstructDMat4x4: out.debug << "Construct dmat4";  break;
338     case EOpConstructStruct:  out.debug << "Construct structure";  break;
339
340     case EOpLessThan:         out.debug << "Compare Less Than";             break;
341     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
342     case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
343     case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
344     case EOpVectorEqual:      out.debug << "Equal";                         break;
345     case EOpVectorNotEqual:   out.debug << "NotEqual";                      break;
346
347     case EOpMod:           out.debug << "mod";         break;
348     case EOpModf:          out.debug << "modf";        break;
349     case EOpPow:           out.debug << "pow";         break;
350
351     case EOpAtan:          out.debug << "arc tangent"; break;
352
353     case EOpMin:           out.debug << "min";         break;
354     case EOpMax:           out.debug << "max";         break;
355     case EOpClamp:         out.debug << "clamp";       break;
356     case EOpMix:           out.debug << "mix";         break;
357     case EOpStep:          out.debug << "step";        break;
358     case EOpSmoothStep:    out.debug << "smoothstep";  break;
359
360     case EOpDistance:      out.debug << "distance";                break;
361     case EOpDot:           out.debug << "dot-product";             break;
362     case EOpCross:         out.debug << "cross-product";           break;
363     case EOpFaceForward:   out.debug << "face-forward";            break;
364     case EOpReflect:       out.debug << "reflect";                 break;
365     case EOpRefract:       out.debug << "refract";                 break;
366     case EOpMul:           out.debug << "component-wise multiply"; break;
367     case EOpOuterProduct:  out.debug << "outer product";           break;
368
369     case EOpEmitVertex:    out.debug << "EmitVertex";              break;
370     case EOpEndPrimitive:  out.debug << "EndPrimitive";            break;
371
372     case EOpBarrier:                    out.debug << "Barrier";                    break;
373     case EOpMemoryBarrier:              out.debug << "MemoryBarrier";              break;
374     case EOpMemoryBarrierAtomicCounter: out.debug << "MemoryBarrierAtomicCounter"; break;
375     case EOpMemoryBarrierBuffer:        out.debug << "MemoryBarrierBuffer";        break;
376     case EOpMemoryBarrierImage:         out.debug << "MemoryBarrierImage";         break;
377     case EOpMemoryBarrierShared:        out.debug << "MemoryBarrierShared";        break;
378     case EOpGroupMemoryBarrier:         out.debug << "GroupMemoryBarrier";         break;
379
380     default: out.debug.message(EPrefixError, "Bad aggregation op");
381     }
382
383     if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
384         out.debug << " (" << node->getCompleteString() << ")";
385
386     out.debug << "\n";
387
388     return true;
389 }
390
391 bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
392 {
393     TInfoSink& out = infoSink;
394
395     OutputTreeText(out, node, depth);
396
397     out.debug << "Test condition and select";
398     out.debug << " (" << node->getCompleteString() << ")\n";
399
400     ++depth;
401
402     OutputTreeText(out, node, depth);
403     out.debug << "Condition\n";
404     node->getCondition()->traverse(this);
405
406     OutputTreeText(out, node, depth);
407     if (node->getTrueBlock()) {
408         out.debug << "true case\n";
409         node->getTrueBlock()->traverse(this);
410     } else
411         out.debug << "true case is null\n";
412
413     if (node->getFalseBlock()) {
414         OutputTreeText(out, node, depth);
415         out.debug << "false case\n";
416         node->getFalseBlock()->traverse(this);
417     }
418
419     --depth;
420
421     return false;
422 }
423
424 void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth)
425 {
426     int size = node->getType().computeNumComponents();
427
428     for (int i = 0; i < size; i++) {
429         OutputTreeText(out, node, depth);
430         switch (constUnion[i].getType()) {
431         case EbtBool:
432             if (constUnion[i].getBConst())
433                 out.debug << "true";
434             else
435                 out.debug << "false";
436
437             out.debug << " (" << "const bool" << ")";
438
439             out.debug << "\n";
440             break;
441         case EbtFloat:
442         case EbtDouble:
443             {
444                 const int maxSize = 300;
445                 char buf[maxSize];
446                 snprintf(buf, maxSize, "%f", constUnion[i].getDConst());
447
448                 out.debug << buf << "\n";
449             }
450             break;
451         case EbtInt:
452             {
453                 const int maxSize = 300;
454                 char buf[maxSize];
455                 snprintf(buf, maxSize, "%d (%s)", constUnion[i].getIConst(), "const int");
456
457                 out.debug << buf << "\n";
458             }
459             break;
460         case EbtUint:
461             {
462                 const int maxSize = 300;
463                 char buf[maxSize];
464                 snprintf(buf, maxSize, "%u (%s)", constUnion[i].getUConst(), "const uint");
465
466                 out.debug << buf << "\n";
467             }
468             break;
469         default:
470             out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc());
471             break;
472         }
473     }
474 }
475
476 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
477 {
478     OutputTreeText(infoSink, node, depth);
479     infoSink.debug << "Constant:\n";
480
481     OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
482 }
483
484 void TOutputTraverser::visitSymbol(TIntermSymbol* node)
485 {
486     OutputTreeText(infoSink, node, depth);
487
488     infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n";
489
490     if (! node->getConstArray().empty())
491         OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
492 }
493
494 bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
495 {
496     TInfoSink& out = infoSink;
497
498     OutputTreeText(out, node, depth);
499
500     out.debug << "Loop with condition ";
501     if (! node->testFirst())
502         out.debug << "not ";
503     out.debug << "tested first\n";
504
505     ++depth;
506
507     OutputTreeText(infoSink, node, depth);
508     if (node->getTest()) {
509         out.debug << "Loop Condition\n";
510         node->getTest()->traverse(this);
511     } else
512         out.debug << "No loop condition\n";
513
514     OutputTreeText(infoSink, node, depth);
515     if (node->getBody()) {
516         out.debug << "Loop Body\n";
517         node->getBody()->traverse(this);
518     } else
519         out.debug << "No loop body\n";
520
521     if (node->getTerminal()) {
522         OutputTreeText(infoSink, node, depth);
523         out.debug << "Loop Terminal Expression\n";
524         node->getTerminal()->traverse(this);
525     }
526
527     --depth;
528
529     return false;
530 }
531
532 bool TOutputTraverser::visitBranch(TVisit /* visit*/, TIntermBranch* node)
533 {
534     TInfoSink& out = infoSink;
535
536     OutputTreeText(out, node, depth);
537
538     switch (node->getFlowOp()) {
539     case EOpKill:      out.debug << "Branch: Kill";           break;
540     case EOpBreak:     out.debug << "Branch: Break";          break;
541     case EOpContinue:  out.debug << "Branch: Continue";       break;
542     case EOpReturn:    out.debug << "Branch: Return";         break;
543     case EOpCase:      out.debug << "case: ";                 break;
544     case EOpDefault:   out.debug << "default: ";              break;
545     default:               out.debug << "Branch: Unknown Branch"; break;
546     }
547
548     if (node->getExpression()) {
549         out.debug << " with expression\n";
550         ++depth;
551         node->getExpression()->traverse(this);
552         --depth;
553     } else
554         out.debug << "\n";
555
556     return false;
557 }
558
559 bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
560 {
561     TInfoSink& out = infoSink;
562
563     OutputTreeText(out, node, depth);
564     out.debug << "switch\n";
565
566     OutputTreeText(out, node, depth);
567     out.debug << "condition\n";
568     ++depth;
569     node->getCondition()->traverse(this);
570
571     --depth;
572     OutputTreeText(out, node, depth);
573     out.debug << "body\n";
574     ++depth;
575     node->getBody()->traverse(this);
576
577     --depth;
578
579     return false;
580 }
581
582 //
583 // This function is the one to call externally to start the traversal.
584 // Individual functions can be initialized to 0 to skip processing of that
585 // type of node.  It's children will still be processed.
586 //
587 void TIntermediate::output(TInfoSink& infoSink, bool tree)
588 {
589     infoSink.debug << "Shader version: " << version << "\n";
590     if (requestedExtensions.size() > 0) {
591         for (std::set<std::string>::const_iterator extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt)
592             infoSink.debug << "Requested " << *extIt << "\n";
593     }
594
595     if (xfbMode)
596         infoSink.debug << "in xfb mode\n";
597
598     switch (language) {
599     case EShLangVertex:
600         break;
601
602     case EShLangTessControl:
603         infoSink.debug << "vertices = " << vertices << "\n";
604         break;
605
606     case EShLangTessEvaluation:
607         infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
608         infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n";
609         infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n";
610         if (pointMode)
611             infoSink.debug << "using point mode\n";
612         break;
613
614     case EShLangGeometry:
615         infoSink.debug << "invocations = " << invocations << "\n";
616         infoSink.debug << "max_vertices = " << vertices << "\n";
617         infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
618         infoSink.debug << "output primitive = " << TQualifier::getGeometryString(outputPrimitive) << "\n";
619         break;
620
621     case EShLangFragment:
622         if (pixelCenterInteger)
623             infoSink.debug << "gl_FragCoord pixel center is integer\n";
624         if (originUpperLeft)
625             infoSink.debug << "gl_FragCoord origin is upper left\n";
626         if (earlyFragmentTests)
627             infoSink.debug << "using early_fragment_tests\n";
628         if (depthLayout != EldNone)
629             infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
630         break;
631
632     case EShLangCompute:
633         infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n";
634         break;
635
636     default:
637         break;
638     }
639
640     if (treeRoot == 0 || ! tree)
641         return;
642
643     TOutputTraverser it(infoSink);
644
645     treeRoot->traverse(&it);
646 }
647
648 } // end namespace glslang