1//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/localintermediate.h"
8
9//
10// Two purposes:
11// 1.  Show an example of how to iterate tree.  Functions can
12//     also directly call Traverse() on children themselves to
13//     have finer grained control over the process than shown here.
14//     See the last function for how to get started.
15// 2.  Print out a text based description of the tree.
16//
17
18//
19// Use this class to carry along data from node to node in
20// the traversal
21//
22class TOutputTraverser : public TIntermTraverser {
23public:
24    TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
25    TInfoSinkBase& sink;
26
27protected:
28    void visitSymbol(TIntermSymbol*);
29    void visitConstantUnion(TIntermConstantUnion*);
30    bool visitBinary(Visit visit, TIntermBinary*);
31    bool visitUnary(Visit visit, TIntermUnary*);
32    bool visitSelection(Visit visit, TIntermSelection*);
33    bool visitAggregate(Visit visit, TIntermAggregate*);
34    bool visitLoop(Visit visit, TIntermLoop*);
35    bool visitBranch(Visit visit, TIntermBranch*);
36};
37
38TString TType::getCompleteString() const
39{
40    TStringStream stream;
41
42    if (qualifier != EvqTemporary && qualifier != EvqGlobal)
43        stream << getQualifierString() << " " << getPrecisionString() << " ";
44    if (array)
45        stream << "array[" << getArraySize() << "] of ";
46    if (matrix)
47        stream << size << "X" << size << " matrix of ";
48    else if (size > 1)
49        stream << size << "-component vector of ";
50
51    stream << getBasicString();
52    return stream.str();
53}
54
55//
56// Helper functions for printing, not part of traversing.
57//
58
59void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
60{
61    int i;
62
63    sink.location(node->getLine());
64
65    for (i = 0; i < depth; ++i)
66        sink << "  ";
67}
68
69//
70// The rest of the file are the traversal functions.  The last one
71// is the one that starts the traversal.
72//
73// Return true from interior nodes to have the external traversal
74// continue on to children.  If you process children yourself,
75// return false.
76//
77
78void TOutputTraverser::visitSymbol(TIntermSymbol* node)
79{
80    OutputTreeText(sink, node, depth);
81
82    sink << "'" << node->getSymbol() << "' ";
83    sink << "(" << node->getCompleteString() << ")\n";
84}
85
86bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
87{
88    TInfoSinkBase& out = sink;
89
90    OutputTreeText(out, node, depth);
91
92    switch (node->getOp()) {
93        case EOpAssign:                   out << "move second child to first child";           break;
94        case EOpInitialize:               out << "initialize first child with second child";   break;
95        case EOpAddAssign:                out << "add second child into first child";          break;
96        case EOpSubAssign:                out << "subtract second child into first child";     break;
97        case EOpMulAssign:                out << "multiply second child into first child";     break;
98        case EOpVectorTimesMatrixAssign:  out << "matrix mult second child into first child";  break;
99        case EOpVectorTimesScalarAssign:  out << "vector scale second child into first child"; break;
100        case EOpMatrixTimesScalarAssign:  out << "matrix scale second child into first child"; break;
101        case EOpMatrixTimesMatrixAssign:  out << "matrix mult second child into first child"; break;
102        case EOpDivAssign:                out << "divide second child into first child";       break;
103        case EOpIndexDirect:   out << "direct index";   break;
104        case EOpIndexIndirect: out << "indirect index"; break;
105        case EOpIndexDirectStruct:   out << "direct index for structure";   break;
106        case EOpVectorSwizzle: out << "vector swizzle"; break;
107
108        case EOpAdd:    out << "add";                     break;
109        case EOpSub:    out << "subtract";                break;
110        case EOpMul:    out << "component-wise multiply"; break;
111        case EOpDiv:    out << "divide";                  break;
112        case EOpEqual:            out << "Compare Equal";                 break;
113        case EOpNotEqual:         out << "Compare Not Equal";             break;
114        case EOpLessThan:         out << "Compare Less Than";             break;
115        case EOpGreaterThan:      out << "Compare Greater Than";          break;
116        case EOpLessThanEqual:    out << "Compare Less Than or Equal";    break;
117        case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
118
119        case EOpVectorTimesScalar: out << "vector-scale";          break;
120        case EOpVectorTimesMatrix: out << "vector-times-matrix";   break;
121        case EOpMatrixTimesVector: out << "matrix-times-vector";   break;
122        case EOpMatrixTimesScalar: out << "matrix-scale";          break;
123        case EOpMatrixTimesMatrix: out << "matrix-multiply";       break;
124
125        case EOpLogicalOr:  out << "logical-or";   break;
126        case EOpLogicalXor: out << "logical-xor"; break;
127        case EOpLogicalAnd: out << "logical-and"; break;
128        default: out << "<unknown op>";
129    }
130
131    out << " (" << node->getCompleteString() << ")";
132
133    out << "\n";
134
135    return true;
136}
137
138bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
139{
140    TInfoSinkBase& out = sink;
141
142    OutputTreeText(out, node, depth);
143
144    switch (node->getOp()) {
145        case EOpNegative:       out << "Negate value";         break;
146        case EOpVectorLogicalNot:
147        case EOpLogicalNot:     out << "Negate conditional";   break;
148
149        case EOpPostIncrement:  out << "Post-Increment";       break;
150        case EOpPostDecrement:  out << "Post-Decrement";       break;
151        case EOpPreIncrement:   out << "Pre-Increment";        break;
152        case EOpPreDecrement:   out << "Pre-Decrement";        break;
153
154        case EOpConvIntToBool:  out << "Convert int to bool";  break;
155        case EOpConvFloatToBool:out << "Convert float to bool";break;
156        case EOpConvBoolToFloat:out << "Convert bool to float";break;
157        case EOpConvIntToFloat: out << "Convert int to float"; break;
158        case EOpConvFloatToInt: out << "Convert float to int"; break;
159        case EOpConvBoolToInt:  out << "Convert bool to int";  break;
160
161        case EOpRadians:        out << "radians";              break;
162        case EOpDegrees:        out << "degrees";              break;
163        case EOpSin:            out << "sine";                 break;
164        case EOpCos:            out << "cosine";               break;
165        case EOpTan:            out << "tangent";              break;
166        case EOpAsin:           out << "arc sine";             break;
167        case EOpAcos:           out << "arc cosine";           break;
168        case EOpAtan:           out << "arc tangent";          break;
169
170        case EOpExp:            out << "exp";                  break;
171        case EOpLog:            out << "log";                  break;
172        case EOpExp2:           out << "exp2";                 break;
173        case EOpLog2:           out << "log2";                 break;
174        case EOpSqrt:           out << "sqrt";                 break;
175        case EOpInverseSqrt:    out << "inverse sqrt";         break;
176
177        case EOpAbs:            out << "Absolute value";       break;
178        case EOpSign:           out << "Sign";                 break;
179        case EOpFloor:          out << "Floor";                break;
180        case EOpCeil:           out << "Ceiling";              break;
181        case EOpFract:          out << "Fraction";             break;
182
183        case EOpLength:         out << "length";               break;
184        case EOpNormalize:      out << "normalize";            break;
185            //	case EOpDPdx:           out << "dPdx";                 break;
186            //	case EOpDPdy:           out << "dPdy";                 break;
187            //	case EOpFwidth:         out << "fwidth";               break;
188
189        case EOpAny:            out << "any";                  break;
190        case EOpAll:            out << "all";                  break;
191
192        default:
193            out.prefix(EPrefixError);
194            out << "Bad unary op";
195    }
196
197    out << " (" << node->getCompleteString() << ")";
198
199    out << "\n";
200
201    return true;
202}
203
204bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
205{
206    TInfoSinkBase& out = sink;
207
208    if (node->getOp() == EOpNull) {
209        out.prefix(EPrefixError);
210        out << "node is still EOpNull!";
211        return true;
212    }
213
214    OutputTreeText(out, node, depth);
215
216    switch (node->getOp()) {
217        case EOpSequence:      out << "Sequence\n"; return true;
218        case EOpComma:         out << "Comma\n"; return true;
219        case EOpFunction:      out << "Function Definition: " << node->getName(); break;
220        case EOpFunctionCall:  out << "Function Call: " << node->getName(); break;
221        case EOpParameters:    out << "Function Parameters: ";              break;
222
223        case EOpConstructFloat: out << "Construct float"; break;
224        case EOpConstructVec2:  out << "Construct vec2";  break;
225        case EOpConstructVec3:  out << "Construct vec3";  break;
226        case EOpConstructVec4:  out << "Construct vec4";  break;
227        case EOpConstructBool:  out << "Construct bool";  break;
228        case EOpConstructBVec2: out << "Construct bvec2"; break;
229        case EOpConstructBVec3: out << "Construct bvec3"; break;
230        case EOpConstructBVec4: out << "Construct bvec4"; break;
231        case EOpConstructInt:   out << "Construct int";   break;
232        case EOpConstructIVec2: out << "Construct ivec2"; break;
233        case EOpConstructIVec3: out << "Construct ivec3"; break;
234        case EOpConstructIVec4: out << "Construct ivec4"; break;
235        case EOpConstructMat2:  out << "Construct mat2";  break;
236        case EOpConstructMat3:  out << "Construct mat3";  break;
237        case EOpConstructMat4:  out << "Construct mat4";  break;
238        case EOpConstructStruct:  out << "Construct structure";  break;
239
240        case EOpLessThan:         out << "Compare Less Than";             break;
241        case EOpGreaterThan:      out << "Compare Greater Than";          break;
242        case EOpLessThanEqual:    out << "Compare Less Than or Equal";    break;
243        case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
244        case EOpVectorEqual:      out << "Equal";                         break;
245        case EOpVectorNotEqual:   out << "NotEqual";                      break;
246
247        case EOpMod:           out << "mod";         break;
248        case EOpPow:           out << "pow";         break;
249
250        case EOpAtan:          out << "arc tangent"; break;
251
252        case EOpMin:           out << "min";         break;
253        case EOpMax:           out << "max";         break;
254        case EOpClamp:         out << "clamp";       break;
255        case EOpMix:           out << "mix";         break;
256        case EOpStep:          out << "step";        break;
257        case EOpSmoothStep:    out << "smoothstep";  break;
258
259        case EOpDistance:      out << "distance";                break;
260        case EOpDot:           out << "dot-product";             break;
261        case EOpCross:         out << "cross-product";           break;
262        case EOpFaceForward:   out << "face-forward";            break;
263        case EOpReflect:       out << "reflect";                 break;
264        case EOpRefract:       out << "refract";                 break;
265        case EOpMul:           out << "component-wise multiply"; break;
266
267        case EOpDeclaration:   out << "Declaration: ";   break;
268
269        default:
270            out.prefix(EPrefixError);
271            out << "Bad aggregation op";
272    }
273
274    if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
275        out << " (" << node->getCompleteString() << ")";
276
277    out << "\n";
278
279    return true;
280}
281
282bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
283{
284    TInfoSinkBase& out = sink;
285
286    OutputTreeText(out, node, depth);
287
288    out << "Test condition and select";
289    out << " (" << node->getCompleteString() << ")\n";
290
291    ++depth;
292
293    OutputTreeText(sink, node, depth);
294    out << "Condition\n";
295    node->getCondition()->traverse(this);
296
297    OutputTreeText(sink, node, depth);
298    if (node->getTrueBlock()) {
299        out << "true case\n";
300        node->getTrueBlock()->traverse(this);
301    } else
302        out << "true case is null\n";
303
304    if (node->getFalseBlock()) {
305        OutputTreeText(sink, node, depth);
306        out << "false case\n";
307        node->getFalseBlock()->traverse(this);
308    }
309
310    --depth;
311
312    return false;
313}
314
315void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
316{
317    TInfoSinkBase& out = sink;
318
319    size_t size = node->getType().getObjectSize();
320
321    for (size_t i = 0; i < size; i++) {
322        OutputTreeText(out, node, depth);
323        switch (node->getUnionArrayPointer()[i].getType()) {
324            case EbtBool:
325                if (node->getUnionArrayPointer()[i].getBConst())
326                    out << "true";
327                else
328                    out << "false";
329
330                out << " (" << "const bool" << ")";
331                out << "\n";
332                break;
333            case EbtFloat:
334                out << node->getUnionArrayPointer()[i].getFConst();
335                out << " (const float)\n";
336                break;
337            case EbtInt:
338                out << node->getUnionArrayPointer()[i].getIConst();
339                out << " (const int)\n";
340                break;
341            default:
342                out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
343                break;
344        }
345    }
346}
347
348bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
349{
350    TInfoSinkBase& out = sink;
351
352    OutputTreeText(out, node, depth);
353
354    out << "Loop with condition ";
355    if (node->getType() == ELoopDoWhile)
356        out << "not ";
357    out << "tested first\n";
358
359    ++depth;
360
361    OutputTreeText(sink, node, depth);
362    if (node->getCondition()) {
363        out << "Loop Condition\n";
364        node->getCondition()->traverse(this);
365    } else
366        out << "No loop condition\n";
367
368    OutputTreeText(sink, node, depth);
369    if (node->getBody()) {
370        out << "Loop Body\n";
371        node->getBody()->traverse(this);
372    } else
373        out << "No loop body\n";
374
375    if (node->getExpression()) {
376        OutputTreeText(sink, node, depth);
377        out << "Loop Terminal Expression\n";
378        node->getExpression()->traverse(this);
379    }
380
381    --depth;
382
383    return false;
384}
385
386bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
387{
388    TInfoSinkBase& out = sink;
389
390    OutputTreeText(out, node, depth);
391
392    switch (node->getFlowOp()) {
393        case EOpKill:      out << "Branch: Kill";           break;
394        case EOpBreak:     out << "Branch: Break";          break;
395        case EOpContinue:  out << "Branch: Continue";       break;
396        case EOpReturn:    out << "Branch: Return";         break;
397        default:           out << "Branch: Unknown Branch"; break;
398    }
399
400    if (node->getExpression()) {
401        out << " with expression\n";
402        ++depth;
403        node->getExpression()->traverse(this);
404        --depth;
405    } else
406        out << "\n";
407
408    return false;
409}
410
411//
412// This function is the one to call externally to start the traversal.
413// Individual functions can be initialized to 0 to skip processing of that
414// type of node.  It's children will still be processed.
415//
416void TIntermediate::outputTree(TIntermNode* root)
417{
418    if (root == 0)
419        return;
420
421    TOutputTraverser it(infoSink.info);
422
423    root->traverse(&it);
424}
425