blob: 6e30b86af80660c692198a74c303535828900642 [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;
108 case EOpModAssign: out.debug << "mod second child into first child"; break;
109 case EOpAndAssign: out.debug << "and second child into first child"; break;
110 case EOpInclusiveOrAssign: out.debug << "or second child into first child"; break;
111 case EOpExclusiveOrAssign: out.debug << "exclusive or second child into first child"; break;
112 case EOpLeftShiftAssign: out.debug << "left shift second child into first child"; break;
113 case EOpRightShiftAssign: out.debug << "right shift second child into first child"; break;
114
115 case EOpIndexDirect: out.debug << "direct index"; break;
116 case EOpIndexIndirect: out.debug << "indirect index"; break;
117 case EOpIndexDirectStruct: out.debug << "direct index for structure"; break;
118 case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
119
120 case EOpAdd: out.debug << "add"; break;
121 case EOpSub: out.debug << "subtract"; break;
122 case EOpMul: out.debug << "component-wise multiply"; break;
123 case EOpDiv: out.debug << "divide"; break;
124 case EOpMod: out.debug << "mod"; break;
125 case EOpRightShift: out.debug << "right-shift"; break;
126 case EOpLeftShift: out.debug << "left-shift"; break;
127 case EOpAnd: out.debug << "bitwise and"; break;
128 case EOpInclusiveOr: out.debug << "inclusive-or"; break;
129 case EOpExclusiveOr: out.debug << "exclusive-or"; break;
130 case EOpEqual: out.debug << "Compare Equal"; break;
131 case EOpNotEqual: out.debug << "Compare Not Equal"; break;
132 case EOpLessThan: out.debug << "Compare Less Than"; break;
133 case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
134 case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break;
135 case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
136
137 case EOpVectorTimesScalar: out.debug << "vector-scale"; break;
138 case EOpVectorTimesMatrix: out.debug << "vector-times-matrix"; break;
139 case EOpMatrixTimesVector: out.debug << "matrix-times-vector"; break;
140 case EOpMatrixTimesScalar: out.debug << "matrix-scale"; break;
141 case EOpMatrixTimesMatrix: out.debug << "matrix-multiply"; break;
142
143 case EOpLogicalOr: out.debug << "logical-or"; break;
144 case EOpLogicalXor: out.debug << "logical-xor"; break;
145 case EOpLogicalAnd: out.debug << "logical-and"; break;
146 default: out.debug << "<unknown op>";
147 }
148
149 out.debug << " (" << node->getCompleteString() << ")";
150
151 out.debug << "\n";
152
153 return true;
154}
155
156bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
157{
158 TInfoSink& out = infoSink;
159
160 OutputTreeText(out, node, depth);
161
162 switch (node->getOp()) {
163 case EOpNegative: out.debug << "Negate value"; break;
164 case EOpVectorLogicalNot:
165 case EOpLogicalNot: out.debug << "Negate conditional"; break;
166 case EOpBitwiseNot: out.debug << "Bitwise not"; break;
167
168 case EOpPostIncrement: out.debug << "Post-Increment"; break;
169 case EOpPostDecrement: out.debug << "Post-Decrement"; break;
170 case EOpPreIncrement: out.debug << "Pre-Increment"; break;
171 case EOpPreDecrement: out.debug << "Pre-Decrement"; break;
172
173 case EOpConvIntToBool: out.debug << "Convert int to bool"; break;
174 case EOpConvFloatToBool:out.debug << "Convert float to bool";break;
175 case EOpConvBoolToFloat:out.debug << "Convert bool to float";break;
176 case EOpConvIntToFloat: out.debug << "Convert int to float"; break;
177 case EOpConvFloatToInt: out.debug << "Convert float to int"; break;
178 case EOpConvBoolToInt: out.debug << "Convert bool to int"; break;
179
180 case EOpRadians: out.debug << "radians"; break;
181 case EOpDegrees: out.debug << "degrees"; break;
182 case EOpSin: out.debug << "sine"; break;
183 case EOpCos: out.debug << "cosine"; break;
184 case EOpTan: out.debug << "tangent"; break;
185 case EOpAsin: out.debug << "arc sine"; break;
186 case EOpAcos: out.debug << "arc cosine"; break;
187 case EOpAtan: out.debug << "arc tangent"; break;
188
189 case EOpExp: out.debug << "exp"; break;
190 case EOpLog: out.debug << "log"; break;
191 case EOpExp2: out.debug << "exp2"; break;
192 case EOpLog2: out.debug << "log2"; break;
193 case EOpSqrt: out.debug << "sqrt"; break;
194 case EOpInverseSqrt: out.debug << "inverse sqrt"; break;
195
196 case EOpAbs: out.debug << "Absolute value"; break;
197 case EOpSign: out.debug << "Sign"; break;
198 case EOpFloor: out.debug << "Floor"; break;
199 case EOpCeil: out.debug << "Ceiling"; break;
200 case EOpFract: out.debug << "Fraction"; break;
201
202 case EOpLength: out.debug << "length"; break;
203 case EOpNormalize: out.debug << "normalize"; break;
204// case EOpDPdx: out.debug << "dPdx"; break;
205// case EOpDPdy: out.debug << "dPdy"; break;
206// case EOpFwidth: out.debug << "fwidth"; break;
207
208 case EOpAny: out.debug << "any"; break;
209 case EOpAll: out.debug << "all"; break;
210
211 default: out.debug.message(EPrefixError, "Bad unary op");
212 }
213
214 out.debug << " (" << node->getCompleteString() << ")";
215
216 out.debug << "\n";
217
218 return true;
219}
220
221bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
222{
223 TInfoSink& out = infoSink;
224
225 if (node->getOp() == EOpNull) {
226 out.debug.message(EPrefixError, "node is still EOpNull!");
227 return true;
228 }
229
230 OutputTreeText(out, node, depth);
231
232 switch (node->getOp()) {
233 case EOpSequence: out.debug << "Sequence\n"; return true;
234 case EOpComma: out.debug << "Comma\n"; return true;
235 case EOpFunction: out.debug << "Function Definition: " << node->getName(); break;
236 case EOpFunctionCall: out.debug << "Function Call: " << node->getName(); break;
237 case EOpParameters: out.debug << "Function Parameters: "; break;
238
239 case EOpConstructFloat: out.debug << "Construct float"; break;
240 case EOpConstructVec2: out.debug << "Construct vec2"; break;
241 case EOpConstructVec3: out.debug << "Construct vec3"; break;
242 case EOpConstructVec4: out.debug << "Construct vec4"; break;
243 case EOpConstructBool: out.debug << "Construct bool"; break;
244 case EOpConstructBVec2: out.debug << "Construct bvec2"; break;
245 case EOpConstructBVec3: out.debug << "Construct bvec3"; break;
246 case EOpConstructBVec4: out.debug << "Construct bvec4"; break;
247 case EOpConstructInt: out.debug << "Construct int"; break;
248 case EOpConstructIVec2: out.debug << "Construct ivec2"; break;
249 case EOpConstructIVec3: out.debug << "Construct ivec3"; break;
250 case EOpConstructIVec4: out.debug << "Construct ivec4"; break;
251 case EOpConstructMat2: out.debug << "Construct mat2"; break;
252 case EOpConstructMat3: out.debug << "Construct mat3"; break;
253 case EOpConstructMat4: out.debug << "Construct mat4"; break;
254 case EOpConstructStruct: out.debug << "Construct structure"; break;
255
256 case EOpLessThan: out.debug << "Compare Less Than"; break;
257 case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
258 case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break;
259 case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
260 case EOpVectorEqual: out.debug << "Equal"; break;
261 case EOpVectorNotEqual: out.debug << "NotEqual"; break;
262
263 case EOpMod: out.debug << "mod"; break;
264 case EOpPow: out.debug << "pow"; break;
265
266 case EOpAtan: out.debug << "arc tangent"; break;
267
268 case EOpMin: out.debug << "min"; break;
269 case EOpMax: out.debug << "max"; break;
270 case EOpClamp: out.debug << "clamp"; break;
271 case EOpMix: out.debug << "mix"; break;
272 case EOpStep: out.debug << "step"; break;
273 case EOpSmoothStep: out.debug << "smoothstep"; break;
274
275 case EOpDistance: out.debug << "distance"; break;
276 case EOpDot: out.debug << "dot-product"; break;
277 case EOpCross: out.debug << "cross-product"; break;
278 case EOpFaceForward: out.debug << "face-forward"; break;
279 case EOpReflect: out.debug << "reflect"; break;
280 case EOpRefract: out.debug << "refract"; break;
281 case EOpMul: out.debug << "component-wise multiply"; break;
282
283 case EOpItof: out.debug << "itof"; break;
284 case EOpFtoi: out.debug << "ftoi"; break;
285 case EOpSkipPixels: out.debug << "skipPixels"; break;
286 case EOpReadInput: out.debug << "readInput"; break;
287 case EOpWritePixel: out.debug << "writePixel"; break;
288 case EOpBitmapLsb: out.debug << "bitmapLSB"; break;
289 case EOpBitmapMsb: out.debug << "bitmapMSB"; break;
290 case EOpWriteOutput: out.debug << "writeOutput"; break;
291 case EOpReadPixel: out.debug << "readPixel"; break;
292
293 default: out.debug.message(EPrefixError, "Bad aggregation op");
294 }
295
296 if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
297 out.debug << " (" << node->getCompleteString() << ")";
298
299 out.debug << "\n";
300
301 return true;
302}
303
304bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
305{
306 TInfoSink& out = infoSink;
307
308 OutputTreeText(out, node, depth);
309
310 out.debug << "Test condition and select";
311 out.debug << " (" << node->getCompleteString() << ")\n";
312
313 ++depth;
314
315 OutputTreeText(infoSink, node, depth);
316 out.debug << "Condition\n";
317 node->getCondition()->traverse(this);
318
319 OutputTreeText(infoSink, node, depth);
320 if (node->getTrueBlock()) {
321 out.debug << "true case\n";
322 node->getTrueBlock()->traverse(this);
323 } else
324 out.debug << "true case is null\n";
325
326 if (node->getFalseBlock()) {
327 OutputTreeText(infoSink, node, depth);
328 out.debug << "false case\n";
329 node->getFalseBlock()->traverse(this);
330 }
331
332 --depth;
333
334 return false;
335}
336
337void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
338{
339 TInfoSink& out = infoSink;
340
341 int size = node->getType().getObjectSize();
342
343 for (int i = 0; i < size; i++) {
344 OutputTreeText(out, node, depth);
345 switch (node->getUnionArrayPointer()[i].getType()) {
346 case EbtBool:
347 if (node->getUnionArrayPointer()[i].getBConst())
348 out.debug << "true";
349 else
350 out.debug << "false";
351
352 out.debug << " (" << "const bool" << ")";
353
354 out.debug << "\n";
355 break;
356 case EbtFloat:
357 {
358 char buf[300];
359 sprintf(buf, "%f (%s)", node->getUnionArrayPointer()[i].getFConst(), "const float");
360
361 out.debug << buf << "\n";
362 }
363 break;
364 case EbtInt:
365 {
366 char buf[300];
367 sprintf(buf, "%d (%s)", node->getUnionArrayPointer()[i].getIConst(), "const int");
368
369 out.debug << buf << "\n";
370 break;
371 }
372 default:
373 out.info.message(EPrefixInternalError, "Unknown constant", node->getLine());
374 break;
375 }
376 }
377}
378
379bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
380{
381 TInfoSink& out = infoSink;
382
383 OutputTreeText(out, node, depth);
384
385 out.debug << "Loop with condition ";
386 if (! node->testFirst())
387 out.debug << "not ";
388 out.debug << "tested first\n";
389
390 ++depth;
391
392 OutputTreeText(infoSink, node, depth);
393 if (node->getTest()) {
394 out.debug << "Loop Condition\n";
395 node->getTest()->traverse(this);
396 } else
397 out.debug << "No loop condition\n";
398
399 OutputTreeText(infoSink, node, depth);
400 if (node->getBody()) {
401 out.debug << "Loop Body\n";
402 node->getBody()->traverse(this);
403 } else
404 out.debug << "No loop body\n";
405
406 if (node->getTerminal()) {
407 OutputTreeText(infoSink, node, depth);
408 out.debug << "Loop Terminal Expression\n";
409 node->getTerminal()->traverse(this);
410 }
411
412 --depth;
413
414 return false;
415}
416
417bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
418{
419 TInfoSink& out = infoSink;
420
421 OutputTreeText(out, node, depth);
422
423 switch (node->getFlowOp()) {
424 case EOpKill: out.debug << "Branch: Kill"; break;
425 case EOpBreak: out.debug << "Branch: Break"; break;
426 case EOpContinue: out.debug << "Branch: Continue"; break;
427 case EOpReturn: out.debug << "Branch: Return"; break;
428 default: out.debug << "Branch: Unknown Branch"; break;
429 }
430
431 if (node->getExpression()) {
432 out.debug << " with expression\n";
433 ++depth;
434 node->getExpression()->traverse(this);
435 --depth;
436 } else
437 out.debug << "\n";
438
439 return false;
440}
441
442//
443// This function is the one to call externally to start the traversal.
444// Individual functions can be initialized to 0 to skip processing of that
445// type of node. It's children will still be processed.
446//
447void TIntermediate::outputTree(TIntermNode* root)
448{
449 if (root == 0)
450 return;
451
452 TOutputTraverser it(infoSink);
453
454 root->traverse(&it);
455}