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