blob: 1e623d13627785de4d32469e2c4e55e3d90c913e [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madillb1a85f42014-08-19 15:23:24 -04007#include "compiler/translator/IntermNode.h"
Olli Etuahod4f303e2015-05-20 17:09:06 +03008#include "compiler/translator/InfoSink.h"
Olli Etuaho217fe6e2015-08-05 13:25:08 +03009#include "compiler/translator/SymbolTable.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000010
Olli Etuaho27446bd2015-08-10 14:59:53 +030011void TIntermSymbol::traverse(TIntermTraverser *it)
12{
13 it->traverseSymbol(this);
14}
15
16void TIntermRaw::traverse(TIntermTraverser *it)
17{
18 it->traverseRaw(this);
19}
20
21void TIntermConstantUnion::traverse(TIntermTraverser *it)
22{
23 it->traverseConstantUnion(this);
24}
25
Olli Etuahob6fa0432016-09-28 16:28:05 +010026void TIntermSwizzle::traverse(TIntermTraverser *it)
27{
28 it->traverseSwizzle(this);
29}
30
Olli Etuaho27446bd2015-08-10 14:59:53 +030031void TIntermBinary::traverse(TIntermTraverser *it)
32{
33 it->traverseBinary(this);
34}
35
36void TIntermUnary::traverse(TIntermTraverser *it)
37{
38 it->traverseUnary(this);
39}
40
Olli Etuahod0bad2c2016-09-09 18:01:16 +030041void TIntermTernary::traverse(TIntermTraverser *it)
42{
43 it->traverseTernary(this);
44}
45
Olli Etuaho57961272016-09-14 13:57:46 +030046void TIntermIfElse::traverse(TIntermTraverser *it)
Olli Etuaho27446bd2015-08-10 14:59:53 +030047{
Olli Etuaho57961272016-09-14 13:57:46 +030048 it->traverseIfElse(this);
Olli Etuaho27446bd2015-08-10 14:59:53 +030049}
50
51void TIntermSwitch::traverse(TIntermTraverser *it)
52{
53 it->traverseSwitch(this);
54}
55
56void TIntermCase::traverse(TIntermTraverser *it)
57{
58 it->traverseCase(this);
59}
60
Olli Etuaho336b1472016-10-05 16:37:55 +010061void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
62{
63 it->traverseFunctionDefinition(this);
64}
65
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010066void TIntermBlock::traverse(TIntermTraverser *it)
67{
68 it->traverseBlock(this);
69}
70
Olli Etuaho13389b62016-10-16 11:48:18 +010071void TIntermDeclaration::traverse(TIntermTraverser *it)
72{
73 it->traverseDeclaration(this);
74}
75
Olli Etuaho27446bd2015-08-10 14:59:53 +030076void TIntermAggregate::traverse(TIntermTraverser *it)
77{
78 it->traverseAggregate(this);
79}
80
81void TIntermLoop::traverse(TIntermTraverser *it)
82{
83 it->traverseLoop(this);
84}
85
86void TIntermBranch::traverse(TIntermTraverser *it)
87{
88 it->traverseBranch(this);
89}
90
Jamie Madill03d863c2016-07-27 18:15:53 -040091TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
92 : preVisit(preVisit),
93 inVisit(inVisit),
94 postVisit(postVisit),
95 mDepth(0),
96 mMaxDepth(0),
97 mInGlobalScope(true),
98 mTemporaryIndex(nullptr)
99{
100}
101
102TIntermTraverser::~TIntermTraverser()
103{
104}
105
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100106void TIntermTraverser::pushParentBlock(TIntermBlock *node)
Olli Etuaho56eea882015-05-18 12:41:03 +0300107{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300108 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +0300109}
110
111void TIntermTraverser::incrementParentBlockPos()
112{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300113 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +0300114}
115
116void TIntermTraverser::popParentBlock()
117{
118 ASSERT(!mParentBlockStack.empty());
119 mParentBlockStack.pop_back();
120}
121
122void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
123{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300124 TIntermSequence emptyInsertionsAfter;
125 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
126}
127
128void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
129 const TIntermSequence &insertionsAfter)
130{
Olli Etuaho56eea882015-05-18 12:41:03 +0300131 ASSERT(!mParentBlockStack.empty());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300132 NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
133 insertionsBefore, insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300134 mInsertions.push_back(insert);
135}
136
Jamie Madill1048e432016-07-23 18:51:28 -0400137void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
138{
139 TIntermSequence insertions;
140 insertions.push_back(statement);
141 insertStatementsInParentBlock(insertions);
142}
143
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300144TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300145{
146 // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
147 TInfoSinkBase symbolNameOut;
148 ASSERT(mTemporaryIndex != nullptr);
149 symbolNameOut << "s" << (*mTemporaryIndex);
150 TString symbolName = symbolNameOut.c_str();
151
152 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
153 node->setInternal(true);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300154 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300155 return node;
156}
157
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300158TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
159{
160 return createTempSymbol(type, EvqTemporary);
161}
162
Olli Etuaho13389b62016-10-16 11:48:18 +0100163TIntermDeclaration *TIntermTraverser::createTempDeclaration(const TType &type)
Olli Etuaho4f1af782015-05-25 11:55:07 +0300164{
Olli Etuaho13389b62016-10-16 11:48:18 +0100165 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
166 tempDeclaration->appendDeclarator(createTempSymbol(type));
Olli Etuaho4f1af782015-05-25 11:55:07 +0300167 return tempDeclaration;
168}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300169
Olli Etuaho13389b62016-10-16 11:48:18 +0100170TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer,
171 TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300172{
173 ASSERT(initializer != nullptr);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300174 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuaho13389b62016-10-16 11:48:18 +0100175 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300176 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
Olli Etuaho13389b62016-10-16 11:48:18 +0100177 tempDeclaration->appendDeclarator(tempInit);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300178 return tempDeclaration;
179}
180
Olli Etuaho13389b62016-10-16 11:48:18 +0100181TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300182{
183 return createTempInitDeclaration(initializer, EvqTemporary);
184}
185
Olli Etuahod4f303e2015-05-20 17:09:06 +0300186TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
187{
188 ASSERT(rightNode != nullptr);
189 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300190 TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300191 return assignment;
192}
193
194void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
195{
196 mTemporaryIndex = temporaryIndex;
197}
198
199void TIntermTraverser::nextTemporaryIndex()
200{
201 ASSERT(mTemporaryIndex != nullptr);
202 ++(*mTemporaryIndex);
203}
204
Olli Etuaho5f579b12015-08-14 17:44:43 +0300205void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300206{
207 mFunctionMap[name] = paramSequence;
208}
209
Olli Etuaho3fc93372015-08-11 14:50:59 +0300210bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300211{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300212 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuahobd674552016-10-06 13:28:42 +0100213 return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
214 mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300215}
216
Olli Etuaho3fc93372015-08-11 14:50:59 +0300217TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300218{
219 ASSERT(isInFunctionMap(callNode));
Olli Etuahobd674552016-10-06 13:28:42 +0100220 return mFunctionMap[callNode->getFunctionSymbolInfo()->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300221}
222
Olli Etuaho3fc93372015-08-11 14:50:59 +0300223void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300224{
225 mInFunctionCallOutParameter = inOutParameter;
226}
227
Olli Etuaho3fc93372015-08-11 14:50:59 +0300228bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300229{
230 return mInFunctionCallOutParameter;
231}
232
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233//
234// Traverse the intermediate representation tree, and
235// call a node type specific function for each node.
236// Done recursively through the member function Traverse().
237// Node types can be skipped if their function to call is 0,
238// but their subtree will still be traversed.
239// Nodes with children can have their whole subtree skipped
240// if preVisit is turned on and the type specific function
241// returns false.
242//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243
244//
245// Traversal functions for terminals are straighforward....
246//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300247void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000248{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300249 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000250}
251
Olli Etuaho27446bd2015-08-10 14:59:53 +0300252void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000253{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300254 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255}
256
Olli Etuahob6fa0432016-09-28 16:28:05 +0100257void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
258{
259 bool visit = true;
260
261 if (preVisit)
262 visit = visitSwizzle(PreVisit, node);
263
264 if (visit)
265 {
266 incrementDepth(node);
267
268 node->getOperand()->traverse(this);
269
270 decrementDepth();
271 }
272
273 if (visit && postVisit)
274 visitSwizzle(PostVisit, node);
275}
276
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277//
278// Traverse a binary node.
279//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300280void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700282 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700284 //
285 // visit the node before children if pre-visiting.
286 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300287 if (preVisit)
288 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700290 //
291 // Visit the children, in the right order.
292 //
293 if (visit)
294 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300295 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296
Olli Etuaho3fc93372015-08-11 14:50:59 +0300297 if (node->getLeft())
298 node->getLeft()->traverse(this);
299
300 if (inVisit)
301 visit = visitBinary(InVisit, node);
302
303 if (visit && node->getRight())
304 node->getRight()->traverse(this);
305
306 decrementDepth();
307 }
308
309 //
310 // Visit the node after the children, if requested and the traversal
311 // hasn't been cancelled yet.
312 //
313 if (visit && postVisit)
314 visitBinary(PostVisit, node);
315}
316
317void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
318{
319 bool visit = true;
320
321 //
322 // visit the node before children if pre-visiting.
323 //
324 if (preVisit)
325 visit = visitBinary(PreVisit, node);
326
327 //
328 // Visit the children, in the right order.
329 //
330 if (visit)
331 {
332 incrementDepth(node);
333
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300334 // Some binary operations like indexing can be inside an expression which must be an
335 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300336 bool parentOperatorRequiresLValue = operatorRequiresLValue();
337 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
338 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300339 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300340 ASSERT(!isLValueRequiredHere());
341 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300342 }
343
Olli Etuaho27446bd2015-08-10 14:59:53 +0300344 if (node->getLeft())
345 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346
Olli Etuaho27446bd2015-08-10 14:59:53 +0300347 if (inVisit)
348 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349
Olli Etuaho27446bd2015-08-10 14:59:53 +0300350 if (node->isAssignment())
351 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300352
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300353 // Index is not required to be an l-value even when the surrounding expression is required
354 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300355 TOperator op = node->getOp();
356 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
357 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300358 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300359 setOperatorRequiresLValue(false);
360 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300361 }
362
Olli Etuaho27446bd2015-08-10 14:59:53 +0300363 if (visit && node->getRight())
364 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700365
Olli Etuaho27446bd2015-08-10 14:59:53 +0300366 setOperatorRequiresLValue(parentOperatorRequiresLValue);
367 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300368
Olli Etuaho27446bd2015-08-10 14:59:53 +0300369 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700370 }
371
372 //
373 // Visit the node after the children, if requested and the traversal
374 // hasn't been cancelled yet.
375 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300376 if (visit && postVisit)
377 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000378}
379
380//
381// Traverse a unary node. Same comments in binary node apply here.
382//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300383void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000384{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700385 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386
Olli Etuaho27446bd2015-08-10 14:59:53 +0300387 if (preVisit)
388 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000389
Olli Etuahoa26ad582015-08-04 13:51:47 +0300390 if (visit)
391 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300392 incrementDepth(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300393
Olli Etuaho3fc93372015-08-11 14:50:59 +0300394 node->getOperand()->traverse(this);
395
396 decrementDepth();
397 }
398
399 if (visit && postVisit)
400 visitUnary(PostVisit, node);
401}
402
403void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
404{
405 bool visit = true;
406
407 if (preVisit)
408 visit = visitUnary(PreVisit, node);
409
410 if (visit)
411 {
412 incrementDepth(node);
413
Olli Etuaho27446bd2015-08-10 14:59:53 +0300414 ASSERT(!operatorRequiresLValue());
415 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300416 {
417 case EOpPostIncrement:
418 case EOpPostDecrement:
419 case EOpPreIncrement:
420 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300421 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300422 break;
423 default:
424 break;
425 }
426
Olli Etuaho27446bd2015-08-10 14:59:53 +0300427 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300428
Olli Etuaho27446bd2015-08-10 14:59:53 +0300429 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300430
Olli Etuaho27446bd2015-08-10 14:59:53 +0300431 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700432 }
433
Olli Etuaho27446bd2015-08-10 14:59:53 +0300434 if (visit && postVisit)
435 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436}
437
Olli Etuaho336b1472016-10-05 16:37:55 +0100438// Traverse a function definition node.
439void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
440{
441 bool visit = true;
442
443 if (preVisit)
444 visit = visitFunctionDefinition(PreVisit, node);
445
446 if (visit)
447 {
448 incrementDepth(node);
449 mInGlobalScope = false;
450
451 node->getFunctionParameters()->traverse(this);
452 if (inVisit)
453 visit = visitFunctionDefinition(InVisit, node);
454 node->getBody()->traverse(this);
455
456 mInGlobalScope = true;
457 decrementDepth();
458 }
459
460 if (visit && postVisit)
461 visitFunctionDefinition(PostVisit, node);
462}
463
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100464// Traverse a block node.
465void TIntermTraverser::traverseBlock(TIntermBlock *node)
466{
467 bool visit = true;
468
469 TIntermSequence *sequence = node->getSequence();
470
471 if (preVisit)
472 visit = visitBlock(PreVisit, node);
473
474 if (visit)
475 {
476 incrementDepth(node);
477 pushParentBlock(node);
478
479 for (auto *child : *sequence)
480 {
481 child->traverse(this);
482 if (visit && inVisit)
483 {
484 if (child != sequence->back())
485 visit = visitBlock(InVisit, node);
486 }
487
488 incrementParentBlockPos();
489 }
490
491 popParentBlock();
492 decrementDepth();
493 }
494
495 if (visit && postVisit)
496 visitBlock(PostVisit, node);
497}
498
Olli Etuaho13389b62016-10-16 11:48:18 +0100499// Traverse a declaration node.
500void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
501{
502 bool visit = true;
503
504 TIntermSequence *sequence = node->getSequence();
505
506 if (preVisit)
507 visit = visitDeclaration(PreVisit, node);
508
509 if (visit)
510 {
511 incrementDepth(node);
512
513 for (auto *child : *sequence)
514 {
515 child->traverse(this);
516 if (visit && inVisit)
517 {
518 if (child != sequence->back())
519 visit = visitDeclaration(InVisit, node);
520 }
521 }
522
523 decrementDepth();
524 }
525
526 if (visit && postVisit)
527 visitDeclaration(PostVisit, node);
528}
529
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000530// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300531void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700533 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000534
Olli Etuaho27446bd2015-08-10 14:59:53 +0300535 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300536
537 if (preVisit)
538 visit = visitAggregate(PreVisit, node);
539
540 if (visit)
541 {
542 incrementDepth(node);
543
Olli Etuaho3fc93372015-08-11 14:50:59 +0300544 for (auto *child : *sequence)
545 {
546 child->traverse(this);
547 if (visit && inVisit)
548 {
549 if (child != sequence->back())
550 visit = visitAggregate(InVisit, node);
551 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300552 }
553
Olli Etuaho3fc93372015-08-11 14:50:59 +0300554 decrementDepth();
555 }
556
557 if (visit && postVisit)
558 visitAggregate(PostVisit, node);
559}
560
Olli Etuaho336b1472016-10-05 16:37:55 +0100561void TLValueTrackingTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
562{
563 TIntermAggregate *params = node->getFunctionParameters();
564 ASSERT(params != nullptr);
565 ASSERT(params->getOp() == EOpParameters);
566 addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), params->getSequence());
567
568 TIntermTraverser::traverseFunctionDefinition(node);
569}
570
Olli Etuaho3fc93372015-08-11 14:50:59 +0300571void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
572{
573 bool visit = true;
574
575 TIntermSequence *sequence = node->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +0100576 if (node->getOp() == EOpPrototype)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300577 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100578 addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300579 }
580
Olli Etuaho27446bd2015-08-10 14:59:53 +0300581 if (preVisit)
582 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700584 if (visit)
585 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300586 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300587 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700588 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300589 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300590 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300591 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300592 // The function is not user-defined - it is likely built-in texture function.
593 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300594 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700595 }
596 }
597
Olli Etuaho27446bd2015-08-10 14:59:53 +0300598 incrementDepth(node);
Olli Etuaho56eea882015-05-18 12:41:03 +0300599
Olli Etuahoa26ad582015-08-04 13:51:47 +0300600 if (inFunctionMap)
601 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300602 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300603 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300604 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300605 {
606 ASSERT(paramIter != params->end());
607 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300608 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300609
Olli Etuaho27446bd2015-08-10 14:59:53 +0300610 child->traverse(this);
611 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300612 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300613 if (child != sequence->back())
614 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300615 }
616
617 ++paramIter;
618 }
619
Olli Etuaho27446bd2015-08-10 14:59:53 +0300620 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300621 }
622 else
623 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300624 // Find the built-in function corresponding to this op so that we can determine the
625 // in/out qualifiers of its parameters.
626 TFunction *builtInFunc = nullptr;
627 TString opString = GetOperatorString(node->getOp());
628 if (!node->isConstructor() && !opString.empty())
629 {
630 // The return type doesn't affect the mangled name of the function, which is used
631 // to look it up from the symbol table.
632 TType dummyReturnType;
633 TFunction call(&opString, &dummyReturnType, node->getOp());
634 for (auto *child : *sequence)
635 {
636 TType *paramType = child->getAsTyped()->getTypePointer();
637 TConstParameter p(paramType);
638 call.addParameter(p);
639 }
640
641 TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
642 if (sym != nullptr && sym->isFunction())
643 {
644 builtInFunc = static_cast<TFunction *>(sym);
645 ASSERT(builtInFunc->getParamCount() == sequence->size());
646 }
647 }
648
649 size_t paramIndex = 0;
650
Olli Etuaho27446bd2015-08-10 14:59:53 +0300651 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300652 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300653 TQualifier qualifier = EvqIn;
654 if (builtInFunc != nullptr)
655 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
656 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300657 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300658
Olli Etuaho27446bd2015-08-10 14:59:53 +0300659 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300660 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300661 if (child != sequence->back())
662 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300663 }
664
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300665 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300666 }
667
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300668 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300669 }
670
Olli Etuaho27446bd2015-08-10 14:59:53 +0300671 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700672 }
673
Olli Etuaho27446bd2015-08-10 14:59:53 +0300674 if (visit && postVisit)
675 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000676}
677
678//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300679// Traverse a ternary node. Same comments in binary node apply here.
680//
681void TIntermTraverser::traverseTernary(TIntermTernary *node)
682{
683 bool visit = true;
684
685 if (preVisit)
686 visit = visitTernary(PreVisit, node);
687
688 if (visit)
689 {
690 incrementDepth(node);
691 node->getCondition()->traverse(this);
692 if (node->getTrueExpression())
693 node->getTrueExpression()->traverse(this);
694 if (node->getFalseExpression())
695 node->getFalseExpression()->traverse(this);
696 decrementDepth();
697 }
698
699 if (visit && postVisit)
700 visitTernary(PostVisit, node);
701}
702
Olli Etuaho57961272016-09-14 13:57:46 +0300703// Traverse an if-else node. Same comments in binary node apply here.
704void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000705{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700706 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000707
Olli Etuaho27446bd2015-08-10 14:59:53 +0300708 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300709 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000710
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700711 if (visit)
712 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300713 incrementDepth(node);
714 node->getCondition()->traverse(this);
715 if (node->getTrueBlock())
716 node->getTrueBlock()->traverse(this);
717 if (node->getFalseBlock())
718 node->getFalseBlock()->traverse(this);
719 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700720 }
721
Olli Etuaho27446bd2015-08-10 14:59:53 +0300722 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300723 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000724}
725
726//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200727// Traverse a switch node. Same comments in binary node apply here.
728//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300729void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200730{
731 bool visit = true;
732
Olli Etuaho27446bd2015-08-10 14:59:53 +0300733 if (preVisit)
734 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200735
736 if (visit)
737 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300738 incrementDepth(node);
739 node->getInit()->traverse(this);
740 if (inVisit)
741 visit = visitSwitch(InVisit, node);
742 if (visit && node->getStatementList())
743 node->getStatementList()->traverse(this);
744 decrementDepth();
Olli Etuahoa3a36662015-02-17 13:46:51 +0200745 }
746
Olli Etuaho27446bd2015-08-10 14:59:53 +0300747 if (visit && postVisit)
748 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200749}
750
751//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300752// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200753//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300754void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200755{
756 bool visit = true;
757
Olli Etuaho27446bd2015-08-10 14:59:53 +0300758 if (preVisit)
759 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200760
Olli Etuaho27446bd2015-08-10 14:59:53 +0300761 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100762 {
763 incrementDepth(node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300764 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100765 decrementDepth();
766 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200767
Olli Etuaho27446bd2015-08-10 14:59:53 +0300768 if (visit && postVisit)
769 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200770}
771
772//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000773// Traverse a loop node. Same comments in binary node apply here.
774//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300775void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000776{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700777 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000778
Olli Etuaho27446bd2015-08-10 14:59:53 +0300779 if (preVisit)
780 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000781
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700782 if (visit)
783 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300784 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785
Olli Etuaho27446bd2015-08-10 14:59:53 +0300786 if (node->getInit())
787 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000788
Olli Etuaho27446bd2015-08-10 14:59:53 +0300789 if (node->getCondition())
790 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000791
Olli Etuaho27446bd2015-08-10 14:59:53 +0300792 if (node->getBody())
793 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700794
Olli Etuaho27446bd2015-08-10 14:59:53 +0300795 if (node->getExpression())
796 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000797
Olli Etuaho27446bd2015-08-10 14:59:53 +0300798 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700799 }
800
Olli Etuaho27446bd2015-08-10 14:59:53 +0300801 if (visit && postVisit)
802 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000803}
804
805//
806// Traverse a branch node. Same comments in binary node apply here.
807//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300808void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000809{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700810 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811
Olli Etuaho27446bd2015-08-10 14:59:53 +0300812 if (preVisit)
813 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814
Olli Etuaho27446bd2015-08-10 14:59:53 +0300815 if (visit && node->getExpression())
816 {
817 incrementDepth(node);
818 node->getExpression()->traverse(this);
819 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700820 }
821
Olli Etuaho27446bd2015-08-10 14:59:53 +0300822 if (visit && postVisit)
823 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000824}
825
Olli Etuaho27446bd2015-08-10 14:59:53 +0300826void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400827{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300828 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400829}