blob: 72da6d2dadc8011a4058c286fbb168a2c28bb11c [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
26void TIntermBinary::traverse(TIntermTraverser *it)
27{
28 it->traverseBinary(this);
29}
30
31void TIntermUnary::traverse(TIntermTraverser *it)
32{
33 it->traverseUnary(this);
34}
35
Olli Etuahod0bad2c2016-09-09 18:01:16 +030036void TIntermTernary::traverse(TIntermTraverser *it)
37{
38 it->traverseTernary(this);
39}
40
Olli Etuaho57961272016-09-14 13:57:46 +030041void TIntermIfElse::traverse(TIntermTraverser *it)
Olli Etuaho27446bd2015-08-10 14:59:53 +030042{
Olli Etuaho57961272016-09-14 13:57:46 +030043 it->traverseIfElse(this);
Olli Etuaho27446bd2015-08-10 14:59:53 +030044}
45
46void TIntermSwitch::traverse(TIntermTraverser *it)
47{
48 it->traverseSwitch(this);
49}
50
51void TIntermCase::traverse(TIntermTraverser *it)
52{
53 it->traverseCase(this);
54}
55
56void TIntermAggregate::traverse(TIntermTraverser *it)
57{
58 it->traverseAggregate(this);
59}
60
61void TIntermLoop::traverse(TIntermTraverser *it)
62{
63 it->traverseLoop(this);
64}
65
66void TIntermBranch::traverse(TIntermTraverser *it)
67{
68 it->traverseBranch(this);
69}
70
Jamie Madill03d863c2016-07-27 18:15:53 -040071TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
72 : preVisit(preVisit),
73 inVisit(inVisit),
74 postVisit(postVisit),
75 mDepth(0),
76 mMaxDepth(0),
77 mInGlobalScope(true),
78 mTemporaryIndex(nullptr)
79{
80}
81
82TIntermTraverser::~TIntermTraverser()
83{
84}
85
Olli Etuaho56eea882015-05-18 12:41:03 +030086void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
87{
Olli Etuaho64f0be92015-06-03 17:38:34 +030088 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +030089}
90
91void TIntermTraverser::incrementParentBlockPos()
92{
Olli Etuaho64f0be92015-06-03 17:38:34 +030093 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +030094}
95
96void TIntermTraverser::popParentBlock()
97{
98 ASSERT(!mParentBlockStack.empty());
99 mParentBlockStack.pop_back();
100}
101
102void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
103{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300104 TIntermSequence emptyInsertionsAfter;
105 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
106}
107
108void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
109 const TIntermSequence &insertionsAfter)
110{
Olli Etuaho56eea882015-05-18 12:41:03 +0300111 ASSERT(!mParentBlockStack.empty());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300112 NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
113 insertionsBefore, insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300114 mInsertions.push_back(insert);
115}
116
Jamie Madill1048e432016-07-23 18:51:28 -0400117void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
118{
119 TIntermSequence insertions;
120 insertions.push_back(statement);
121 insertStatementsInParentBlock(insertions);
122}
123
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300124TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300125{
126 // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
127 TInfoSinkBase symbolNameOut;
128 ASSERT(mTemporaryIndex != nullptr);
129 symbolNameOut << "s" << (*mTemporaryIndex);
130 TString symbolName = symbolNameOut.c_str();
131
132 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
133 node->setInternal(true);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300134 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300135 return node;
136}
137
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300138TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
139{
140 return createTempSymbol(type, EvqTemporary);
141}
142
Olli Etuaho4f1af782015-05-25 11:55:07 +0300143TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
144{
145 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
146 tempDeclaration->getSequence()->push_back(createTempSymbol(type));
147 return tempDeclaration;
148}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300149
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300150TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300151{
152 ASSERT(initializer != nullptr);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300153 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300154 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300155 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300156 tempDeclaration->getSequence()->push_back(tempInit);
157 return tempDeclaration;
158}
159
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300160TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
161{
162 return createTempInitDeclaration(initializer, EvqTemporary);
163}
164
Olli Etuahod4f303e2015-05-20 17:09:06 +0300165TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
166{
167 ASSERT(rightNode != nullptr);
168 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300169 TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300170 return assignment;
171}
172
173void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
174{
175 mTemporaryIndex = temporaryIndex;
176}
177
178void TIntermTraverser::nextTemporaryIndex()
179{
180 ASSERT(mTemporaryIndex != nullptr);
181 ++(*mTemporaryIndex);
182}
183
Olli Etuaho5f579b12015-08-14 17:44:43 +0300184void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300185{
186 mFunctionMap[name] = paramSequence;
187}
188
Olli Etuaho3fc93372015-08-11 14:50:59 +0300189bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300190{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300191 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300192 return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300193}
194
Olli Etuaho3fc93372015-08-11 14:50:59 +0300195TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300196{
197 ASSERT(isInFunctionMap(callNode));
Olli Etuaho5f579b12015-08-14 17:44:43 +0300198 return mFunctionMap[callNode->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300199}
200
Olli Etuaho3fc93372015-08-11 14:50:59 +0300201void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300202{
203 mInFunctionCallOutParameter = inOutParameter;
204}
205
Olli Etuaho3fc93372015-08-11 14:50:59 +0300206bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300207{
208 return mInFunctionCallOutParameter;
209}
210
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211//
212// Traverse the intermediate representation tree, and
213// call a node type specific function for each node.
214// Done recursively through the member function Traverse().
215// Node types can be skipped if their function to call is 0,
216// but their subtree will still be traversed.
217// Nodes with children can have their whole subtree skipped
218// if preVisit is turned on and the type specific function
219// returns false.
220//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221
222//
223// Traversal functions for terminals are straighforward....
224//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300225void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300227 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228}
229
Olli Etuaho27446bd2015-08-10 14:59:53 +0300230void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300232 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233}
234
235//
236// Traverse a binary node.
237//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300238void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700240 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000241
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700242 //
243 // visit the node before children if pre-visiting.
244 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300245 if (preVisit)
246 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000247
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700248 //
249 // Visit the children, in the right order.
250 //
251 if (visit)
252 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300253 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000254
Olli Etuaho3fc93372015-08-11 14:50:59 +0300255 if (node->getLeft())
256 node->getLeft()->traverse(this);
257
258 if (inVisit)
259 visit = visitBinary(InVisit, node);
260
261 if (visit && node->getRight())
262 node->getRight()->traverse(this);
263
264 decrementDepth();
265 }
266
267 //
268 // Visit the node after the children, if requested and the traversal
269 // hasn't been cancelled yet.
270 //
271 if (visit && postVisit)
272 visitBinary(PostVisit, node);
273}
274
275void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
276{
277 bool visit = true;
278
279 //
280 // visit the node before children if pre-visiting.
281 //
282 if (preVisit)
283 visit = visitBinary(PreVisit, node);
284
285 //
286 // Visit the children, in the right order.
287 //
288 if (visit)
289 {
290 incrementDepth(node);
291
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300292 // Some binary operations like indexing can be inside an expression which must be an
293 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300294 bool parentOperatorRequiresLValue = operatorRequiresLValue();
295 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
296 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300297 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300298 ASSERT(!isLValueRequiredHere());
299 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300300 }
301
Olli Etuaho27446bd2015-08-10 14:59:53 +0300302 if (node->getLeft())
303 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000304
Olli Etuaho27446bd2015-08-10 14:59:53 +0300305 if (inVisit)
306 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307
Olli Etuaho27446bd2015-08-10 14:59:53 +0300308 if (node->isAssignment())
309 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300310
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300311 // Index is not required to be an l-value even when the surrounding expression is required
312 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300313 TOperator op = node->getOp();
314 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
315 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300316 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300317 setOperatorRequiresLValue(false);
318 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300319 }
320
Olli Etuaho27446bd2015-08-10 14:59:53 +0300321 if (visit && node->getRight())
322 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700323
Olli Etuaho27446bd2015-08-10 14:59:53 +0300324 setOperatorRequiresLValue(parentOperatorRequiresLValue);
325 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300326
Olli Etuaho27446bd2015-08-10 14:59:53 +0300327 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700328 }
329
330 //
331 // Visit the node after the children, if requested and the traversal
332 // hasn't been cancelled yet.
333 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300334 if (visit && postVisit)
335 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336}
337
338//
339// Traverse a unary node. Same comments in binary node apply here.
340//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300341void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700343 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344
Olli Etuaho27446bd2015-08-10 14:59:53 +0300345 if (preVisit)
346 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000347
Olli Etuahoa26ad582015-08-04 13:51:47 +0300348 if (visit)
349 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300350 incrementDepth(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300351
Olli Etuaho3fc93372015-08-11 14:50:59 +0300352 node->getOperand()->traverse(this);
353
354 decrementDepth();
355 }
356
357 if (visit && postVisit)
358 visitUnary(PostVisit, node);
359}
360
361void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
362{
363 bool visit = true;
364
365 if (preVisit)
366 visit = visitUnary(PreVisit, node);
367
368 if (visit)
369 {
370 incrementDepth(node);
371
Olli Etuaho27446bd2015-08-10 14:59:53 +0300372 ASSERT(!operatorRequiresLValue());
373 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300374 {
375 case EOpPostIncrement:
376 case EOpPostDecrement:
377 case EOpPreIncrement:
378 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300379 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300380 break;
381 default:
382 break;
383 }
384
Olli Etuaho27446bd2015-08-10 14:59:53 +0300385 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300386
Olli Etuaho27446bd2015-08-10 14:59:53 +0300387 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300388
Olli Etuaho27446bd2015-08-10 14:59:53 +0300389 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700390 }
391
Olli Etuaho27446bd2015-08-10 14:59:53 +0300392 if (visit && postVisit)
393 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000394}
395
396//
397// Traverse an aggregate node. Same comments in binary node apply here.
398//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300399void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700401 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402
Olli Etuaho27446bd2015-08-10 14:59:53 +0300403 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300404
405 if (preVisit)
406 visit = visitAggregate(PreVisit, node);
407
408 if (visit)
409 {
410 incrementDepth(node);
411
412 if (node->getOp() == EOpSequence)
413 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300414 else if (node->getOp() == EOpFunction)
415 mInGlobalScope = false;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300416
417 for (auto *child : *sequence)
418 {
419 child->traverse(this);
420 if (visit && inVisit)
421 {
422 if (child != sequence->back())
423 visit = visitAggregate(InVisit, node);
424 }
425
426 if (node->getOp() == EOpSequence)
427 incrementParentBlockPos();
428 }
429
430 if (node->getOp() == EOpSequence)
431 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300432 else if (node->getOp() == EOpFunction)
433 mInGlobalScope = true;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300434
435 decrementDepth();
436 }
437
438 if (visit && postVisit)
439 visitAggregate(PostVisit, node);
440}
441
442void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
443{
444 bool visit = true;
445
446 TIntermSequence *sequence = node->getSequence();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300447 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300448 {
449 case EOpFunction:
450 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300451 TIntermAggregate *params = sequence->front()->getAsAggregate();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300452 ASSERT(params != nullptr);
453 ASSERT(params->getOp() == EOpParameters);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300454 addToFunctionMap(node->getNameObj(), params->getSequence());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300455 break;
456 }
457 case EOpPrototype:
Olli Etuaho5f579b12015-08-14 17:44:43 +0300458 addToFunctionMap(node->getNameObj(), sequence);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300459 break;
460 default:
461 break;
462 }
463
Olli Etuaho27446bd2015-08-10 14:59:53 +0300464 if (preVisit)
465 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000466
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700467 if (visit)
468 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300469 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300470 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700471 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300472 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300473 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300474 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300475 // The function is not user-defined - it is likely built-in texture function.
476 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300477 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700478 }
479 }
480
Olli Etuaho27446bd2015-08-10 14:59:53 +0300481 incrementDepth(node);
Olli Etuaho56eea882015-05-18 12:41:03 +0300482
Olli Etuahoa26ad582015-08-04 13:51:47 +0300483 if (inFunctionMap)
484 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300485 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300486 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300487 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300488 {
489 ASSERT(paramIter != params->end());
490 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300491 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300492
Olli Etuaho27446bd2015-08-10 14:59:53 +0300493 child->traverse(this);
494 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300495 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300496 if (child != sequence->back())
497 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300498 }
499
500 ++paramIter;
501 }
502
Olli Etuaho27446bd2015-08-10 14:59:53 +0300503 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300504 }
505 else
506 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300507 if (node->getOp() == EOpSequence)
508 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300509 else if (node->getOp() == EOpFunction)
510 mInGlobalScope = false;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300511
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300512 // Find the built-in function corresponding to this op so that we can determine the
513 // in/out qualifiers of its parameters.
514 TFunction *builtInFunc = nullptr;
515 TString opString = GetOperatorString(node->getOp());
516 if (!node->isConstructor() && !opString.empty())
517 {
518 // The return type doesn't affect the mangled name of the function, which is used
519 // to look it up from the symbol table.
520 TType dummyReturnType;
521 TFunction call(&opString, &dummyReturnType, node->getOp());
522 for (auto *child : *sequence)
523 {
524 TType *paramType = child->getAsTyped()->getTypePointer();
525 TConstParameter p(paramType);
526 call.addParameter(p);
527 }
528
529 TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
530 if (sym != nullptr && sym->isFunction())
531 {
532 builtInFunc = static_cast<TFunction *>(sym);
533 ASSERT(builtInFunc->getParamCount() == sequence->size());
534 }
535 }
536
537 size_t paramIndex = 0;
538
Olli Etuaho27446bd2015-08-10 14:59:53 +0300539 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300540 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300541 TQualifier qualifier = EvqIn;
542 if (builtInFunc != nullptr)
543 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
544 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300545 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300546
Olli Etuaho27446bd2015-08-10 14:59:53 +0300547 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300548 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300549 if (child != sequence->back())
550 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300551 }
552
Olli Etuaho27446bd2015-08-10 14:59:53 +0300553 if (node->getOp() == EOpSequence)
554 incrementParentBlockPos();
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300555
556 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300557 }
558
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300559 setInFunctionCallOutParameter(false);
560
Olli Etuaho27446bd2015-08-10 14:59:53 +0300561 if (node->getOp() == EOpSequence)
562 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300563 else if (node->getOp() == EOpFunction)
564 mInGlobalScope = true;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300565 }
566
Olli Etuaho27446bd2015-08-10 14:59:53 +0300567 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700568 }
569
Olli Etuaho27446bd2015-08-10 14:59:53 +0300570 if (visit && postVisit)
571 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000572}
573
574//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300575// Traverse a ternary node. Same comments in binary node apply here.
576//
577void TIntermTraverser::traverseTernary(TIntermTernary *node)
578{
579 bool visit = true;
580
581 if (preVisit)
582 visit = visitTernary(PreVisit, node);
583
584 if (visit)
585 {
586 incrementDepth(node);
587 node->getCondition()->traverse(this);
588 if (node->getTrueExpression())
589 node->getTrueExpression()->traverse(this);
590 if (node->getFalseExpression())
591 node->getFalseExpression()->traverse(this);
592 decrementDepth();
593 }
594
595 if (visit && postVisit)
596 visitTernary(PostVisit, node);
597}
598
Olli Etuaho57961272016-09-14 13:57:46 +0300599// Traverse an if-else node. Same comments in binary node apply here.
600void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700602 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000603
Olli Etuaho27446bd2015-08-10 14:59:53 +0300604 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300605 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000606
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700607 if (visit)
608 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300609 incrementDepth(node);
610 node->getCondition()->traverse(this);
611 if (node->getTrueBlock())
612 node->getTrueBlock()->traverse(this);
613 if (node->getFalseBlock())
614 node->getFalseBlock()->traverse(this);
615 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700616 }
617
Olli Etuaho27446bd2015-08-10 14:59:53 +0300618 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300619 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620}
621
622//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200623// Traverse a switch node. Same comments in binary node apply here.
624//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300625void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200626{
627 bool visit = true;
628
Olli Etuaho27446bd2015-08-10 14:59:53 +0300629 if (preVisit)
630 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200631
632 if (visit)
633 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300634 incrementDepth(node);
635 node->getInit()->traverse(this);
636 if (inVisit)
637 visit = visitSwitch(InVisit, node);
638 if (visit && node->getStatementList())
639 node->getStatementList()->traverse(this);
640 decrementDepth();
Olli Etuahoa3a36662015-02-17 13:46:51 +0200641 }
642
Olli Etuaho27446bd2015-08-10 14:59:53 +0300643 if (visit && postVisit)
644 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200645}
646
647//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300648// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200649//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300650void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200651{
652 bool visit = true;
653
Olli Etuaho27446bd2015-08-10 14:59:53 +0300654 if (preVisit)
655 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200656
Olli Etuaho27446bd2015-08-10 14:59:53 +0300657 if (visit && node->getCondition())
658 node->getCondition()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200659
Olli Etuaho27446bd2015-08-10 14:59:53 +0300660 if (visit && postVisit)
661 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200662}
663
664//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000665// Traverse a loop node. Same comments in binary node apply here.
666//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300667void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700669 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000670
Olli Etuaho27446bd2015-08-10 14:59:53 +0300671 if (preVisit)
672 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700674 if (visit)
675 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300676 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000677
Olli Etuaho27446bd2015-08-10 14:59:53 +0300678 if (node->getInit())
679 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000680
Olli Etuaho27446bd2015-08-10 14:59:53 +0300681 if (node->getCondition())
682 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000683
Olli Etuaho27446bd2015-08-10 14:59:53 +0300684 if (node->getBody())
685 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700686
Olli Etuaho27446bd2015-08-10 14:59:53 +0300687 if (node->getExpression())
688 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000689
Olli Etuaho27446bd2015-08-10 14:59:53 +0300690 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700691 }
692
Olli Etuaho27446bd2015-08-10 14:59:53 +0300693 if (visit && postVisit)
694 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000695}
696
697//
698// Traverse a branch node. Same comments in binary node apply here.
699//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300700void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000701{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700702 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000703
Olli Etuaho27446bd2015-08-10 14:59:53 +0300704 if (preVisit)
705 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000706
Olli Etuaho27446bd2015-08-10 14:59:53 +0300707 if (visit && node->getExpression())
708 {
709 incrementDepth(node);
710 node->getExpression()->traverse(this);
711 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700712 }
713
Olli Etuaho27446bd2015-08-10 14:59:53 +0300714 if (visit && postVisit)
715 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000716}
717
Olli Etuaho27446bd2015-08-10 14:59:53 +0300718void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400719{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300720 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400721}