blob: adcd24269a988af64c7c14202cd4ddd23e0e08fd [file] [log] [blame]
Olli Etuahocccf2b02017-07-05 14:50:54 +03001//
2// Copyright (c) 2002-2014 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
Olli Etuahocccf2b02017-07-05 14:50:54 +03007#include "compiler/translator/SymbolTable.h"
Olli Etuahoc26214d2018-03-16 10:43:11 +02008#include "compiler/translator/tree_util/IntermTraverse.h"
Olli Etuahocccf2b02017-07-05 14:50:54 +03009
10namespace sh
11{
12
13namespace
14{
15
Olli Etuaho1bb85282017-12-14 13:39:53 +020016void OutputFunction(TInfoSinkBase &out, const char *str, const TFunction *func)
17{
18 const char *internal =
19 (func->symbolType() == SymbolType::AngleInternal) ? " (internal function)" : "";
Olli Etuahobed35d72017-12-20 16:36:26 +020020 out << str << internal << ": " << func->name() << " (symbol id " << func->uniqueId().get()
Olli Etuaho1bb85282017-12-14 13:39:53 +020021 << ")";
22}
23
Olli Etuahocccf2b02017-07-05 14:50:54 +030024// Two purposes:
25// 1. Show an example of how to iterate tree. Functions can also directly call traverse() on
26// children themselves to have finer grained control over the process than shown here, though
27// that's not recommended if it can be avoided.
28// 2. Print out a text based description of the tree.
29
30// The traverser subclass is used to carry along data from node to node in the traversal.
31class TOutputTraverser : public TIntermTraverser
32{
33 public:
Olli Etuaho4002e922018-04-04 16:55:34 +030034 TOutputTraverser(TInfoSinkBase &out)
35 : TIntermTraverser(true, false, false), mOut(out), mIndentDepth(0)
36 {
37 }
Olli Etuahocccf2b02017-07-05 14:50:54 +030038
39 protected:
40 void visitSymbol(TIntermSymbol *) override;
41 void visitConstantUnion(TIntermConstantUnion *) override;
42 bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
43 bool visitBinary(Visit visit, TIntermBinary *) override;
44 bool visitUnary(Visit visit, TIntermUnary *) override;
45 bool visitTernary(Visit visit, TIntermTernary *node) override;
46 bool visitIfElse(Visit visit, TIntermIfElse *node) override;
47 bool visitSwitch(Visit visit, TIntermSwitch *node) override;
48 bool visitCase(Visit visit, TIntermCase *node) override;
Olli Etuahod4bd9632018-03-08 16:32:44 +020049 void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
Olli Etuahocccf2b02017-07-05 14:50:54 +030050 bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
51 bool visitAggregate(Visit visit, TIntermAggregate *) override;
52 bool visitBlock(Visit visit, TIntermBlock *) override;
53 bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
54 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
55 bool visitLoop(Visit visit, TIntermLoop *) override;
56 bool visitBranch(Visit visit, TIntermBranch *) override;
57
Olli Etuaho4002e922018-04-04 16:55:34 +030058 int getCurrentIndentDepth() const { return mIndentDepth + getCurrentTraversalDepth(); }
59
Olli Etuahocccf2b02017-07-05 14:50:54 +030060 TInfoSinkBase &mOut;
Olli Etuaho4002e922018-04-04 16:55:34 +030061 int mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +030062};
63
64//
65// Helper functions for printing, not part of traversing.
66//
67void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth)
68{
69 int i;
70
71 out.location(node->getLine().first_file, node->getLine().first_line);
72
73 for (i = 0; i < depth; ++i)
74 out << " ";
75}
76
77//
78// 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
86void TOutputTraverser::visitSymbol(TIntermSymbol *node)
87{
Olli Etuaho4002e922018-04-04 16:55:34 +030088 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +030089
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +020090 if (node->variable().symbolType() == SymbolType::Empty)
91 {
92 mOut << "''";
93 }
94 else
95 {
96 mOut << "'" << node->getName() << "' ";
97 }
Olli Etuahob6af22b2017-12-15 14:05:44 +020098 mOut << "(symbol id " << node->uniqueId().get() << ") ";
Olli Etuahocccf2b02017-07-05 14:50:54 +030099 mOut << "(" << node->getCompleteString() << ")";
100 mOut << "\n";
101}
102
103bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
104{
Olli Etuaho4002e922018-04-04 16:55:34 +0300105 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300106 mOut << "vector swizzle (";
107 node->writeOffsetsAsXYZW(&mOut);
108 mOut << ")";
109
110 mOut << " (" << node->getCompleteString() << ")";
111 mOut << "\n";
112 return true;
113}
114
115bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
116{
Olli Etuaho4002e922018-04-04 16:55:34 +0300117 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300118
119 switch (node->getOp())
120 {
121 case EOpComma:
122 mOut << "comma";
123 break;
124 case EOpAssign:
125 mOut << "move second child to first child";
126 break;
127 case EOpInitialize:
128 mOut << "initialize first child with second child";
129 break;
130 case EOpAddAssign:
131 mOut << "add second child into first child";
132 break;
133 case EOpSubAssign:
134 mOut << "subtract second child into first child";
135 break;
136 case EOpMulAssign:
137 mOut << "multiply second child into first child";
138 break;
139 case EOpVectorTimesMatrixAssign:
140 mOut << "matrix mult second child into first child";
141 break;
142 case EOpVectorTimesScalarAssign:
143 mOut << "vector scale second child into first child";
144 break;
145 case EOpMatrixTimesScalarAssign:
146 mOut << "matrix scale second child into first child";
147 break;
148 case EOpMatrixTimesMatrixAssign:
149 mOut << "matrix mult second child into first child";
150 break;
151 case EOpDivAssign:
152 mOut << "divide second child into first child";
153 break;
154 case EOpIModAssign:
155 mOut << "modulo second child into first child";
156 break;
157 case EOpBitShiftLeftAssign:
158 mOut << "bit-wise shift first child left by second child";
159 break;
160 case EOpBitShiftRightAssign:
161 mOut << "bit-wise shift first child right by second child";
162 break;
163 case EOpBitwiseAndAssign:
164 mOut << "bit-wise and second child into first child";
165 break;
166 case EOpBitwiseXorAssign:
167 mOut << "bit-wise xor second child into first child";
168 break;
169 case EOpBitwiseOrAssign:
170 mOut << "bit-wise or second child into first child";
171 break;
172
173 case EOpIndexDirect:
174 mOut << "direct index";
175 break;
176 case EOpIndexIndirect:
177 mOut << "indirect index";
178 break;
179 case EOpIndexDirectStruct:
180 mOut << "direct index for structure";
181 break;
182 case EOpIndexDirectInterfaceBlock:
183 mOut << "direct index for interface block";
184 break;
185
186 case EOpAdd:
187 mOut << "add";
188 break;
189 case EOpSub:
190 mOut << "subtract";
191 break;
192 case EOpMul:
193 mOut << "component-wise multiply";
194 break;
195 case EOpDiv:
196 mOut << "divide";
197 break;
198 case EOpIMod:
199 mOut << "modulo";
200 break;
201 case EOpBitShiftLeft:
202 mOut << "bit-wise shift left";
203 break;
204 case EOpBitShiftRight:
205 mOut << "bit-wise shift right";
206 break;
207 case EOpBitwiseAnd:
208 mOut << "bit-wise and";
209 break;
210 case EOpBitwiseXor:
211 mOut << "bit-wise xor";
212 break;
213 case EOpBitwiseOr:
214 mOut << "bit-wise or";
215 break;
216
217 case EOpEqual:
218 mOut << "Compare Equal";
219 break;
220 case EOpNotEqual:
221 mOut << "Compare Not Equal";
222 break;
223 case EOpLessThan:
224 mOut << "Compare Less Than";
225 break;
226 case EOpGreaterThan:
227 mOut << "Compare Greater Than";
228 break;
229 case EOpLessThanEqual:
230 mOut << "Compare Less Than or Equal";
231 break;
232 case EOpGreaterThanEqual:
233 mOut << "Compare Greater Than or Equal";
234 break;
235
236 case EOpVectorTimesScalar:
237 mOut << "vector-scale";
238 break;
239 case EOpVectorTimesMatrix:
240 mOut << "vector-times-matrix";
241 break;
242 case EOpMatrixTimesVector:
243 mOut << "matrix-times-vector";
244 break;
245 case EOpMatrixTimesScalar:
246 mOut << "matrix-scale";
247 break;
248 case EOpMatrixTimesMatrix:
249 mOut << "matrix-multiply";
250 break;
251
252 case EOpLogicalOr:
253 mOut << "logical-or";
254 break;
255 case EOpLogicalXor:
256 mOut << "logical-xor";
257 break;
258 case EOpLogicalAnd:
259 mOut << "logical-and";
260 break;
261 default:
262 mOut << "<unknown op>";
263 }
264
265 mOut << " (" << node->getCompleteString() << ")";
266
267 mOut << "\n";
268
269 // Special handling for direct indexes. Because constant
270 // unions are not aware they are struct indexes, treat them
271 // here where we have that contextual knowledge.
272 if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
273 {
274 node->getLeft()->traverse(this);
275
276 TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
277 ASSERT(intermConstantUnion);
278
Olli Etuaho4002e922018-04-04 16:55:34 +0300279 OutputTreeText(mOut, intermConstantUnion, getCurrentIndentDepth() + 1);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300280
281 // The following code finds the field name from the constant union
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200282 const TConstantUnion *constantUnion = intermConstantUnion->getConstantValue();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300283 const TStructure *structure = node->getLeft()->getType().getStruct();
284 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
285 ASSERT(structure || interfaceBlock);
286
287 const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
288
289 const TField *field = fields[constantUnion->getIConst()];
290
291 mOut << constantUnion->getIConst() << " (field '" << field->name() << "')";
292
293 mOut << "\n";
294
295 return false;
296 }
297
298 return true;
299}
300
301bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
302{
Olli Etuaho4002e922018-04-04 16:55:34 +0300303 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300304
305 switch (node->getOp())
306 {
307 // Give verbose names for ops that have special syntax and some built-in functions that are
308 // easy to confuse with others, but mostly use GLSL names for functions.
309 case EOpNegative:
310 mOut << "Negate value";
311 break;
312 case EOpPositive:
313 mOut << "Positive sign";
314 break;
315 case EOpLogicalNot:
316 mOut << "negation";
317 break;
318 case EOpBitwiseNot:
319 mOut << "bit-wise not";
320 break;
321
322 case EOpPostIncrement:
323 mOut << "Post-Increment";
324 break;
325 case EOpPostDecrement:
326 mOut << "Post-Decrement";
327 break;
328 case EOpPreIncrement:
329 mOut << "Pre-Increment";
330 break;
331 case EOpPreDecrement:
332 mOut << "Pre-Decrement";
333 break;
334
Olli Etuahobb2bbfb2017-08-24 15:43:33 +0300335 case EOpArrayLength:
336 mOut << "Array length";
337 break;
338
Olli Etuahocccf2b02017-07-05 14:50:54 +0300339 case EOpLogicalNotComponentWise:
340 mOut << "component-wise not";
341 break;
342
343 default:
344 mOut << GetOperatorString(node->getOp());
345 break;
346 }
347
348 mOut << " (" << node->getCompleteString() << ")";
349
350 mOut << "\n";
351
352 return true;
353}
354
355bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
356{
Olli Etuaho4002e922018-04-04 16:55:34 +0300357 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300358 mOut << "Function Definition:\n";
Olli Etuahocccf2b02017-07-05 14:50:54 +0300359 return true;
360}
361
362bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
363{
Olli Etuaho4002e922018-04-04 16:55:34 +0300364 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300365 mOut << "Invariant Declaration:\n";
366 return true;
367}
368
Olli Etuahod4bd9632018-03-08 16:32:44 +0200369void TOutputTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuahocccf2b02017-07-05 14:50:54 +0300370{
Olli Etuaho4002e922018-04-04 16:55:34 +0300371 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200372 OutputFunction(mOut, "Function Prototype", node->getFunction());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300373 mOut << " (" << node->getCompleteString() << ")";
374 mOut << "\n";
Olli Etuahod4bd9632018-03-08 16:32:44 +0200375 size_t paramCount = node->getFunction()->getParamCount();
376 for (size_t i = 0; i < paramCount; ++i)
377 {
378 const TVariable *param = node->getFunction()->getParam(i);
Olli Etuaho4002e922018-04-04 16:55:34 +0300379 OutputTreeText(mOut, node, getCurrentIndentDepth() + 1);
Olli Etuahod4bd9632018-03-08 16:32:44 +0200380 mOut << "parameter: " << param->name() << " (" << param->getType().getCompleteString()
381 << ")";
382 }
Olli Etuahocccf2b02017-07-05 14:50:54 +0300383}
384
385bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
386{
Olli Etuaho4002e922018-04-04 16:55:34 +0300387 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300388
389 if (node->getOp() == EOpNull)
390 {
391 mOut.prefix(SH_ERROR);
392 mOut << "node is still EOpNull!\n";
393 return true;
394 }
395
396 // Give verbose names for some built-in functions that are easy to confuse with others, but
397 // mostly use GLSL names for functions.
398 switch (node->getOp())
399 {
400 case EOpCallFunctionInAST:
Olli Etuaho1bb85282017-12-14 13:39:53 +0200401 OutputFunction(mOut, "Call an user-defined function", node->getFunction());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300402 break;
403 case EOpCallInternalRawFunction:
404 OutputFunction(mOut, "Call an internal function with raw implementation",
Olli Etuaho1bb85282017-12-14 13:39:53 +0200405 node->getFunction());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300406 break;
407 case EOpCallBuiltInFunction:
Olli Etuaho1bb85282017-12-14 13:39:53 +0200408 OutputFunction(mOut, "Call a built-in function", node->getFunction());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300409 break;
410
411 case EOpConstruct:
412 // The type of the constructor will be printed below.
413 mOut << "Construct";
414 break;
415
416 case EOpEqualComponentWise:
417 mOut << "component-wise equal";
418 break;
419 case EOpNotEqualComponentWise:
420 mOut << "component-wise not equal";
421 break;
422 case EOpLessThanComponentWise:
423 mOut << "component-wise less than";
424 break;
425 case EOpGreaterThanComponentWise:
426 mOut << "component-wise greater than";
427 break;
428 case EOpLessThanEqualComponentWise:
429 mOut << "component-wise less than or equal";
430 break;
431 case EOpGreaterThanEqualComponentWise:
432 mOut << "component-wise greater than or equal";
433 break;
434
435 case EOpDot:
436 mOut << "dot product";
437 break;
438 case EOpCross:
439 mOut << "cross product";
440 break;
441 case EOpMulMatrixComponentWise:
442 mOut << "component-wise multiply";
443 break;
444
445 default:
446 mOut << GetOperatorString(node->getOp());
447 break;
448 }
449
450 mOut << " (" << node->getCompleteString() << ")";
451
452 mOut << "\n";
453
454 return true;
455}
456
457bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
458{
Olli Etuaho4002e922018-04-04 16:55:34 +0300459 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300460 mOut << "Code block\n";
461
462 return true;
463}
464
465bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
466{
Olli Etuaho4002e922018-04-04 16:55:34 +0300467 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300468 mOut << "Declaration\n";
469
470 return true;
471}
472
473bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
474{
Olli Etuaho4002e922018-04-04 16:55:34 +0300475 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300476
477 mOut << "Ternary selection";
478 mOut << " (" << node->getCompleteString() << ")\n";
479
Olli Etuaho4002e922018-04-04 16:55:34 +0300480 ++mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300481
Olli Etuaho4002e922018-04-04 16:55:34 +0300482 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300483 mOut << "Condition\n";
484 node->getCondition()->traverse(this);
485
Olli Etuaho4002e922018-04-04 16:55:34 +0300486 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300487 if (node->getTrueExpression())
488 {
489 mOut << "true case\n";
490 node->getTrueExpression()->traverse(this);
491 }
492 if (node->getFalseExpression())
493 {
Olli Etuaho4002e922018-04-04 16:55:34 +0300494 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300495 mOut << "false case\n";
496 node->getFalseExpression()->traverse(this);
497 }
498
Olli Etuaho4002e922018-04-04 16:55:34 +0300499 --mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300500
501 return false;
502}
503
504bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
505{
Olli Etuaho4002e922018-04-04 16:55:34 +0300506 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300507
508 mOut << "If test\n";
509
Olli Etuaho4002e922018-04-04 16:55:34 +0300510 ++mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300511
Olli Etuaho4002e922018-04-04 16:55:34 +0300512 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300513 mOut << "Condition\n";
514 node->getCondition()->traverse(this);
515
Olli Etuaho4002e922018-04-04 16:55:34 +0300516 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300517 if (node->getTrueBlock())
518 {
519 mOut << "true case\n";
520 node->getTrueBlock()->traverse(this);
521 }
522 else
523 {
524 mOut << "true case is null\n";
525 }
526
527 if (node->getFalseBlock())
528 {
Olli Etuaho4002e922018-04-04 16:55:34 +0300529 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300530 mOut << "false case\n";
531 node->getFalseBlock()->traverse(this);
532 }
533
Olli Etuaho4002e922018-04-04 16:55:34 +0300534 --mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300535
536 return false;
537}
538
539bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
540{
Olli Etuaho4002e922018-04-04 16:55:34 +0300541 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300542
543 mOut << "Switch\n";
544
545 return true;
546}
547
548bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
549{
Olli Etuaho4002e922018-04-04 16:55:34 +0300550 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300551
552 if (node->getCondition() == nullptr)
553 {
554 mOut << "Default\n";
555 }
556 else
557 {
558 mOut << "Case\n";
559 }
560
561 return true;
562}
563
564void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
565{
566 size_t size = node->getType().getObjectSize();
567
568 for (size_t i = 0; i < size; i++)
569 {
Olli Etuaho4002e922018-04-04 16:55:34 +0300570 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200571 switch (node->getConstantValue()[i].getType())
Olli Etuahocccf2b02017-07-05 14:50:54 +0300572 {
573 case EbtBool:
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200574 if (node->getConstantValue()[i].getBConst())
Olli Etuahocccf2b02017-07-05 14:50:54 +0300575 mOut << "true";
576 else
577 mOut << "false";
578
579 mOut << " ("
580 << "const bool"
581 << ")";
582 mOut << "\n";
583 break;
584 case EbtFloat:
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200585 mOut << node->getConstantValue()[i].getFConst();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300586 mOut << " (const float)\n";
587 break;
588 case EbtInt:
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200589 mOut << node->getConstantValue()[i].getIConst();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300590 mOut << " (const int)\n";
591 break;
592 case EbtUInt:
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200593 mOut << node->getConstantValue()[i].getUConst();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300594 mOut << " (const uint)\n";
595 break;
596 case EbtYuvCscStandardEXT:
597 mOut << getYuvCscStandardEXTString(
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200598 node->getConstantValue()[i].getYuvCscStandardEXTConst());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300599 mOut << " (const yuvCscStandardEXT)\n";
600 break;
601 default:
602 mOut.prefix(SH_ERROR);
603 mOut << "Unknown constant\n";
604 break;
605 }
606 }
607}
608
609bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
610{
Olli Etuaho4002e922018-04-04 16:55:34 +0300611 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300612
613 mOut << "Loop with condition ";
614 if (node->getType() == ELoopDoWhile)
615 mOut << "not ";
616 mOut << "tested first\n";
617
Olli Etuaho4002e922018-04-04 16:55:34 +0300618 ++mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300619
Olli Etuaho4002e922018-04-04 16:55:34 +0300620 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300621 if (node->getCondition())
622 {
623 mOut << "Loop Condition\n";
624 node->getCondition()->traverse(this);
625 }
626 else
627 {
628 mOut << "No loop condition\n";
629 }
630
Olli Etuaho4002e922018-04-04 16:55:34 +0300631 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300632 if (node->getBody())
633 {
634 mOut << "Loop Body\n";
635 node->getBody()->traverse(this);
636 }
637 else
638 {
639 mOut << "No loop body\n";
640 }
641
642 if (node->getExpression())
643 {
Olli Etuaho4002e922018-04-04 16:55:34 +0300644 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300645 mOut << "Loop Terminal Expression\n";
646 node->getExpression()->traverse(this);
647 }
648
Olli Etuaho4002e922018-04-04 16:55:34 +0300649 --mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300650
651 return false;
652}
653
654bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
655{
Olli Etuaho4002e922018-04-04 16:55:34 +0300656 OutputTreeText(mOut, node, getCurrentIndentDepth());
Olli Etuahocccf2b02017-07-05 14:50:54 +0300657
658 switch (node->getFlowOp())
659 {
660 case EOpKill:
661 mOut << "Branch: Kill";
662 break;
663 case EOpBreak:
664 mOut << "Branch: Break";
665 break;
666 case EOpContinue:
667 mOut << "Branch: Continue";
668 break;
669 case EOpReturn:
670 mOut << "Branch: Return";
671 break;
672 default:
673 mOut << "Branch: Unknown Branch";
674 break;
675 }
676
677 if (node->getExpression())
678 {
679 mOut << " with expression\n";
Olli Etuaho4002e922018-04-04 16:55:34 +0300680 ++mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300681 node->getExpression()->traverse(this);
Olli Etuaho4002e922018-04-04 16:55:34 +0300682 --mIndentDepth;
Olli Etuahocccf2b02017-07-05 14:50:54 +0300683 }
684 else
685 {
686 mOut << "\n";
687 }
688
689 return false;
690}
691
692} // anonymous namespace
693
694void OutputTree(TIntermNode *root, TInfoSinkBase &out)
695{
696 TOutputTraverser it(out);
697 ASSERT(root);
698 root->traverse(&it);
699}
700
701} // namespace sh