blob: 189a422d40aa209de1f8432fc53962a3f051431f [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
61void TIntermAggregate::traverse(TIntermTraverser *it)
62{
63 it->traverseAggregate(this);
64}
65
66void TIntermLoop::traverse(TIntermTraverser *it)
67{
68 it->traverseLoop(this);
69}
70
71void TIntermBranch::traverse(TIntermTraverser *it)
72{
73 it->traverseBranch(this);
74}
75
Jamie Madill03d863c2016-07-27 18:15:53 -040076TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
77 : preVisit(preVisit),
78 inVisit(inVisit),
79 postVisit(postVisit),
80 mDepth(0),
81 mMaxDepth(0),
82 mInGlobalScope(true),
83 mTemporaryIndex(nullptr)
84{
85}
86
87TIntermTraverser::~TIntermTraverser()
88{
89}
90
Olli Etuaho56eea882015-05-18 12:41:03 +030091void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
92{
Olli Etuaho64f0be92015-06-03 17:38:34 +030093 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +030094}
95
96void TIntermTraverser::incrementParentBlockPos()
97{
Olli Etuaho64f0be92015-06-03 17:38:34 +030098 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +030099}
100
101void TIntermTraverser::popParentBlock()
102{
103 ASSERT(!mParentBlockStack.empty());
104 mParentBlockStack.pop_back();
105}
106
107void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
108{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300109 TIntermSequence emptyInsertionsAfter;
110 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
111}
112
113void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
114 const TIntermSequence &insertionsAfter)
115{
Olli Etuaho56eea882015-05-18 12:41:03 +0300116 ASSERT(!mParentBlockStack.empty());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300117 NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
118 insertionsBefore, insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300119 mInsertions.push_back(insert);
120}
121
Jamie Madill1048e432016-07-23 18:51:28 -0400122void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
123{
124 TIntermSequence insertions;
125 insertions.push_back(statement);
126 insertStatementsInParentBlock(insertions);
127}
128
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300129TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300130{
131 // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
132 TInfoSinkBase symbolNameOut;
133 ASSERT(mTemporaryIndex != nullptr);
134 symbolNameOut << "s" << (*mTemporaryIndex);
135 TString symbolName = symbolNameOut.c_str();
136
137 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
138 node->setInternal(true);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300139 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300140 return node;
141}
142
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300143TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
144{
145 return createTempSymbol(type, EvqTemporary);
146}
147
Olli Etuaho4f1af782015-05-25 11:55:07 +0300148TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
149{
150 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
151 tempDeclaration->getSequence()->push_back(createTempSymbol(type));
152 return tempDeclaration;
153}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300154
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300155TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300156{
157 ASSERT(initializer != nullptr);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300158 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300159 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300160 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300161 tempDeclaration->getSequence()->push_back(tempInit);
162 return tempDeclaration;
163}
164
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300165TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
166{
167 return createTempInitDeclaration(initializer, EvqTemporary);
168}
169
Olli Etuahod4f303e2015-05-20 17:09:06 +0300170TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
171{
172 ASSERT(rightNode != nullptr);
173 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300174 TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300175 return assignment;
176}
177
178void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
179{
180 mTemporaryIndex = temporaryIndex;
181}
182
183void TIntermTraverser::nextTemporaryIndex()
184{
185 ASSERT(mTemporaryIndex != nullptr);
186 ++(*mTemporaryIndex);
187}
188
Olli Etuaho5f579b12015-08-14 17:44:43 +0300189void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300190{
191 mFunctionMap[name] = paramSequence;
192}
193
Olli Etuaho3fc93372015-08-11 14:50:59 +0300194bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300195{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300196 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300197 return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300198}
199
Olli Etuaho3fc93372015-08-11 14:50:59 +0300200TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300201{
202 ASSERT(isInFunctionMap(callNode));
Olli Etuaho5f579b12015-08-14 17:44:43 +0300203 return mFunctionMap[callNode->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300204}
205
Olli Etuaho3fc93372015-08-11 14:50:59 +0300206void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300207{
208 mInFunctionCallOutParameter = inOutParameter;
209}
210
Olli Etuaho3fc93372015-08-11 14:50:59 +0300211bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300212{
213 return mInFunctionCallOutParameter;
214}
215
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216//
217// Traverse the intermediate representation tree, and
218// call a node type specific function for each node.
219// Done recursively through the member function Traverse().
220// Node types can be skipped if their function to call is 0,
221// but their subtree will still be traversed.
222// Nodes with children can have their whole subtree skipped
223// if preVisit is turned on and the type specific function
224// returns false.
225//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226
227//
228// Traversal functions for terminals are straighforward....
229//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300230void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300232 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233}
234
Olli Etuaho27446bd2015-08-10 14:59:53 +0300235void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000236{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300237 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000238}
239
Olli Etuahob6fa0432016-09-28 16:28:05 +0100240void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
241{
242 bool visit = true;
243
244 if (preVisit)
245 visit = visitSwizzle(PreVisit, node);
246
247 if (visit)
248 {
249 incrementDepth(node);
250
251 node->getOperand()->traverse(this);
252
253 decrementDepth();
254 }
255
256 if (visit && postVisit)
257 visitSwizzle(PostVisit, node);
258}
259
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260//
261// Traverse a binary node.
262//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300263void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700265 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700267 //
268 // visit the node before children if pre-visiting.
269 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300270 if (preVisit)
271 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700273 //
274 // Visit the children, in the right order.
275 //
276 if (visit)
277 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300278 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279
Olli Etuaho3fc93372015-08-11 14:50:59 +0300280 if (node->getLeft())
281 node->getLeft()->traverse(this);
282
283 if (inVisit)
284 visit = visitBinary(InVisit, node);
285
286 if (visit && node->getRight())
287 node->getRight()->traverse(this);
288
289 decrementDepth();
290 }
291
292 //
293 // Visit the node after the children, if requested and the traversal
294 // hasn't been cancelled yet.
295 //
296 if (visit && postVisit)
297 visitBinary(PostVisit, node);
298}
299
300void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
301{
302 bool visit = true;
303
304 //
305 // visit the node before children if pre-visiting.
306 //
307 if (preVisit)
308 visit = visitBinary(PreVisit, node);
309
310 //
311 // Visit the children, in the right order.
312 //
313 if (visit)
314 {
315 incrementDepth(node);
316
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300317 // Some binary operations like indexing can be inside an expression which must be an
318 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300319 bool parentOperatorRequiresLValue = operatorRequiresLValue();
320 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
321 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300322 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300323 ASSERT(!isLValueRequiredHere());
324 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300325 }
326
Olli Etuaho27446bd2015-08-10 14:59:53 +0300327 if (node->getLeft())
328 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329
Olli Etuaho27446bd2015-08-10 14:59:53 +0300330 if (inVisit)
331 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332
Olli Etuaho27446bd2015-08-10 14:59:53 +0300333 if (node->isAssignment())
334 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300335
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300336 // Index is not required to be an l-value even when the surrounding expression is required
337 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300338 TOperator op = node->getOp();
339 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
340 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300341 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300342 setOperatorRequiresLValue(false);
343 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300344 }
345
Olli Etuaho27446bd2015-08-10 14:59:53 +0300346 if (visit && node->getRight())
347 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700348
Olli Etuaho27446bd2015-08-10 14:59:53 +0300349 setOperatorRequiresLValue(parentOperatorRequiresLValue);
350 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300351
Olli Etuaho27446bd2015-08-10 14:59:53 +0300352 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700353 }
354
355 //
356 // Visit the node after the children, if requested and the traversal
357 // hasn't been cancelled yet.
358 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300359 if (visit && postVisit)
360 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361}
362
363//
364// Traverse a unary node. Same comments in binary node apply here.
365//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300366void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000367{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700368 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000369
Olli Etuaho27446bd2015-08-10 14:59:53 +0300370 if (preVisit)
371 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372
Olli Etuahoa26ad582015-08-04 13:51:47 +0300373 if (visit)
374 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300375 incrementDepth(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300376
Olli Etuaho3fc93372015-08-11 14:50:59 +0300377 node->getOperand()->traverse(this);
378
379 decrementDepth();
380 }
381
382 if (visit && postVisit)
383 visitUnary(PostVisit, node);
384}
385
386void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
387{
388 bool visit = true;
389
390 if (preVisit)
391 visit = visitUnary(PreVisit, node);
392
393 if (visit)
394 {
395 incrementDepth(node);
396
Olli Etuaho27446bd2015-08-10 14:59:53 +0300397 ASSERT(!operatorRequiresLValue());
398 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300399 {
400 case EOpPostIncrement:
401 case EOpPostDecrement:
402 case EOpPreIncrement:
403 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300404 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300405 break;
406 default:
407 break;
408 }
409
Olli Etuaho27446bd2015-08-10 14:59:53 +0300410 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300411
Olli Etuaho27446bd2015-08-10 14:59:53 +0300412 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300413
Olli Etuaho27446bd2015-08-10 14:59:53 +0300414 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700415 }
416
Olli Etuaho27446bd2015-08-10 14:59:53 +0300417 if (visit && postVisit)
418 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000419}
420
421//
422// Traverse an aggregate node. Same comments in binary node apply here.
423//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300424void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700426 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427
Olli Etuaho27446bd2015-08-10 14:59:53 +0300428 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300429
430 if (preVisit)
431 visit = visitAggregate(PreVisit, node);
432
433 if (visit)
434 {
435 incrementDepth(node);
436
437 if (node->getOp() == EOpSequence)
438 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300439 else if (node->getOp() == EOpFunction)
440 mInGlobalScope = false;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300441
442 for (auto *child : *sequence)
443 {
444 child->traverse(this);
445 if (visit && inVisit)
446 {
447 if (child != sequence->back())
448 visit = visitAggregate(InVisit, node);
449 }
450
451 if (node->getOp() == EOpSequence)
452 incrementParentBlockPos();
453 }
454
455 if (node->getOp() == EOpSequence)
456 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300457 else if (node->getOp() == EOpFunction)
458 mInGlobalScope = true;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300459
460 decrementDepth();
461 }
462
463 if (visit && postVisit)
464 visitAggregate(PostVisit, node);
465}
466
467void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
468{
469 bool visit = true;
470
471 TIntermSequence *sequence = node->getSequence();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300472 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300473 {
474 case EOpFunction:
475 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300476 TIntermAggregate *params = sequence->front()->getAsAggregate();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300477 ASSERT(params != nullptr);
478 ASSERT(params->getOp() == EOpParameters);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300479 addToFunctionMap(node->getNameObj(), params->getSequence());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300480 break;
481 }
482 case EOpPrototype:
Olli Etuaho5f579b12015-08-14 17:44:43 +0300483 addToFunctionMap(node->getNameObj(), sequence);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300484 break;
485 default:
486 break;
487 }
488
Olli Etuaho27446bd2015-08-10 14:59:53 +0300489 if (preVisit)
490 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000491
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700492 if (visit)
493 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300494 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300495 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700496 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300497 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300498 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300499 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300500 // The function is not user-defined - it is likely built-in texture function.
501 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300502 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700503 }
504 }
505
Olli Etuaho27446bd2015-08-10 14:59:53 +0300506 incrementDepth(node);
Olli Etuaho56eea882015-05-18 12:41:03 +0300507
Olli Etuahoa26ad582015-08-04 13:51:47 +0300508 if (inFunctionMap)
509 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300510 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300511 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300512 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300513 {
514 ASSERT(paramIter != params->end());
515 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300516 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300517
Olli Etuaho27446bd2015-08-10 14:59:53 +0300518 child->traverse(this);
519 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300520 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300521 if (child != sequence->back())
522 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300523 }
524
525 ++paramIter;
526 }
527
Olli Etuaho27446bd2015-08-10 14:59:53 +0300528 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300529 }
530 else
531 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300532 if (node->getOp() == EOpSequence)
533 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300534 else if (node->getOp() == EOpFunction)
535 mInGlobalScope = false;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300536
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300537 // Find the built-in function corresponding to this op so that we can determine the
538 // in/out qualifiers of its parameters.
539 TFunction *builtInFunc = nullptr;
540 TString opString = GetOperatorString(node->getOp());
541 if (!node->isConstructor() && !opString.empty())
542 {
543 // The return type doesn't affect the mangled name of the function, which is used
544 // to look it up from the symbol table.
545 TType dummyReturnType;
546 TFunction call(&opString, &dummyReturnType, node->getOp());
547 for (auto *child : *sequence)
548 {
549 TType *paramType = child->getAsTyped()->getTypePointer();
550 TConstParameter p(paramType);
551 call.addParameter(p);
552 }
553
554 TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
555 if (sym != nullptr && sym->isFunction())
556 {
557 builtInFunc = static_cast<TFunction *>(sym);
558 ASSERT(builtInFunc->getParamCount() == sequence->size());
559 }
560 }
561
562 size_t paramIndex = 0;
563
Olli Etuaho27446bd2015-08-10 14:59:53 +0300564 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300565 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300566 TQualifier qualifier = EvqIn;
567 if (builtInFunc != nullptr)
568 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
569 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300570 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300571
Olli Etuaho27446bd2015-08-10 14:59:53 +0300572 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300573 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300574 if (child != sequence->back())
575 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300576 }
577
Olli Etuaho27446bd2015-08-10 14:59:53 +0300578 if (node->getOp() == EOpSequence)
579 incrementParentBlockPos();
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300580
581 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300582 }
583
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300584 setInFunctionCallOutParameter(false);
585
Olli Etuaho27446bd2015-08-10 14:59:53 +0300586 if (node->getOp() == EOpSequence)
587 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300588 else if (node->getOp() == EOpFunction)
589 mInGlobalScope = true;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300590 }
591
Olli Etuaho27446bd2015-08-10 14:59:53 +0300592 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700593 }
594
Olli Etuaho27446bd2015-08-10 14:59:53 +0300595 if (visit && postVisit)
596 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597}
598
599//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300600// Traverse a ternary node. Same comments in binary node apply here.
601//
602void TIntermTraverser::traverseTernary(TIntermTernary *node)
603{
604 bool visit = true;
605
606 if (preVisit)
607 visit = visitTernary(PreVisit, node);
608
609 if (visit)
610 {
611 incrementDepth(node);
612 node->getCondition()->traverse(this);
613 if (node->getTrueExpression())
614 node->getTrueExpression()->traverse(this);
615 if (node->getFalseExpression())
616 node->getFalseExpression()->traverse(this);
617 decrementDepth();
618 }
619
620 if (visit && postVisit)
621 visitTernary(PostVisit, node);
622}
623
Olli Etuaho57961272016-09-14 13:57:46 +0300624// Traverse an if-else node. Same comments in binary node apply here.
625void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700627 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628
Olli Etuaho27446bd2015-08-10 14:59:53 +0300629 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300630 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000631
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700632 if (visit)
633 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300634 incrementDepth(node);
635 node->getCondition()->traverse(this);
636 if (node->getTrueBlock())
637 node->getTrueBlock()->traverse(this);
638 if (node->getFalseBlock())
639 node->getFalseBlock()->traverse(this);
640 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700641 }
642
Olli Etuaho27446bd2015-08-10 14:59:53 +0300643 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300644 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645}
646
647//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200648// Traverse a switch node. Same comments in binary node apply here.
649//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300650void TIntermTraverser::traverseSwitch(TIntermSwitch *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 = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200656
657 if (visit)
658 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300659 incrementDepth(node);
660 node->getInit()->traverse(this);
661 if (inVisit)
662 visit = visitSwitch(InVisit, node);
663 if (visit && node->getStatementList())
664 node->getStatementList()->traverse(this);
665 decrementDepth();
Olli Etuahoa3a36662015-02-17 13:46:51 +0200666 }
667
Olli Etuaho27446bd2015-08-10 14:59:53 +0300668 if (visit && postVisit)
669 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200670}
671
672//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300673// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200674//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300675void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200676{
677 bool visit = true;
678
Olli Etuaho27446bd2015-08-10 14:59:53 +0300679 if (preVisit)
680 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200681
Olli Etuaho27446bd2015-08-10 14:59:53 +0300682 if (visit && node->getCondition())
683 node->getCondition()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200684
Olli Etuaho27446bd2015-08-10 14:59:53 +0300685 if (visit && postVisit)
686 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200687}
688
689//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000690// Traverse a loop node. Same comments in binary node apply here.
691//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300692void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000693{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700694 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000695
Olli Etuaho27446bd2015-08-10 14:59:53 +0300696 if (preVisit)
697 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000698
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700699 if (visit)
700 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300701 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000702
Olli Etuaho27446bd2015-08-10 14:59:53 +0300703 if (node->getInit())
704 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000705
Olli Etuaho27446bd2015-08-10 14:59:53 +0300706 if (node->getCondition())
707 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000708
Olli Etuaho27446bd2015-08-10 14:59:53 +0300709 if (node->getBody())
710 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700711
Olli Etuaho27446bd2015-08-10 14:59:53 +0300712 if (node->getExpression())
713 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000714
Olli Etuaho27446bd2015-08-10 14:59:53 +0300715 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700716 }
717
Olli Etuaho27446bd2015-08-10 14:59:53 +0300718 if (visit && postVisit)
719 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000720}
721
722//
723// Traverse a branch node. Same comments in binary node apply here.
724//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300725void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000726{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700727 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000728
Olli Etuaho27446bd2015-08-10 14:59:53 +0300729 if (preVisit)
730 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000731
Olli Etuaho27446bd2015-08-10 14:59:53 +0300732 if (visit && node->getExpression())
733 {
734 incrementDepth(node);
735 node->getExpression()->traverse(this);
736 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700737 }
738
Olli Etuaho27446bd2015-08-10 14:59:53 +0300739 if (visit && postVisit)
740 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000741}
742
Olli Etuaho27446bd2015-08-10 14:59:53 +0300743void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400744{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300745 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400746}