blob: 942eadcfa770f8012fda7fee10fc2338ad8cb38f [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
Zhenyao Moe40d1e92014-07-16 17:40:36 -070010namespace
11{
12
Olli Etuaho5f579b12015-08-14 17:44:43 +030013void OutputFunction(TInfoSinkBase &out, const char *str, TIntermAggregate *node)
14{
15 const char *internal = node->getNameObj().isInternal() ? " (internal function)" : "";
16 out << str << internal << ": " << node->getNameObj().getString();
17}
18
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019//
20// Two purposes:
21// 1. Show an example of how to iterate tree. Functions can
22// also directly call Traverse() on children themselves to
23// have finer grained control over the process than shown here.
24// See the last function for how to get started.
25// 2. Print out a text based description of the tree.
26//
27
28//
29// Use this class to carry along data from node to node in
30// the traversal
31//
Zhenyao Moe40d1e92014-07-16 17:40:36 -070032class TOutputTraverser : public TIntermTraverser
33{
34 public:
35 TOutputTraverser(TInfoSinkBase &i)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +030036 : TIntermTraverser(true, false, false),
37 sink(i)
38 {
39 }
alokp@chromium.org7beea402010-09-15 21:18:34 +000040 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;
45 bool visitBinary(Visit visit, TIntermBinary *) override;
46 bool visitUnary(Visit visit, TIntermUnary *) override;
Olli Etuahod0bad2c2016-09-09 18:01:16 +030047 bool visitTernary(Visit visit, TIntermTernary *node) override;
Corentin Walleze5a1f272015-08-21 02:58:25 +020048 bool visitSelection(Visit visit, TIntermSelection *) override;
49 bool visitAggregate(Visit visit, TIntermAggregate *) override;
50 bool visitLoop(Visit visit, TIntermLoop *) override;
51 bool visitBranch(Visit visit, TIntermBranch *) override;
Olli Etuahod0bad2c2016-09-09 18:01:16 +030052 // TODO: Add missing visit functions
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053};
54
Zhenyao Moe40d1e92014-07-16 17:40:36 -070055//
56// Helper functions for printing, not part of traversing.
57//
58void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
59{
60 int i;
61
62 sink.location(node->getLine());
63
64 for (i = 0; i < depth; ++i)
65 sink << " ";
66}
67
68} // namespace anonymous
69
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000070//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000071// The rest of the file are the traversal functions. The last one
72// is the one that starts the traversal.
73//
74// Return true from interior nodes to have the external traversal
75// continue on to children. If you process children yourself,
76// return false.
77//
78
Zhenyao Moe40d1e92014-07-16 17:40:36 -070079void TOutputTraverser::visitSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000080{
Zhenyao Moe40d1e92014-07-16 17:40:36 -070081 OutputTreeText(sink, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000082
alokp@chromium.org7beea402010-09-15 21:18:34 +000083 sink << "'" << node->getSymbol() << "' ";
84 sink << "(" << node->getCompleteString() << ")\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000085}
86
Zhenyao Moe40d1e92014-07-16 17:40:36 -070087bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000088{
alokp@chromium.org7beea402010-09-15 21:18:34 +000089 TInfoSinkBase& out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000090
Zhenyao Moe40d1e92014-07-16 17:40:36 -070091 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000092
Zhenyao Moe40d1e92014-07-16 17:40:36 -070093 switch (node->getOp())
94 {
95 case EOpAssign:
96 out << "move second child to first child";
97 break;
98 case EOpInitialize:
99 out << "initialize first child with second child";
100 break;
101 case EOpAddAssign:
102 out << "add second child into first child";
103 break;
104 case EOpSubAssign:
105 out << "subtract second child into first child";
106 break;
107 case EOpMulAssign:
108 out << "multiply second child into first child";
109 break;
110 case EOpVectorTimesMatrixAssign:
111 out << "matrix mult second child into first child";
112 break;
113 case EOpVectorTimesScalarAssign:
114 out << "vector scale second child into first child";
115 break;
116 case EOpMatrixTimesScalarAssign:
117 out << "matrix scale second child into first child";
118 break;
119 case EOpMatrixTimesMatrixAssign:
120 out << "matrix mult second child into first child";
121 break;
122 case EOpDivAssign:
123 out << "divide second child into first child";
124 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200125 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000126 out << "modulo second child into first child";
127 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200128 case EOpBitShiftLeftAssign:
129 out << "bit-wise shift first child left by second child";
130 break;
131 case EOpBitShiftRightAssign:
132 out << "bit-wise shift first child right by second child";
133 break;
134 case EOpBitwiseAndAssign:
135 out << "bit-wise and second child into first child";
136 break;
137 case EOpBitwiseXorAssign:
138 out << "bit-wise xor second child into first child";
139 break;
140 case EOpBitwiseOrAssign:
141 out << "bit-wise or second child into first child";
142 break;
143
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700144 case EOpIndexDirect:
145 out << "direct index";
146 break;
147 case EOpIndexIndirect:
148 out << "indirect index";
149 break;
150 case EOpIndexDirectStruct:
151 out << "direct index for structure";
152 break;
153 case EOpIndexDirectInterfaceBlock:
154 out << "direct index for interface block";
155 break;
156 case EOpVectorSwizzle:
157 out << "vector swizzle";
158 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700160 case EOpAdd:
161 out << "add";
162 break;
163 case EOpSub:
164 out << "subtract";
165 break;
166 case EOpMul:
167 out << "component-wise multiply";
168 break;
169 case EOpDiv:
170 out << "divide";
171 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200172 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000173 out << "modulo";
174 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200175 case EOpBitShiftLeft:
176 out << "bit-wise shift left";
177 break;
178 case EOpBitShiftRight:
179 out << "bit-wise shift right";
180 break;
181 case EOpBitwiseAnd:
182 out << "bit-wise and";
183 break;
184 case EOpBitwiseXor:
185 out << "bit-wise xor";
186 break;
187 case EOpBitwiseOr:
188 out << "bit-wise or";
189 break;
190
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700191 case EOpEqual:
192 out << "Compare Equal";
193 break;
194 case EOpNotEqual:
195 out << "Compare Not Equal";
196 break;
197 case EOpLessThan:
198 out << "Compare Less Than";
199 break;
200 case EOpGreaterThan:
201 out << "Compare Greater Than";
202 break;
203 case EOpLessThanEqual:
204 out << "Compare Less Than or Equal";
205 break;
206 case EOpGreaterThanEqual:
207 out << "Compare Greater Than or Equal";
208 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000209
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700210 case EOpVectorTimesScalar:
211 out << "vector-scale";
212 break;
213 case EOpVectorTimesMatrix:
214 out << "vector-times-matrix";
215 break;
216 case EOpMatrixTimesVector:
217 out << "matrix-times-vector";
218 break;
219 case EOpMatrixTimesScalar:
220 out << "matrix-scale";
221 break;
222 case EOpMatrixTimesMatrix:
223 out << "matrix-multiply";
224 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700226 case EOpLogicalOr:
227 out << "logical-or";
228 break;
229 case EOpLogicalXor:
230 out << "logical-xor";
231 break;
232 case EOpLogicalAnd:
233 out << "logical-and";
234 break;
235 default:
236 out << "<unknown op>";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000237 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000238
alokp@chromium.org7beea402010-09-15 21:18:34 +0000239 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000240
alokp@chromium.org7beea402010-09-15 21:18:34 +0000241 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242
Jamie Madill60305f12014-11-18 13:25:26 -0500243 // Special handling for direct indexes. Because constant
244 // unions are not aware they are struct indexes, treat them
245 // here where we have that contextual knowledge.
246 if (node->getOp() == EOpIndexDirectStruct ||
247 node->getOp() == EOpIndexDirectInterfaceBlock)
248 {
249 mDepth++;
250 node->getLeft()->traverse(this);
251 mDepth--;
252
253 TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
254 ASSERT(intermConstantUnion);
255
256 OutputTreeText(out, intermConstantUnion, mDepth + 1);
257
258 // The following code finds the field name from the constant union
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400259 const TConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer();
Jamie Madill60305f12014-11-18 13:25:26 -0500260 const TStructure *structure = node->getLeft()->getType().getStruct();
261 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
262 ASSERT(structure || interfaceBlock);
263
264 const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
265
266 const TField *field = fields[constantUnion->getIConst()];
267
268 out << constantUnion->getIConst() << " (field '" << field->name() << "')";
269
270 return false;
271 }
272
alokp@chromium.org76b82082010-03-24 17:59:39 +0000273 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274}
275
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700276bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277{
alokp@chromium.org7beea402010-09-15 21:18:34 +0000278 TInfoSinkBase& out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700280 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700282 switch (node->getOp())
283 {
284 case EOpNegative: out << "Negate value"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700285 case EOpPositive: out << "Positive sign"; break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700286 case EOpVectorLogicalNot:
287 case EOpLogicalNot: out << "Negate conditional"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200288 case EOpBitwiseNot: out << "bit-wise not"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700290 case EOpPostIncrement: out << "Post-Increment"; break;
291 case EOpPostDecrement: out << "Post-Decrement"; break;
292 case EOpPreIncrement: out << "Pre-Increment"; break;
293 case EOpPreDecrement: out << "Pre-Decrement"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700295 case EOpRadians: out << "radians"; break;
296 case EOpDegrees: out << "degrees"; break;
297 case EOpSin: out << "sine"; break;
298 case EOpCos: out << "cosine"; break;
299 case EOpTan: out << "tangent"; break;
300 case EOpAsin: out << "arc sine"; break;
301 case EOpAcos: out << "arc cosine"; break;
302 case EOpAtan: out << "arc tangent"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200304 case EOpSinh: out << "hyperbolic sine"; break;
305 case EOpCosh: out << "hyperbolic cosine"; break;
306 case EOpTanh: out << "hyperbolic tangent"; break;
307 case EOpAsinh: out << "arc hyperbolic sine"; break;
308 case EOpAcosh: out << "arc hyperbolic cosine"; break;
309 case EOpAtanh: out << "arc hyperbolic tangent"; break;
310
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700311 case EOpExp: out << "exp"; break;
312 case EOpLog: out << "log"; break;
313 case EOpExp2: out << "exp2"; break;
314 case EOpLog2: out << "log2"; break;
315 case EOpSqrt: out << "sqrt"; break;
316 case EOpInverseSqrt: out << "inverse sqrt"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700318 case EOpAbs: out << "Absolute value"; break;
319 case EOpSign: out << "Sign"; break;
320 case EOpFloor: out << "Floor"; break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800321 case EOpTrunc: out << "Truncate"; break;
322 case EOpRound: out << "Round"; break;
323 case EOpRoundEven: out << "Round half even"; break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700324 case EOpCeil: out << "Ceiling"; break;
325 case EOpFract: out << "Fraction"; break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530326 case EOpIsNan: out << "Is not a number"; break;
327 case EOpIsInf: out << "Is infinity"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200329 case EOpFloatBitsToInt: out << "float bits to int"; break;
330 case EOpFloatBitsToUint: out << "float bits to uint"; break;
331 case EOpIntBitsToFloat: out << "int bits to float"; break;
332 case EOpUintBitsToFloat: out << "uint bits to float"; break;
333
Olli Etuaho7700ff62015-01-15 12:16:29 +0200334 case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break;
335 case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break;
336 case EOpPackHalf2x16: out << "pack half 2x16"; break;
337
338 case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break;
339 case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break;
340 case EOpUnpackHalf2x16: out << "unpack half 2x16"; break;
341
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700342 case EOpLength: out << "length"; break;
343 case EOpNormalize: out << "normalize"; break;
344 // case EOpDPdx: out << "dPdx"; break;
345 // case EOpDPdy: out << "dPdy"; break;
346 // case EOpFwidth: out << "fwidth"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347
Olli Etuahoe39706d2014-12-30 16:40:36 +0200348 case EOpDeterminant: out << "determinant"; break;
349 case EOpTranspose: out << "transpose"; break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200350 case EOpInverse: out << "inverse"; break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200351
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700352 case EOpAny: out << "any"; break;
353 case EOpAll: out << "all"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700355 default:
356 out.prefix(EPrefixError);
357 out << "Bad unary op";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000358 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359
alokp@chromium.org7beea402010-09-15 21:18:34 +0000360 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361
alokp@chromium.org7beea402010-09-15 21:18:34 +0000362 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000363
alokp@chromium.org76b82082010-03-24 17:59:39 +0000364 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000365}
366
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700367bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000368{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700369 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700371 if (node->getOp() == EOpNull)
372 {
Jamie Madill075edd82013-07-08 13:30:19 -0400373 out.prefix(EPrefixError);
374 out << "node is still EOpNull!";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000375 return true;
376 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700378 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700380 switch (node->getOp())
381 {
382 case EOpSequence: out << "Sequence\n"; return true;
383 case EOpComma: out << "Comma\n"; return true;
Olli Etuaho5f579b12015-08-14 17:44:43 +0300384 case EOpFunction: OutputFunction(out, "Function Definition", node); break;
385 case EOpFunctionCall: OutputFunction(out, "Function Call", node); break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700386 case EOpParameters: out << "Function Parameters: "; break;
Olli Etuaho5f579b12015-08-14 17:44:43 +0300387 case EOpPrototype: OutputFunction(out, "Function Prototype", node); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700389 case EOpConstructFloat: out << "Construct float"; break;
390 case EOpConstructVec2: out << "Construct vec2"; break;
391 case EOpConstructVec3: out << "Construct vec3"; break;
392 case EOpConstructVec4: out << "Construct vec4"; break;
393 case EOpConstructBool: out << "Construct bool"; break;
394 case EOpConstructBVec2: out << "Construct bvec2"; break;
395 case EOpConstructBVec3: out << "Construct bvec3"; break;
396 case EOpConstructBVec4: out << "Construct bvec4"; break;
397 case EOpConstructInt: out << "Construct int"; break;
398 case EOpConstructIVec2: out << "Construct ivec2"; break;
399 case EOpConstructIVec3: out << "Construct ivec3"; break;
400 case EOpConstructIVec4: out << "Construct ivec4"; break;
401 case EOpConstructUInt: out << "Construct uint"; break;
402 case EOpConstructUVec2: out << "Construct uvec2"; break;
403 case EOpConstructUVec3: out << "Construct uvec3"; break;
404 case EOpConstructUVec4: out << "Construct uvec4"; break;
405 case EOpConstructMat2: out << "Construct mat2"; break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400406 case EOpConstructMat2x3: out << "Construct mat2x3"; break;
407 case EOpConstructMat2x4: out << "Construct mat2x4"; break;
408 case EOpConstructMat3x2: out << "Construct mat3x2"; break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700409 case EOpConstructMat3: out << "Construct mat3"; break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400410 case EOpConstructMat3x4: out << "Construct mat3x4"; break;
411 case EOpConstructMat4x2: out << "Construct mat4x2"; break;
412 case EOpConstructMat4x3: out << "Construct mat4x3"; break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700413 case EOpConstructMat4: out << "Construct mat4"; break;
414 case EOpConstructStruct: out << "Construct structure"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700416 case EOpLessThan: out << "Compare Less Than"; break;
417 case EOpGreaterThan: out << "Compare Greater Than"; break;
418 case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
419 case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
420 case EOpVectorEqual: out << "Equal"; break;
421 case EOpVectorNotEqual: out << "NotEqual"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700423 case EOpMod: out << "mod"; break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200424 case EOpModf: out << "modf"; break;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700425 case EOpPow: out << "pow"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700427 case EOpAtan: out << "arc tangent"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000428
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700429 case EOpMin: out << "min"; break;
430 case EOpMax: out << "max"; break;
431 case EOpClamp: out << "clamp"; break;
432 case EOpMix: out << "mix"; break;
433 case EOpStep: out << "step"; break;
434 case EOpSmoothStep: out << "smoothstep"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700436 case EOpDistance: out << "distance"; break;
437 case EOpDot: out << "dot-product"; break;
438 case EOpCross: out << "cross-product"; break;
439 case EOpFaceForward: out << "face-forward"; break;
440 case EOpReflect: out << "reflect"; break;
441 case EOpRefract: out << "refract"; break;
442 case EOpMul: out << "component-wise multiply"; break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443
Olli Etuahoe39706d2014-12-30 16:40:36 +0200444 case EOpOuterProduct: out << "outer product"; break;
445
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700446 case EOpDeclaration: out << "Declaration: "; break;
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400447 case EOpInvariantDeclaration: out << "Invariant Declaration: "; break;
daniel@transgaming.coma9ae4aa2011-10-19 13:29:27 +0000448
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700449 default:
450 out.prefix(EPrefixError);
451 out << "Bad aggregation op";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000452 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453
alokp@chromium.org76b82082010-03-24 17:59:39 +0000454 if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000455 out << " (" << node->getCompleteString() << ")";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456
alokp@chromium.org7beea402010-09-15 21:18:34 +0000457 out << "\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458
alokp@chromium.org76b82082010-03-24 17:59:39 +0000459 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000460}
461
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300462bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
463{
464 TInfoSinkBase &out = sink;
465
466 OutputTreeText(out, node, mDepth);
467
468 out << "Ternary selection";
469 out << " (" << node->getCompleteString() << ")\n";
470
471 ++mDepth;
472
473 OutputTreeText(sink, node, mDepth);
474 out << "Condition\n";
475 node->getCondition()->traverse(this);
476
477 OutputTreeText(sink, node, mDepth);
478 if (node->getTrueExpression())
479 {
480 out << "true case\n";
481 node->getTrueExpression()->traverse(this);
482 }
483 if (node->getFalseExpression())
484 {
485 OutputTreeText(sink, node, mDepth);
486 out << "false case\n";
487 node->getFalseExpression()->traverse(this);
488 }
489
490 --mDepth;
491
492 return false;
493}
494
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700495bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700497 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000498
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700499 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000500
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300501 out << "If test\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700503 ++mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000504
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700505 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000506 out << "Condition\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000507 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700509 OutputTreeText(sink, node, mDepth);
510 if (node->getTrueBlock())
511 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000512 out << "true case\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000513 node->getTrueBlock()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700514 }
515 else
516 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000517 out << "true case is null\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700518 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700520 if (node->getFalseBlock())
521 {
522 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000523 out << "false case\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000524 node->getFalseBlock()->traverse(this);
525 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000526
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700527 --mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000528
alokp@chromium.org76b82082010-03-24 17:59:39 +0000529 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530}
531
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700532void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000533{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700534 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000535
Jamie Madill94bf7f22013-07-08 13:31:15 -0400536 size_t size = node->getType().getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000537
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700538 for (size_t i = 0; i < size; i++)
539 {
540 OutputTreeText(out, node, mDepth);
541 switch (node->getUnionArrayPointer()[i].getType())
542 {
543 case EbtBool:
544 if (node->getUnionArrayPointer()[i].getBConst())
545 out << "true";
546 else
547 out << "false";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700549 out << " (" << "const bool" << ")";
550 out << "\n";
551 break;
552 case EbtFloat:
553 out << node->getUnionArrayPointer()[i].getFConst();
554 out << " (const float)\n";
555 break;
556 case EbtInt:
557 out << node->getUnionArrayPointer()[i].getIConst();
558 out << " (const int)\n";
559 break;
560 case EbtUInt:
561 out << node->getUnionArrayPointer()[i].getUConst();
562 out << " (const uint)\n";
563 break;
564 default:
565 out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
566 break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000567 }
568 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000569}
570
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700571bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *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
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700575 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576
alokp@chromium.org7beea402010-09-15 21:18:34 +0000577 out << "Loop with condition ";
alokp@chromium.org52813552010-11-16 18:36:09 +0000578 if (node->getType() == ELoopDoWhile)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000579 out << "not ";
580 out << "tested first\n";
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000581
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700582 ++mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700584 OutputTreeText(sink, node, mDepth);
585 if (node->getCondition())
586 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000587 out << "Loop Condition\n";
alokp@chromium.org52813552010-11-16 18:36:09 +0000588 node->getCondition()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700589 }
590 else
591 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000592 out << "No loop condition\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700593 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700595 OutputTreeText(sink, node, mDepth);
596 if (node->getBody())
597 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000598 out << "Loop Body\n";
alokp@chromium.org76b82082010-03-24 17:59:39 +0000599 node->getBody()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700600 }
601 else
602 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000603 out << "No loop body\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700604 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000605
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700606 if (node->getExpression())
607 {
608 OutputTreeText(sink, node, mDepth);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000609 out << "Loop Terminal Expression\n";
alokp@chromium.org52813552010-11-16 18:36:09 +0000610 node->getExpression()->traverse(this);
alokp@chromium.org76b82082010-03-24 17:59:39 +0000611 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000612
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700613 --mDepth;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000614
alokp@chromium.org76b82082010-03-24 17:59:39 +0000615 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000616}
617
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700618bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000619{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700620 TInfoSinkBase &out = sink;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700622 OutputTreeText(out, node, mDepth);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700624 switch (node->getFlowOp())
625 {
626 case EOpKill: out << "Branch: Kill"; break;
627 case EOpBreak: out << "Branch: Break"; break;
628 case EOpContinue: out << "Branch: Continue"; break;
629 case EOpReturn: out << "Branch: Return"; break;
630 default: out << "Branch: Unknown Branch"; break;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000631 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700633 if (node->getExpression())
634 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000635 out << " with expression\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700636 ++mDepth;
alokp@chromium.org76b82082010-03-24 17:59:39 +0000637 node->getExpression()->traverse(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700638 --mDepth;
639 }
640 else
641 {
alokp@chromium.org7beea402010-09-15 21:18:34 +0000642 out << "\n";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700643 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644
alokp@chromium.org76b82082010-03-24 17:59:39 +0000645 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646}
647
648//
649// This function is the one to call externally to start the traversal.
650// Individual functions can be initialized to 0 to skip processing of that
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200651// type of node. Its children will still be processed.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000652//
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200653void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000654{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200655 TOutputTraverser it(infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000656
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200657 ASSERT(root);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658
alokp@chromium.org76b82082010-03-24 17:59:39 +0000659 root->traverse(&it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000660}