• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //
22 class TOutputTraverser : public TIntermTraverser {
23 public:
TOutputTraverser(TInfoSinkBase & i)24     TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
25     TInfoSinkBase& sink;
26 
27 protected:
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 
getCompleteString() const38 TString TType::getCompleteString() const
39 {
40     TStringStream stream;
41 
42     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
43         stream << getQualifierString() << " " << getPrecisionString() << " ";
44     if (array)
45         stream << "array 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 
OutputTreeText(TInfoSinkBase & sink,TIntermNode * node,const int depth)59 void 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 
visitSymbol(TIntermSymbol * node)78 void TOutputTraverser::visitSymbol(TIntermSymbol* node)
79 {
80     OutputTreeText(sink, node, depth);
81 
82     sink << "'" << node->getSymbol() << "' ";
83     sink << "(" << node->getCompleteString() << ")\n";
84 }
85 
visitBinary(Visit visit,TIntermBinary * node)86 bool 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 
visitUnary(Visit visit,TIntermUnary * node)138 bool 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: out.message(EPrefixError, "Bad unary op");
193     }
194 
195     out << " (" << node->getCompleteString() << ")";
196 
197     out << "\n";
198 
199     return true;
200 }
201 
visitAggregate(Visit visit,TIntermAggregate * node)202 bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
203 {
204     TInfoSinkBase& out = sink;
205 
206     if (node->getOp() == EOpNull) {
207         out.message(EPrefixError, "node is still EOpNull!");
208         return true;
209     }
210 
211     OutputTreeText(out, node, depth);
212 
213     switch (node->getOp()) {
214         case EOpSequence:      out << "Sequence\n"; return true;
215         case EOpComma:         out << "Comma\n"; return true;
216         case EOpFunction:      out << "Function Definition: " << node->getName(); break;
217         case EOpFunctionCall:  out << "Function Call: " << node->getName(); break;
218         case EOpParameters:    out << "Function Parameters: ";              break;
219 
220         case EOpConstructFloat: out << "Construct float"; break;
221         case EOpConstructVec2:  out << "Construct vec2";  break;
222         case EOpConstructVec3:  out << "Construct vec3";  break;
223         case EOpConstructVec4:  out << "Construct vec4";  break;
224         case EOpConstructBool:  out << "Construct bool";  break;
225         case EOpConstructBVec2: out << "Construct bvec2"; break;
226         case EOpConstructBVec3: out << "Construct bvec3"; break;
227         case EOpConstructBVec4: out << "Construct bvec4"; break;
228         case EOpConstructInt:   out << "Construct int";   break;
229         case EOpConstructIVec2: out << "Construct ivec2"; break;
230         case EOpConstructIVec3: out << "Construct ivec3"; break;
231         case EOpConstructIVec4: out << "Construct ivec4"; break;
232         case EOpConstructMat2:  out << "Construct mat2";  break;
233         case EOpConstructMat3:  out << "Construct mat3";  break;
234         case EOpConstructMat4:  out << "Construct mat4";  break;
235         case EOpConstructStruct:  out << "Construct structure";  break;
236 
237         case EOpLessThan:         out << "Compare Less Than";             break;
238         case EOpGreaterThan:      out << "Compare Greater Than";          break;
239         case EOpLessThanEqual:    out << "Compare Less Than or Equal";    break;
240         case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
241         case EOpVectorEqual:      out << "Equal";                         break;
242         case EOpVectorNotEqual:   out << "NotEqual";                      break;
243 
244         case EOpMod:           out << "mod";         break;
245         case EOpPow:           out << "pow";         break;
246 
247         case EOpAtan:          out << "arc tangent"; break;
248 
249         case EOpMin:           out << "min";         break;
250         case EOpMax:           out << "max";         break;
251         case EOpClamp:         out << "clamp";       break;
252         case EOpMix:           out << "mix";         break;
253         case EOpStep:          out << "step";        break;
254         case EOpSmoothStep:    out << "smoothstep";  break;
255 
256         case EOpDistance:      out << "distance";                break;
257         case EOpDot:           out << "dot-product";             break;
258         case EOpCross:         out << "cross-product";           break;
259         case EOpFaceForward:   out << "face-forward";            break;
260         case EOpReflect:       out << "reflect";                 break;
261         case EOpRefract:       out << "refract";                 break;
262         case EOpMul:           out << "component-wise multiply"; break;
263 
264         default: out.message(EPrefixError, "Bad aggregation op");
265     }
266 
267     if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
268         out << " (" << node->getCompleteString() << ")";
269 
270     out << "\n";
271 
272     return true;
273 }
274 
visitSelection(Visit visit,TIntermSelection * node)275 bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
276 {
277     TInfoSinkBase& out = sink;
278 
279     OutputTreeText(out, node, depth);
280 
281     out << "Test condition and select";
282     out << " (" << node->getCompleteString() << ")\n";
283 
284     ++depth;
285 
286     OutputTreeText(sink, node, depth);
287     out << "Condition\n";
288     node->getCondition()->traverse(this);
289 
290     OutputTreeText(sink, node, depth);
291     if (node->getTrueBlock()) {
292         out << "true case\n";
293         node->getTrueBlock()->traverse(this);
294     } else
295         out << "true case is null\n";
296 
297     if (node->getFalseBlock()) {
298         OutputTreeText(sink, node, depth);
299         out << "false case\n";
300         node->getFalseBlock()->traverse(this);
301     }
302 
303     --depth;
304 
305     return false;
306 }
307 
visitConstantUnion(TIntermConstantUnion * node)308 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
309 {
310     TInfoSinkBase& out = sink;
311 
312     int size = node->getType().getObjectSize();
313 
314     for (int i = 0; i < size; i++) {
315         OutputTreeText(out, node, depth);
316         switch (node->getUnionArrayPointer()[i].getType()) {
317             case EbtBool:
318                 if (node->getUnionArrayPointer()[i].getBConst())
319                     out << "true";
320                 else
321                     out << "false";
322 
323                 out << " (" << "const bool" << ")";
324                 out << "\n";
325                 break;
326             case EbtFloat:
327                 out << node->getUnionArrayPointer()[i].getFConst();
328                 out << " (const float)\n";
329                 break;
330             case EbtInt:
331                 out << node->getUnionArrayPointer()[i].getIConst();
332                 out << " (const int)\n";
333                 break;
334             default:
335                 out.message(EPrefixInternalError, "Unknown constant", node->getLine());
336                 break;
337         }
338     }
339 }
340 
visitLoop(Visit visit,TIntermLoop * node)341 bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
342 {
343     TInfoSinkBase& out = sink;
344 
345     OutputTreeText(out, node, depth);
346 
347     out << "Loop with condition ";
348     if (node->getType() == ELoopDoWhile)
349         out << "not ";
350     out << "tested first\n";
351 
352     ++depth;
353 
354     OutputTreeText(sink, node, depth);
355     if (node->getCondition()) {
356         out << "Loop Condition\n";
357         node->getCondition()->traverse(this);
358     } else
359         out << "No loop condition\n";
360 
361     OutputTreeText(sink, node, depth);
362     if (node->getBody()) {
363         out << "Loop Body\n";
364         node->getBody()->traverse(this);
365     } else
366         out << "No loop body\n";
367 
368     if (node->getExpression()) {
369         OutputTreeText(sink, node, depth);
370         out << "Loop Terminal Expression\n";
371         node->getExpression()->traverse(this);
372     }
373 
374     --depth;
375 
376     return false;
377 }
378 
visitBranch(Visit visit,TIntermBranch * node)379 bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
380 {
381     TInfoSinkBase& out = sink;
382 
383     OutputTreeText(out, node, depth);
384 
385     switch (node->getFlowOp()) {
386         case EOpKill:      out << "Branch: Kill";           break;
387         case EOpBreak:     out << "Branch: Break";          break;
388         case EOpContinue:  out << "Branch: Continue";       break;
389         case EOpReturn:    out << "Branch: Return";         break;
390         default:           out << "Branch: Unknown Branch"; break;
391     }
392 
393     if (node->getExpression()) {
394         out << " with expression\n";
395         ++depth;
396         node->getExpression()->traverse(this);
397         --depth;
398     } else
399         out << "\n";
400 
401     return false;
402 }
403 
404 //
405 // This function is the one to call externally to start the traversal.
406 // Individual functions can be initialized to 0 to skip processing of that
407 // type of node.  It's children will still be processed.
408 //
outputTree(TIntermNode * root)409 void TIntermediate::outputTree(TIntermNode* root)
410 {
411     if (root == 0)
412         return;
413 
414     TOutputTraverser it(infoSink.info);
415 
416     root->traverse(&it);
417 }
418