blob: d4edd6e724957b46922a029a7b5c65cefc787b17 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capens16004fc2014-06-11 11:29:11 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madillb1a85f42014-08-19 15:23:24 -04007#include "compiler/translator/Intermediate.h"
Geoff Lang17732822013-08-29 13:46:49 -04008#include "compiler/translator/SymbolTable.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009
Jamie Madill45bcc782016-11-07 13:58:48 -050010namespace sh
11{
12
Zhenyao Moe40d1e92014-07-16 17:40:36 -070013namespace
14{
15
Olli Etuaho336b1472016-10-05 16:37:55 +010016void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
Olli Etuaho5f579b12015-08-14 17:44:43 +030017{
Olli Etuaho336b1472016-10-05 16:37:55 +010018 const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
19 out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
20 << info->getId() << ")";
Olli Etuaho5f579b12015-08-14 17:44:43 +030021}
22
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023//
24// Two purposes:
25// 1. Show an example of how to iterate tree. Functions can
26// also directly call Traverse() on children themselves to
27// have finer grained control over the process than shown here.
28// See the last function for how to get started.
29// 2. Print out a text based description of the tree.
30//
31
32//
33// Use this class to carry along data from node to node in
34// the traversal
35//
Zhenyao Moe40d1e92014-07-16 17:40:36 -070036class TOutputTraverser : public TIntermTraverser
37{
38 public:
Jamie Madilld7b1ab52016-12-12 14:42:19 -050039 TOutputTraverser(TInfoSinkBase &i) : TIntermTraverser(true, false, false), sink(i) {}
40 TInfoSinkBase &sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000041
Zhenyao Moe40d1e92014-07-16 17:40:36 -070042 protected:
Corentin Walleze5a1f272015-08-21 02:58:25 +020043 void visitSymbol(TIntermSymbol *) override;
44 void visitConstantUnion(TIntermConstantUnion *) override;
Olli Etuahob6fa0432016-09-28 16:28:05 +010045 bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
Corentin Walleze5a1f272015-08-21 02:58:25 +020046 bool visitBinary(Visit visit, TIntermBinary *) override;
47 bool visitUnary(Visit visit, TIntermUnary *) override;
Olli Etuahod0bad2c2016-09-09 18:01:16 +030048 bool visitTernary(Visit visit, TIntermTernary *node) override;
Olli Etuaho57961272016-09-14 13:57:46 +030049 bool visitIfElse(Visit visit, TIntermIfElse *node) override;
Olli Etuaho13e4d212016-10-13 11:50:27 +010050 bool visitSwitch(Visit visit, TIntermSwitch *node) override;
51 bool visitCase(Visit visit, TIntermCase *node) override;
Olli Etuaho16c745a2017-01-16 17:02:27 +000052 bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
Olli Etuaho336b1472016-10-05 16:37:55 +010053 bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
Corentin Walleze5a1f272015-08-21 02:58:25 +020054 bool visitAggregate(Visit visit, TIntermAggregate *) override;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010055 bool visitBlock(Visit visit, TIntermBlock *) override;
Olli Etuahobf4e1b72016-12-09 11:30:15 +000056 bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
Olli Etuaho13389b62016-10-16 11:48:18 +010057 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
Corentin Walleze5a1f272015-08-21 02:58:25 +020058 bool visitLoop(Visit visit, TIntermLoop *) override;
59 bool visitBranch(Visit visit, TIntermBranch *) override;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060};
61
Zhenyao Moe40d1e92014-07-16 17:40:36 -070062//
63// Helper functions for printing, not part of traversing.
64//
65void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
66{
67 int i;
68
Olli Etuaho77ba4082016-12-16 12:01:18 +000069 sink.location(node->getLine().first_file, node->getLine().first_line);
Zhenyao Moe40d1e92014-07-16 17:40:36 -070070
71 for (i = 0; i < depth; ++i)
72 sink << " ";
73}
74
75} // namespace anonymous
76
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000077//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000078// The rest of the file are the traversal functions. The last one
79// is the one that starts the traversal.
80//
81// Return true from interior nodes to have the external traversal
82// continue on to children. If you process children yourself,
83// return false.
84//
85
Zhenyao Moe40d1e92014-07-16 17:40:36 -070086void TOutputTraverser::visitSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087{
Zhenyao Moe40d1e92014-07-16 17:40:36 -070088 OutputTreeText(sink, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000089
alokp@chromium.org7beea402010-09-15 21:18:34 +000090 sink << "'" << node->getSymbol() << "' ";
91 sink << "(" << node->getCompleteString() << ")\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000092}
93
Olli Etuahob6fa0432016-09-28 16:28:05 +010094bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
95{
96 TInfoSinkBase &out = sink;
97 OutputTreeText(out, node, mDepth);
Olli Etuahoa2aff2a2017-01-20 22:15:05 +000098 out << "vector swizzle (";
99 node->writeOffsetsAsXYZW(&out);
100 out << ")";
101
102 out << " (" << node->getCompleteString() << ")";
103 out << "\n";
Olli Etuahob6fa0432016-09-28 16:28:05 +0100104 return true;
105}
106
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700107bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500109 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000110
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700111 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700113 switch (node->getOp())
114 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100115 case EOpComma:
116 out << "comma";
117 break;
118 case EOpAssign:
119 out << "move second child to first child";
120 break;
121 case EOpInitialize:
122 out << "initialize first child with second child";
123 break;
124 case EOpAddAssign:
125 out << "add second child into first child";
126 break;
127 case EOpSubAssign:
128 out << "subtract second child into first child";
129 break;
130 case EOpMulAssign:
131 out << "multiply second child into first child";
132 break;
133 case EOpVectorTimesMatrixAssign:
134 out << "matrix mult second child into first child";
135 break;
136 case EOpVectorTimesScalarAssign:
137 out << "vector scale second child into first child";
138 break;
139 case EOpMatrixTimesScalarAssign:
140 out << "matrix scale second child into first child";
141 break;
142 case EOpMatrixTimesMatrixAssign:
143 out << "matrix mult second child into first child";
144 break;
145 case EOpDivAssign:
146 out << "divide second child into first child";
147 break;
148 case EOpIModAssign:
149 out << "modulo second child into first child";
150 break;
151 case EOpBitShiftLeftAssign:
152 out << "bit-wise shift first child left by second child";
153 break;
154 case EOpBitShiftRightAssign:
155 out << "bit-wise shift first child right by second child";
156 break;
157 case EOpBitwiseAndAssign:
158 out << "bit-wise and second child into first child";
159 break;
160 case EOpBitwiseXorAssign:
161 out << "bit-wise xor second child into first child";
162 break;
163 case EOpBitwiseOrAssign:
164 out << "bit-wise or second child into first child";
165 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200166
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100167 case EOpIndexDirect:
168 out << "direct index";
169 break;
170 case EOpIndexIndirect:
171 out << "indirect index";
172 break;
173 case EOpIndexDirectStruct:
174 out << "direct index for structure";
175 break;
176 case EOpIndexDirectInterfaceBlock:
177 out << "direct index for interface block";
178 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100180 case EOpAdd:
181 out << "add";
182 break;
183 case EOpSub:
184 out << "subtract";
185 break;
186 case EOpMul:
187 out << "component-wise multiply";
188 break;
189 case EOpDiv:
190 out << "divide";
191 break;
192 case EOpIMod:
193 out << "modulo";
194 break;
195 case EOpBitShiftLeft:
196 out << "bit-wise shift left";
197 break;
198 case EOpBitShiftRight:
199 out << "bit-wise shift right";
200 break;
201 case EOpBitwiseAnd:
202 out << "bit-wise and";
203 break;
204 case EOpBitwiseXor:
205 out << "bit-wise xor";
206 break;
207 case EOpBitwiseOr:
208 out << "bit-wise or";
209 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200210
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100211 case EOpEqual:
212 out << "Compare Equal";
213 break;
214 case EOpNotEqual:
215 out << "Compare Not Equal";
216 break;
217 case EOpLessThan:
218 out << "Compare Less Than";
219 break;
220 case EOpGreaterThan:
221 out << "Compare Greater Than";
222 break;
223 case EOpLessThanEqual:
224 out << "Compare Less Than or Equal";
225 break;
226 case EOpGreaterThanEqual:
227 out << "Compare Greater Than or Equal";
228 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100230 case EOpVectorTimesScalar:
231 out << "vector-scale";
232 break;
233 case EOpVectorTimesMatrix:
234 out << "vector-times-matrix";
235 break;
236 case EOpMatrixTimesVector:
237 out << "matrix-times-vector";
238 break;
239 case EOpMatrixTimesScalar:
240 out << "matrix-scale";
241 break;
242 case EOpMatrixTimesMatrix:
243 out << "matrix-multiply";
244 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100246 case EOpLogicalOr:
247 out << "logical-or";
248 break;
249 case EOpLogicalXor:
250 out << "logical-xor";
251 break;
252 case EOpLogicalAnd:
253 out << "logical-and";
254 break;
255 default:
256 out << "<unknown op>";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000257 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000258
alokp@chromium.org7beea402010-09-15 21:18:34 +0000259 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260
alokp@chromium.org7beea402010-09-15 21:18:34 +0000261 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000262
Jamie Madill60305f12014-11-18 13:25:26 -0500263 // Special handling for direct indexes. Because constant
264 // unions are not aware they are struct indexes, treat them
265 // here where we have that contextual knowledge.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500266 if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
Jamie Madill60305f12014-11-18 13:25:26 -0500267 {
268 mDepth++;
269 node->getLeft()->traverse(this);
270 mDepth--;
271
272 TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
273 ASSERT(intermConstantUnion);
274
275 OutputTreeText(out, intermConstantUnion, mDepth + 1);
276
277 // The following code finds the field name from the constant union
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500278 const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
279 const TStructure *structure = node->getLeft()->getType().getStruct();
Jamie Madill60305f12014-11-18 13:25:26 -0500280 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
281 ASSERT(structure || interfaceBlock);
282
283 const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
284
285 const TField *field = fields[constantUnion->getIConst()];
286
287 out << constantUnion->getIConst() << " (field '" << field->name() << "')";
288
289 return false;
290 }
291
alokp@chromium.org76b82082010-03-24 17:59:39 +0000292 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293}
294
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700295bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500297 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700299 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700301 switch (node->getOp())
302 {
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000303 // Give verbose names for ops that have special syntax and some built-in functions that are
304 // easy to confuse with others, but mostly use GLSL names for functions.
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500305 case EOpNegative:
306 out << "Negate value";
307 break;
308 case EOpPositive:
309 out << "Positive sign";
310 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500311 case EOpLogicalNot:
Olli Etuahod68924e2017-01-02 17:34:40 +0000312 out << "negation";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500313 break;
314 case EOpBitwiseNot:
315 out << "bit-wise not";
316 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500318 case EOpPostIncrement:
319 out << "Post-Increment";
320 break;
321 case EOpPostDecrement:
322 out << "Post-Decrement";
323 break;
324 case EOpPreIncrement:
325 out << "Pre-Increment";
326 break;
327 case EOpPreDecrement:
328 out << "Pre-Decrement";
329 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330
Olli Etuahod68924e2017-01-02 17:34:40 +0000331 case EOpLogicalNotComponentWise:
332 out << "component-wise not";
333 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000334
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500335 default:
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000336 out << GetOperatorString(node->getOp());
337 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000338 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000339
alokp@chromium.org7beea402010-09-15 21:18:34 +0000340 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341
alokp@chromium.org7beea402010-09-15 21:18:34 +0000342 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343
alokp@chromium.org76b82082010-03-24 17:59:39 +0000344 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345}
346
Olli Etuaho336b1472016-10-05 16:37:55 +0100347bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
348{
349 TInfoSinkBase &out = sink;
350 OutputTreeText(out, node, mDepth);
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000351 out << "Function Definition:\n";
Olli Etuaho336b1472016-10-05 16:37:55 +0100352 out << "\n";
353 return true;
354}
355
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000356bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
357{
358 TInfoSinkBase &out = sink;
359 OutputTreeText(out, node, mDepth);
360 out << "Invariant Declaration:\n";
361 return true;
362}
363
Olli Etuaho16c745a2017-01-16 17:02:27 +0000364bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
365{
366 TInfoSinkBase &out = sink;
367
368 OutputTreeText(out, node, mDepth);
369 OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
370 out << " (" << node->getCompleteString() << ")";
371 out << "\n";
372
373 return true;
374}
375
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700376bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700378 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100380 OutputTreeText(out, node, mDepth);
381
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700382 if (node->getOp() == EOpNull)
383 {
Olli Etuaho77ba4082016-12-16 12:01:18 +0000384 out.prefix(SH_ERROR);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100385 out << "node is still EOpNull!\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000386 return true;
387 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000389 if (node->isConstructor())
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700390 {
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000391 if (node->getOp() == EOpConstructStruct)
392 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500393 out << "Construct structure";
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000394 }
395 else
396 {
397 out << "Construct " << GetOperatorString(node->getOp());
398 }
399 }
400 else
401 {
402 // Give verbose names for some built-in functions that are easy to confuse with others, but
403 // mostly use GLSL names for functions.
404 switch (node->getOp())
405 {
406 case EOpFunctionCall:
407 OutputFunction(out, "Function Call", node->getFunctionSymbolInfo());
408 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000409
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000410 case EOpEqualComponentWise:
411 out << "component-wise equal";
412 break;
413 case EOpNotEqualComponentWise:
414 out << "component-wise not equal";
415 break;
416 case EOpLessThanComponentWise:
417 out << "component-wise less than";
418 break;
419 case EOpGreaterThanComponentWise:
420 out << "component-wise greater than";
421 break;
422 case EOpLessThanEqualComponentWise:
423 out << "component-wise less than or equal";
424 break;
425 case EOpGreaterThanEqualComponentWise:
426 out << "component-wise greater than or equal";
427 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000429 case EOpDot:
430 out << "dot product";
431 break;
432 case EOpCross:
433 out << "cross product";
434 break;
435 case EOpMulMatrixComponentWise:
436 out << "component-wise multiply";
437 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000439 default:
440 out << GetOperatorString(node->getOp());
441 break;
442 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000443 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000444
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000445 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000446
alokp@chromium.org7beea402010-09-15 21:18:34 +0000447 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448
alokp@chromium.org76b82082010-03-24 17:59:39 +0000449 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450}
451
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100452bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
453{
454 TInfoSinkBase &out = sink;
455
456 OutputTreeText(out, node, mDepth);
457 out << "Code block\n";
458
459 return true;
460}
461
Olli Etuaho13389b62016-10-16 11:48:18 +0100462bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
463{
464 TInfoSinkBase &out = sink;
465
466 OutputTreeText(out, node, mDepth);
467 out << "Declaration\n";
468
469 return true;
470}
471
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300472bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
473{
474 TInfoSinkBase &out = sink;
475
476 OutputTreeText(out, node, mDepth);
477
478 out << "Ternary selection";
479 out << " (" << node->getCompleteString() << ")\n";
480
481 ++mDepth;
482
483 OutputTreeText(sink, node, mDepth);
484 out << "Condition\n";
485 node->getCondition()->traverse(this);
486
487 OutputTreeText(sink, node, mDepth);
488 if (node->getTrueExpression())
489 {
490 out << "true case\n";
491 node->getTrueExpression()->traverse(this);
492 }
493 if (node->getFalseExpression())
494 {
495 OutputTreeText(sink, node, mDepth);
496 out << "false case\n";
497 node->getFalseExpression()->traverse(this);
498 }
499
500 --mDepth;
501
502 return false;
503}
504
Olli Etuaho57961272016-09-14 13:57:46 +0300505bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000506{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700507 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700509 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000510
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300511 out << "If test\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000512
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700513 ++mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000514
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700515 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000516 out << "Condition\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000517 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000518
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700519 OutputTreeText(sink, node, mDepth);
520 if (node->getTrueBlock())
521 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000522 out << "true case\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000523 node->getTrueBlock()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700524 }
525 else
526 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000527 out << "true case is null\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700528 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700530 if (node->getFalseBlock())
531 {
532 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000533 out << "false case\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000534 node->getFalseBlock()->traverse(this);
535 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000536
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700537 --mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000538
alokp@chromium.org76b82082010-03-24 17:59:39 +0000539 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000540}
541
Olli Etuaho13e4d212016-10-13 11:50:27 +0100542bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
543{
544 TInfoSinkBase &out = sink;
545
546 OutputTreeText(out, node, mDepth);
547
548 out << "Switch\n";
549
550 return true;
551}
552
553bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
554{
555 TInfoSinkBase &out = sink;
556
557 OutputTreeText(out, node, mDepth);
558
559 if (node->getCondition() == nullptr)
560 {
561 out << "Default\n";
562 }
563 else
564 {
565 out << "Case\n";
566 }
567
568 return true;
569}
570
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700571void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700573 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000574
Jamie Madill94bf7f22013-07-08 13:31:15 -0400575 size_t size = node->getType().getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700577 for (size_t i = 0; i < size; i++)
578 {
579 OutputTreeText(out, node, mDepth);
580 switch (node->getUnionArrayPointer()[i].getType())
581 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500582 case EbtBool:
583 if (node->getUnionArrayPointer()[i].getBConst())
584 out << "true";
585 else
586 out << "false";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000587
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500588 out << " ("
589 << "const bool"
590 << ")";
591 out << "\n";
592 break;
593 case EbtFloat:
594 out << node->getUnionArrayPointer()[i].getFConst();
595 out << " (const float)\n";
596 break;
597 case EbtInt:
598 out << node->getUnionArrayPointer()[i].getIConst();
599 out << " (const int)\n";
600 break;
601 case EbtUInt:
602 out << node->getUnionArrayPointer()[i].getUConst();
603 out << " (const uint)\n";
604 break;
605 default:
Olli Etuaho77ba4082016-12-16 12:01:18 +0000606 out.prefix(SH_ERROR);
607 out << "Unknown constant";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500608 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000609 }
610 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611}
612
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700613bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000614{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700615 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700617 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000618
alokp@chromium.org7beea402010-09-15 21:18:34 +0000619 out << "Loop with condition ";
alokp@chromium.org52813552010-11-16 18:36:09 +0000620 if (node->getType() == ELoopDoWhile)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000621 out << "not ";
622 out << "tested first\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700624 ++mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000625
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700626 OutputTreeText(sink, node, mDepth);
627 if (node->getCondition())
628 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000629 out << "Loop Condition\n";
alokp@chromium.org52813552010-11-16 18:36:09 +0000630 node->getCondition()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700631 }
632 else
633 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000634 out << "No loop condition\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700635 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000636
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700637 OutputTreeText(sink, node, mDepth);
638 if (node->getBody())
639 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000640 out << "Loop Body\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000641 node->getBody()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700642 }
643 else
644 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000645 out << "No loop body\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700646 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000647
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700648 if (node->getExpression())
649 {
650 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000651 out << "Loop Terminal Expression\n";
alokp@chromium.org52813552010-11-16 18:36:09 +0000652 node->getExpression()->traverse(this);
alokp@chromium.org76b82082010-03-24 17:59:39 +0000653 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000654
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700655 --mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656
alokp@chromium.org76b82082010-03-24 17:59:39 +0000657 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658}
659
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700660bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000661{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700662 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000663
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700664 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700666 switch (node->getFlowOp())
667 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500668 case EOpKill:
669 out << "Branch: Kill";
670 break;
671 case EOpBreak:
672 out << "Branch: Break";
673 break;
674 case EOpContinue:
675 out << "Branch: Continue";
676 break;
677 case EOpReturn:
678 out << "Branch: Return";
679 break;
680 default:
681 out << "Branch: Unknown Branch";
682 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000683 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000684
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700685 if (node->getExpression())
686 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000687 out << " with expression\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700688 ++mDepth;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000689 node->getExpression()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700690 --mDepth;
691 }
692 else
693 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000694 out << "\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700695 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000696
alokp@chromium.org76b82082010-03-24 17:59:39 +0000697 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000698}
699
700//
701// This function is the one to call externally to start the traversal.
702// Individual functions can be initialized to 0 to skip processing of that
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200703// type of node. Its children will still be processed.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000704//
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200705void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000706{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200707 TOutputTraverser it(infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000708
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200709 ASSERT(root);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000710
alokp@chromium.org76b82082010-03-24 17:59:39 +0000711 root->traverse(&it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000712}
Jamie Madill45bcc782016-11-07 13:58:48 -0500713
714} // namespace sh