blob: 889bab750422a665c395a796ce8d5646a9172318 [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
36void TIntermSelection::traverse(TIntermTraverser *it)
37{
38 it->traverseSelection(this);
39}
40
41void TIntermSwitch::traverse(TIntermTraverser *it)
42{
43 it->traverseSwitch(this);
44}
45
46void TIntermCase::traverse(TIntermTraverser *it)
47{
48 it->traverseCase(this);
49}
50
51void TIntermAggregate::traverse(TIntermTraverser *it)
52{
53 it->traverseAggregate(this);
54}
55
56void TIntermLoop::traverse(TIntermTraverser *it)
57{
58 it->traverseLoop(this);
59}
60
61void TIntermBranch::traverse(TIntermTraverser *it)
62{
63 it->traverseBranch(this);
64}
65
Olli Etuaho56eea882015-05-18 12:41:03 +030066void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
67{
Olli Etuaho64f0be92015-06-03 17:38:34 +030068 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +030069}
70
71void TIntermTraverser::incrementParentBlockPos()
72{
Olli Etuaho64f0be92015-06-03 17:38:34 +030073 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +030074}
75
76void TIntermTraverser::popParentBlock()
77{
78 ASSERT(!mParentBlockStack.empty());
79 mParentBlockStack.pop_back();
80}
81
82void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
83{
Olli Etuaho5d91dda2015-06-18 15:47:46 +030084 TIntermSequence emptyInsertionsAfter;
85 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
86}
87
88void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
89 const TIntermSequence &insertionsAfter)
90{
Olli Etuaho56eea882015-05-18 12:41:03 +030091 ASSERT(!mParentBlockStack.empty());
Olli Etuaho5d91dda2015-06-18 15:47:46 +030092 NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
93 insertionsBefore, insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +030094 mInsertions.push_back(insert);
95}
96
Jamie Madill1048e432016-07-23 18:51:28 -040097void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
98{
99 TIntermSequence insertions;
100 insertions.push_back(statement);
101 insertStatementsInParentBlock(insertions);
102}
103
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300104TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300105{
106 // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
107 TInfoSinkBase symbolNameOut;
108 ASSERT(mTemporaryIndex != nullptr);
109 symbolNameOut << "s" << (*mTemporaryIndex);
110 TString symbolName = symbolNameOut.c_str();
111
112 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
113 node->setInternal(true);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300114 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300115 return node;
116}
117
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300118TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
119{
120 return createTempSymbol(type, EvqTemporary);
121}
122
Olli Etuaho4f1af782015-05-25 11:55:07 +0300123TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
124{
125 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
126 tempDeclaration->getSequence()->push_back(createTempSymbol(type));
127 return tempDeclaration;
128}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300129
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300130TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300131{
132 ASSERT(initializer != nullptr);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300133 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300134 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
135 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
136 tempInit->setLeft(tempSymbol);
137 tempInit->setRight(initializer);
138 tempInit->setType(tempSymbol->getType());
139 tempDeclaration->getSequence()->push_back(tempInit);
140 return tempDeclaration;
141}
142
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300143TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
144{
145 return createTempInitDeclaration(initializer, EvqTemporary);
146}
147
Olli Etuahod4f303e2015-05-20 17:09:06 +0300148TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
149{
150 ASSERT(rightNode != nullptr);
151 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
152 TIntermBinary *assignment = new TIntermBinary(EOpAssign);
153 assignment->setLeft(tempSymbol);
154 assignment->setRight(rightNode);
155 assignment->setType(tempSymbol->getType());
156 return assignment;
157}
158
159void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
160{
161 mTemporaryIndex = temporaryIndex;
162}
163
164void TIntermTraverser::nextTemporaryIndex()
165{
166 ASSERT(mTemporaryIndex != nullptr);
167 ++(*mTemporaryIndex);
168}
169
Olli Etuaho5f579b12015-08-14 17:44:43 +0300170void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300171{
172 mFunctionMap[name] = paramSequence;
173}
174
Olli Etuaho3fc93372015-08-11 14:50:59 +0300175bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300176{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300177 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300178 return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300179}
180
Olli Etuaho3fc93372015-08-11 14:50:59 +0300181TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300182{
183 ASSERT(isInFunctionMap(callNode));
Olli Etuaho5f579b12015-08-14 17:44:43 +0300184 return mFunctionMap[callNode->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300185}
186
Olli Etuaho3fc93372015-08-11 14:50:59 +0300187void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300188{
189 mInFunctionCallOutParameter = inOutParameter;
190}
191
Olli Etuaho3fc93372015-08-11 14:50:59 +0300192bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300193{
194 return mInFunctionCallOutParameter;
195}
196
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197//
198// Traverse the intermediate representation tree, and
199// call a node type specific function for each node.
200// Done recursively through the member function Traverse().
201// Node types can be skipped if their function to call is 0,
202// but their subtree will still be traversed.
203// Nodes with children can have their whole subtree skipped
204// if preVisit is turned on and the type specific function
205// returns false.
206//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207
208//
209// Traversal functions for terminals are straighforward....
210//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300211void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300213 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214}
215
Olli Etuaho27446bd2015-08-10 14:59:53 +0300216void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300218 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219}
220
221//
222// Traverse a binary node.
223//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300224void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700226 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700228 //
229 // visit the node before children if pre-visiting.
230 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300231 if (preVisit)
232 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700234 //
235 // Visit the children, in the right order.
236 //
237 if (visit)
238 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300239 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000240
Olli Etuaho3fc93372015-08-11 14:50:59 +0300241 if (node->getLeft())
242 node->getLeft()->traverse(this);
243
244 if (inVisit)
245 visit = visitBinary(InVisit, node);
246
247 if (visit && node->getRight())
248 node->getRight()->traverse(this);
249
250 decrementDepth();
251 }
252
253 //
254 // Visit the node after the children, if requested and the traversal
255 // hasn't been cancelled yet.
256 //
257 if (visit && postVisit)
258 visitBinary(PostVisit, node);
259}
260
261void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
262{
263 bool visit = true;
264
265 //
266 // visit the node before children if pre-visiting.
267 //
268 if (preVisit)
269 visit = visitBinary(PreVisit, node);
270
271 //
272 // Visit the children, in the right order.
273 //
274 if (visit)
275 {
276 incrementDepth(node);
277
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300278 // Some binary operations like indexing can be inside an expression which must be an
279 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300280 bool parentOperatorRequiresLValue = operatorRequiresLValue();
281 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
282 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300283 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300284 ASSERT(!isLValueRequiredHere());
285 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300286 }
287
Olli Etuaho27446bd2015-08-10 14:59:53 +0300288 if (node->getLeft())
289 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290
Olli Etuaho27446bd2015-08-10 14:59:53 +0300291 if (inVisit)
292 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293
Olli Etuaho27446bd2015-08-10 14:59:53 +0300294 if (node->isAssignment())
295 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300296
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300297 // Index is not required to be an l-value even when the surrounding expression is required
298 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300299 TOperator op = node->getOp();
300 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
301 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300302 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300303 setOperatorRequiresLValue(false);
304 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300305 }
306
Olli Etuaho27446bd2015-08-10 14:59:53 +0300307 if (visit && node->getRight())
308 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700309
Olli Etuaho27446bd2015-08-10 14:59:53 +0300310 setOperatorRequiresLValue(parentOperatorRequiresLValue);
311 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300312
Olli Etuaho27446bd2015-08-10 14:59:53 +0300313 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700314 }
315
316 //
317 // Visit the node after the children, if requested and the traversal
318 // hasn't been cancelled yet.
319 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300320 if (visit && postVisit)
321 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322}
323
324//
325// Traverse a unary node. Same comments in binary node apply here.
326//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300327void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700329 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330
Olli Etuaho27446bd2015-08-10 14:59:53 +0300331 if (preVisit)
332 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333
Olli Etuahoa26ad582015-08-04 13:51:47 +0300334 if (visit)
335 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300336 incrementDepth(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300337
Olli Etuaho3fc93372015-08-11 14:50:59 +0300338 node->getOperand()->traverse(this);
339
340 decrementDepth();
341 }
342
343 if (visit && postVisit)
344 visitUnary(PostVisit, node);
345}
346
347void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
348{
349 bool visit = true;
350
351 if (preVisit)
352 visit = visitUnary(PreVisit, node);
353
354 if (visit)
355 {
356 incrementDepth(node);
357
Olli Etuaho27446bd2015-08-10 14:59:53 +0300358 ASSERT(!operatorRequiresLValue());
359 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300360 {
361 case EOpPostIncrement:
362 case EOpPostDecrement:
363 case EOpPreIncrement:
364 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300365 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300366 break;
367 default:
368 break;
369 }
370
Olli Etuaho27446bd2015-08-10 14:59:53 +0300371 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300372
Olli Etuaho27446bd2015-08-10 14:59:53 +0300373 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300374
Olli Etuaho27446bd2015-08-10 14:59:53 +0300375 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700376 }
377
Olli Etuaho27446bd2015-08-10 14:59:53 +0300378 if (visit && postVisit)
379 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000380}
381
382//
383// Traverse an aggregate node. Same comments in binary node apply here.
384//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300385void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700387 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000388
Olli Etuaho27446bd2015-08-10 14:59:53 +0300389 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300390
391 if (preVisit)
392 visit = visitAggregate(PreVisit, node);
393
394 if (visit)
395 {
396 incrementDepth(node);
397
398 if (node->getOp() == EOpSequence)
399 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300400 else if (node->getOp() == EOpFunction)
401 mInGlobalScope = false;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300402
403 for (auto *child : *sequence)
404 {
405 child->traverse(this);
406 if (visit && inVisit)
407 {
408 if (child != sequence->back())
409 visit = visitAggregate(InVisit, node);
410 }
411
412 if (node->getOp() == EOpSequence)
413 incrementParentBlockPos();
414 }
415
416 if (node->getOp() == EOpSequence)
417 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300418 else if (node->getOp() == EOpFunction)
419 mInGlobalScope = true;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300420
421 decrementDepth();
422 }
423
424 if (visit && postVisit)
425 visitAggregate(PostVisit, node);
426}
427
428void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
429{
430 bool visit = true;
431
432 TIntermSequence *sequence = node->getSequence();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300433 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300434 {
435 case EOpFunction:
436 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300437 TIntermAggregate *params = sequence->front()->getAsAggregate();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300438 ASSERT(params != nullptr);
439 ASSERT(params->getOp() == EOpParameters);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300440 addToFunctionMap(node->getNameObj(), params->getSequence());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300441 break;
442 }
443 case EOpPrototype:
Olli Etuaho5f579b12015-08-14 17:44:43 +0300444 addToFunctionMap(node->getNameObj(), sequence);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300445 break;
446 default:
447 break;
448 }
449
Olli Etuaho27446bd2015-08-10 14:59:53 +0300450 if (preVisit)
451 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700453 if (visit)
454 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300455 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300456 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700457 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300458 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300459 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300460 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300461 // The function is not user-defined - it is likely built-in texture function.
462 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300463 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700464 }
465 }
466
Olli Etuaho27446bd2015-08-10 14:59:53 +0300467 incrementDepth(node);
Olli Etuaho56eea882015-05-18 12:41:03 +0300468
Olli Etuahoa26ad582015-08-04 13:51:47 +0300469 if (inFunctionMap)
470 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300471 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300472 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300473 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300474 {
475 ASSERT(paramIter != params->end());
476 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300477 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300478
Olli Etuaho27446bd2015-08-10 14:59:53 +0300479 child->traverse(this);
480 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300481 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300482 if (child != sequence->back())
483 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300484 }
485
486 ++paramIter;
487 }
488
Olli Etuaho27446bd2015-08-10 14:59:53 +0300489 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300490 }
491 else
492 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300493 if (node->getOp() == EOpSequence)
494 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300495 else if (node->getOp() == EOpFunction)
496 mInGlobalScope = false;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300497
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300498 // Find the built-in function corresponding to this op so that we can determine the
499 // in/out qualifiers of its parameters.
500 TFunction *builtInFunc = nullptr;
501 TString opString = GetOperatorString(node->getOp());
502 if (!node->isConstructor() && !opString.empty())
503 {
504 // The return type doesn't affect the mangled name of the function, which is used
505 // to look it up from the symbol table.
506 TType dummyReturnType;
507 TFunction call(&opString, &dummyReturnType, node->getOp());
508 for (auto *child : *sequence)
509 {
510 TType *paramType = child->getAsTyped()->getTypePointer();
511 TConstParameter p(paramType);
512 call.addParameter(p);
513 }
514
515 TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
516 if (sym != nullptr && sym->isFunction())
517 {
518 builtInFunc = static_cast<TFunction *>(sym);
519 ASSERT(builtInFunc->getParamCount() == sequence->size());
520 }
521 }
522
523 size_t paramIndex = 0;
524
Olli Etuaho27446bd2015-08-10 14:59:53 +0300525 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300526 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300527 TQualifier qualifier = EvqIn;
528 if (builtInFunc != nullptr)
529 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
530 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300531 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300532
Olli Etuaho27446bd2015-08-10 14:59:53 +0300533 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300534 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300535 if (child != sequence->back())
536 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300537 }
538
Olli Etuaho27446bd2015-08-10 14:59:53 +0300539 if (node->getOp() == EOpSequence)
540 incrementParentBlockPos();
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300541
542 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300543 }
544
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300545 setInFunctionCallOutParameter(false);
546
Olli Etuaho27446bd2015-08-10 14:59:53 +0300547 if (node->getOp() == EOpSequence)
548 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300549 else if (node->getOp() == EOpFunction)
550 mInGlobalScope = true;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300551 }
552
Olli Etuaho27446bd2015-08-10 14:59:53 +0300553 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700554 }
555
Olli Etuaho27446bd2015-08-10 14:59:53 +0300556 if (visit && postVisit)
557 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000558}
559
560//
561// Traverse a selection node. Same comments in binary node apply here.
562//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300563void TIntermTraverser::traverseSelection(TIntermSelection *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000564{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700565 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000566
Olli Etuaho27446bd2015-08-10 14:59:53 +0300567 if (preVisit)
568 visit = visitSelection(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000569
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700570 if (visit)
571 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300572 incrementDepth(node);
573 node->getCondition()->traverse(this);
574 if (node->getTrueBlock())
575 node->getTrueBlock()->traverse(this);
576 if (node->getFalseBlock())
577 node->getFalseBlock()->traverse(this);
578 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700579 }
580
Olli Etuaho27446bd2015-08-10 14:59:53 +0300581 if (visit && postVisit)
582 visitSelection(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000583}
584
585//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200586// Traverse a switch node. Same comments in binary node apply here.
587//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300588void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200589{
590 bool visit = true;
591
Olli Etuaho27446bd2015-08-10 14:59:53 +0300592 if (preVisit)
593 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200594
595 if (visit)
596 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300597 incrementDepth(node);
598 node->getInit()->traverse(this);
599 if (inVisit)
600 visit = visitSwitch(InVisit, node);
601 if (visit && node->getStatementList())
602 node->getStatementList()->traverse(this);
603 decrementDepth();
Olli Etuahoa3a36662015-02-17 13:46:51 +0200604 }
605
Olli Etuaho27446bd2015-08-10 14:59:53 +0300606 if (visit && postVisit)
607 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200608}
609
610//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300611// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200612//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300613void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200614{
615 bool visit = true;
616
Olli Etuaho27446bd2015-08-10 14:59:53 +0300617 if (preVisit)
618 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200619
Olli Etuaho27446bd2015-08-10 14:59:53 +0300620 if (visit && node->getCondition())
621 node->getCondition()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200622
Olli Etuaho27446bd2015-08-10 14:59:53 +0300623 if (visit && postVisit)
624 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200625}
626
627//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000628// Traverse a loop node. Same comments in binary node apply here.
629//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300630void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000631{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700632 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000633
Olli Etuaho27446bd2015-08-10 14:59:53 +0300634 if (preVisit)
635 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000636
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700637 if (visit)
638 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300639 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000640
Olli Etuaho27446bd2015-08-10 14:59:53 +0300641 if (node->getInit())
642 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643
Olli Etuaho27446bd2015-08-10 14:59:53 +0300644 if (node->getCondition())
645 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000646
Olli Etuaho27446bd2015-08-10 14:59:53 +0300647 if (node->getBody())
648 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700649
Olli Etuaho27446bd2015-08-10 14:59:53 +0300650 if (node->getExpression())
651 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000652
Olli Etuaho27446bd2015-08-10 14:59:53 +0300653 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700654 }
655
Olli Etuaho27446bd2015-08-10 14:59:53 +0300656 if (visit && postVisit)
657 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000658}
659
660//
661// Traverse a branch node. Same comments in binary node apply here.
662//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300663void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000664{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700665 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000666
Olli Etuaho27446bd2015-08-10 14:59:53 +0300667 if (preVisit)
668 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000669
Olli Etuaho27446bd2015-08-10 14:59:53 +0300670 if (visit && node->getExpression())
671 {
672 incrementDepth(node);
673 node->getExpression()->traverse(this);
674 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700675 }
676
Olli Etuaho27446bd2015-08-10 14:59:53 +0300677 if (visit && postVisit)
678 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000679}
680
Olli Etuaho27446bd2015-08-10 14:59:53 +0300681void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400682{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300683 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400684}