blob: af2c1999f0959cde9606f3b27ce9c04def771c72 [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 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800406 case EOpCallFunctionInAST:
407 OutputFunction(out, "Call an user-defined function", node->getFunctionSymbolInfo());
408 break;
409 case EOpCallInternalRawFunction:
410 OutputFunction(out, "Call an internal function with raw implementation",
411 node->getFunctionSymbolInfo());
412 break;
413 case EOpCallBuiltInFunction:
414 OutputFunction(out, "Call a built-in function", node->getFunctionSymbolInfo());
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000415 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000417 case EOpEqualComponentWise:
418 out << "component-wise equal";
419 break;
420 case EOpNotEqualComponentWise:
421 out << "component-wise not equal";
422 break;
423 case EOpLessThanComponentWise:
424 out << "component-wise less than";
425 break;
426 case EOpGreaterThanComponentWise:
427 out << "component-wise greater than";
428 break;
429 case EOpLessThanEqualComponentWise:
430 out << "component-wise less than or equal";
431 break;
432 case EOpGreaterThanEqualComponentWise:
433 out << "component-wise greater than or equal";
434 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000436 case EOpDot:
437 out << "dot product";
438 break;
439 case EOpCross:
440 out << "cross product";
441 break;
442 case EOpMulMatrixComponentWise:
443 out << "component-wise multiply";
444 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445
Olli Etuahoa2aff2a2017-01-20 22:15:05 +0000446 default:
447 out << GetOperatorString(node->getOp());
448 break;
449 }
alokp@chromium.org76b82082010-03-24 17:59:39 +0000450 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000452 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453
alokp@chromium.org7beea402010-09-15 21:18:34 +0000454 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455
alokp@chromium.org76b82082010-03-24 17:59:39 +0000456 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000457}
458
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100459bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
460{
461 TInfoSinkBase &out = sink;
462
463 OutputTreeText(out, node, mDepth);
464 out << "Code block\n";
465
466 return true;
467}
468
Olli Etuaho13389b62016-10-16 11:48:18 +0100469bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
470{
471 TInfoSinkBase &out = sink;
472
473 OutputTreeText(out, node, mDepth);
474 out << "Declaration\n";
475
476 return true;
477}
478
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300479bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
480{
481 TInfoSinkBase &out = sink;
482
483 OutputTreeText(out, node, mDepth);
484
485 out << "Ternary selection";
486 out << " (" << node->getCompleteString() << ")\n";
487
488 ++mDepth;
489
490 OutputTreeText(sink, node, mDepth);
491 out << "Condition\n";
492 node->getCondition()->traverse(this);
493
494 OutputTreeText(sink, node, mDepth);
495 if (node->getTrueExpression())
496 {
497 out << "true case\n";
498 node->getTrueExpression()->traverse(this);
499 }
500 if (node->getFalseExpression())
501 {
502 OutputTreeText(sink, node, mDepth);
503 out << "false case\n";
504 node->getFalseExpression()->traverse(this);
505 }
506
507 --mDepth;
508
509 return false;
510}
511
Olli Etuaho57961272016-09-14 13:57:46 +0300512bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000513{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700514 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700516 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300518 out << "If test\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700520 ++mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700522 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000523 out << "Condition\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000524 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000525
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700526 OutputTreeText(sink, node, mDepth);
527 if (node->getTrueBlock())
528 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000529 out << "true case\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000530 node->getTrueBlock()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700531 }
532 else
533 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000534 out << "true case is null\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700535 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000536
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700537 if (node->getFalseBlock())
538 {
539 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000540 out << "false case\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000541 node->getFalseBlock()->traverse(this);
542 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700544 --mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545
alokp@chromium.org76b82082010-03-24 17:59:39 +0000546 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000547}
548
Olli Etuaho13e4d212016-10-13 11:50:27 +0100549bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
550{
551 TInfoSinkBase &out = sink;
552
553 OutputTreeText(out, node, mDepth);
554
555 out << "Switch\n";
556
557 return true;
558}
559
560bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
561{
562 TInfoSinkBase &out = sink;
563
564 OutputTreeText(out, node, mDepth);
565
566 if (node->getCondition() == nullptr)
567 {
568 out << "Default\n";
569 }
570 else
571 {
572 out << "Case\n";
573 }
574
575 return true;
576}
577
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700578void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000579{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700580 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000581
Jamie Madill94bf7f22013-07-08 13:31:15 -0400582 size_t size = node->getType().getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700584 for (size_t i = 0; i < size; i++)
585 {
586 OutputTreeText(out, node, mDepth);
587 switch (node->getUnionArrayPointer()[i].getType())
588 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500589 case EbtBool:
590 if (node->getUnionArrayPointer()[i].getBConst())
591 out << "true";
592 else
593 out << "false";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500595 out << " ("
596 << "const bool"
597 << ")";
598 out << "\n";
599 break;
600 case EbtFloat:
601 out << node->getUnionArrayPointer()[i].getFConst();
602 out << " (const float)\n";
603 break;
604 case EbtInt:
605 out << node->getUnionArrayPointer()[i].getIConst();
606 out << " (const int)\n";
607 break;
608 case EbtUInt:
609 out << node->getUnionArrayPointer()[i].getUConst();
610 out << " (const uint)\n";
611 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300612 case EbtYuvCscStandardEXT:
613 out << getYuvCscStandardEXTString(
614 node->getUnionArrayPointer()[i].getYuvCscStandardEXTConst());
615 out << " (const yuvCscStandardEXT)\n";
616 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500617 default:
Olli Etuaho77ba4082016-12-16 12:01:18 +0000618 out.prefix(SH_ERROR);
Andrei Volykhina5527072017-03-22 16:46:30 +0300619 out << "Unknown constant\n";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500620 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000621 }
622 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623}
624
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700625bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700627 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700629 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000630
alokp@chromium.org7beea402010-09-15 21:18:34 +0000631 out << "Loop with condition ";
alokp@chromium.org52813552010-11-16 18:36:09 +0000632 if (node->getType() == ELoopDoWhile)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000633 out << "not ";
634 out << "tested first\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000635
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700636 ++mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000637
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700638 OutputTreeText(sink, node, mDepth);
639 if (node->getCondition())
640 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000641 out << "Loop Condition\n";
alokp@chromium.org52813552010-11-16 18:36:09 +0000642 node->getCondition()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700643 }
644 else
645 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000646 out << "No loop condition\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700647 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000648
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700649 OutputTreeText(sink, node, mDepth);
650 if (node->getBody())
651 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000652 out << "Loop Body\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000653 node->getBody()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700654 }
655 else
656 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000657 out << "No loop body\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700658 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000659
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700660 if (node->getExpression())
661 {
662 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000663 out << "Loop Terminal Expression\n";
alokp@chromium.org52813552010-11-16 18:36:09 +0000664 node->getExpression()->traverse(this);
alokp@chromium.org76b82082010-03-24 17:59:39 +0000665 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000666
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700667 --mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668
alokp@chromium.org76b82082010-03-24 17:59:39 +0000669 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000670}
671
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700672bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700674 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000675
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700676 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000677
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700678 switch (node->getFlowOp())
679 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500680 case EOpKill:
681 out << "Branch: Kill";
682 break;
683 case EOpBreak:
684 out << "Branch: Break";
685 break;
686 case EOpContinue:
687 out << "Branch: Continue";
688 break;
689 case EOpReturn:
690 out << "Branch: Return";
691 break;
692 default:
693 out << "Branch: Unknown Branch";
694 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000695 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000696
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700697 if (node->getExpression())
698 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000699 out << " with expression\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700700 ++mDepth;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000701 node->getExpression()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700702 --mDepth;
703 }
704 else
705 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000706 out << "\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700707 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000708
alokp@chromium.org76b82082010-03-24 17:59:39 +0000709 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000710}
711
712//
713// This function is the one to call externally to start the traversal.
714// Individual functions can be initialized to 0 to skip processing of that
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200715// type of node. Its children will still be processed.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716//
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200717void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000718{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200719 TOutputTraverser it(infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000720
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200721 ASSERT(root);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000722
alokp@chromium.org76b82082010-03-24 17:59:39 +0000723 root->traverse(&it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000724}
Jamie Madill45bcc782016-11-07 13:58:48 -0500725
726} // namespace sh