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