blob: b785c40f14a9f369bc44d783fafc87c3472774ab [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
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030097TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +030098{
99 // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
100 TInfoSinkBase symbolNameOut;
101 ASSERT(mTemporaryIndex != nullptr);
102 symbolNameOut << "s" << (*mTemporaryIndex);
103 TString symbolName = symbolNameOut.c_str();
104
105 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
106 node->setInternal(true);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300107 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300108 return node;
109}
110
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300111TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
112{
113 return createTempSymbol(type, EvqTemporary);
114}
115
Olli Etuaho4f1af782015-05-25 11:55:07 +0300116TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
117{
118 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
119 tempDeclaration->getSequence()->push_back(createTempSymbol(type));
120 return tempDeclaration;
121}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300122
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300123TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300124{
125 ASSERT(initializer != nullptr);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300126 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300127 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
128 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
129 tempInit->setLeft(tempSymbol);
130 tempInit->setRight(initializer);
131 tempInit->setType(tempSymbol->getType());
132 tempDeclaration->getSequence()->push_back(tempInit);
133 return tempDeclaration;
134}
135
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300136TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
137{
138 return createTempInitDeclaration(initializer, EvqTemporary);
139}
140
Olli Etuahod4f303e2015-05-20 17:09:06 +0300141TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
142{
143 ASSERT(rightNode != nullptr);
144 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
145 TIntermBinary *assignment = new TIntermBinary(EOpAssign);
146 assignment->setLeft(tempSymbol);
147 assignment->setRight(rightNode);
148 assignment->setType(tempSymbol->getType());
149 return assignment;
150}
151
152void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
153{
154 mTemporaryIndex = temporaryIndex;
155}
156
157void TIntermTraverser::nextTemporaryIndex()
158{
159 ASSERT(mTemporaryIndex != nullptr);
160 ++(*mTemporaryIndex);
161}
162
Olli Etuaho5f579b12015-08-14 17:44:43 +0300163void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300164{
165 mFunctionMap[name] = paramSequence;
166}
167
Olli Etuaho3fc93372015-08-11 14:50:59 +0300168bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300169{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300170 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300171 return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300172}
173
Olli Etuaho3fc93372015-08-11 14:50:59 +0300174TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300175{
176 ASSERT(isInFunctionMap(callNode));
Olli Etuaho5f579b12015-08-14 17:44:43 +0300177 return mFunctionMap[callNode->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300178}
179
Olli Etuaho3fc93372015-08-11 14:50:59 +0300180void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300181{
182 mInFunctionCallOutParameter = inOutParameter;
183}
184
Olli Etuaho3fc93372015-08-11 14:50:59 +0300185bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300186{
187 return mInFunctionCallOutParameter;
188}
189
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190//
191// Traverse the intermediate representation tree, and
192// call a node type specific function for each node.
193// Done recursively through the member function Traverse().
194// Node types can be skipped if their function to call is 0,
195// but their subtree will still be traversed.
196// Nodes with children can have their whole subtree skipped
197// if preVisit is turned on and the type specific function
198// returns false.
199//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200
201//
202// Traversal functions for terminals are straighforward....
203//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300204void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300206 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207}
208
Olli Etuaho27446bd2015-08-10 14:59:53 +0300209void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300211 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212}
213
214//
215// Traverse a binary node.
216//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300217void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000218{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700219 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000220
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700221 //
222 // visit the node before children if pre-visiting.
223 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300224 if (preVisit)
225 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700227 //
228 // Visit the children, in the right order.
229 //
230 if (visit)
231 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300232 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233
Olli Etuaho3fc93372015-08-11 14:50:59 +0300234 if (node->getLeft())
235 node->getLeft()->traverse(this);
236
237 if (inVisit)
238 visit = visitBinary(InVisit, node);
239
240 if (visit && node->getRight())
241 node->getRight()->traverse(this);
242
243 decrementDepth();
244 }
245
246 //
247 // Visit the node after the children, if requested and the traversal
248 // hasn't been cancelled yet.
249 //
250 if (visit && postVisit)
251 visitBinary(PostVisit, node);
252}
253
254void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
255{
256 bool visit = true;
257
258 //
259 // visit the node before children if pre-visiting.
260 //
261 if (preVisit)
262 visit = visitBinary(PreVisit, node);
263
264 //
265 // Visit the children, in the right order.
266 //
267 if (visit)
268 {
269 incrementDepth(node);
270
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300271 // Some binary operations like indexing can be inside an expression which must be an
272 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300273 bool parentOperatorRequiresLValue = operatorRequiresLValue();
274 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
275 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300276 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300277 ASSERT(!isLValueRequiredHere());
278 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300279 }
280
Olli Etuaho27446bd2015-08-10 14:59:53 +0300281 if (node->getLeft())
282 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283
Olli Etuaho27446bd2015-08-10 14:59:53 +0300284 if (inVisit)
285 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000286
Olli Etuaho27446bd2015-08-10 14:59:53 +0300287 if (node->isAssignment())
288 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300289
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300290 // Index is not required to be an l-value even when the surrounding expression is required
291 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300292 TOperator op = node->getOp();
293 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
294 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300295 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300296 setOperatorRequiresLValue(false);
297 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300298 }
299
Olli Etuaho27446bd2015-08-10 14:59:53 +0300300 if (visit && node->getRight())
301 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700302
Olli Etuaho27446bd2015-08-10 14:59:53 +0300303 setOperatorRequiresLValue(parentOperatorRequiresLValue);
304 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300305
Olli Etuaho27446bd2015-08-10 14:59:53 +0300306 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700307 }
308
309 //
310 // Visit the node after the children, if requested and the traversal
311 // hasn't been cancelled yet.
312 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300313 if (visit && postVisit)
314 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315}
316
317//
318// Traverse a unary node. Same comments in binary node apply here.
319//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300320void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700322 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323
Olli Etuaho27446bd2015-08-10 14:59:53 +0300324 if (preVisit)
325 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326
Olli Etuahoa26ad582015-08-04 13:51:47 +0300327 if (visit)
328 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300329 incrementDepth(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300330
Olli Etuaho3fc93372015-08-11 14:50:59 +0300331 node->getOperand()->traverse(this);
332
333 decrementDepth();
334 }
335
336 if (visit && postVisit)
337 visitUnary(PostVisit, node);
338}
339
340void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
341{
342 bool visit = true;
343
344 if (preVisit)
345 visit = visitUnary(PreVisit, node);
346
347 if (visit)
348 {
349 incrementDepth(node);
350
Olli Etuaho27446bd2015-08-10 14:59:53 +0300351 ASSERT(!operatorRequiresLValue());
352 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300353 {
354 case EOpPostIncrement:
355 case EOpPostDecrement:
356 case EOpPreIncrement:
357 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300358 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300359 break;
360 default:
361 break;
362 }
363
Olli Etuaho27446bd2015-08-10 14:59:53 +0300364 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300365
Olli Etuaho27446bd2015-08-10 14:59:53 +0300366 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300367
Olli Etuaho27446bd2015-08-10 14:59:53 +0300368 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700369 }
370
Olli Etuaho27446bd2015-08-10 14:59:53 +0300371 if (visit && postVisit)
372 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373}
374
375//
376// Traverse an aggregate node. Same comments in binary node apply here.
377//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300378void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700380 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381
Olli Etuaho27446bd2015-08-10 14:59:53 +0300382 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300383
384 if (preVisit)
385 visit = visitAggregate(PreVisit, node);
386
387 if (visit)
388 {
389 incrementDepth(node);
390
391 if (node->getOp() == EOpSequence)
392 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300393 else if (node->getOp() == EOpFunction)
394 mInGlobalScope = false;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300395
396 for (auto *child : *sequence)
397 {
398 child->traverse(this);
399 if (visit && inVisit)
400 {
401 if (child != sequence->back())
402 visit = visitAggregate(InVisit, node);
403 }
404
405 if (node->getOp() == EOpSequence)
406 incrementParentBlockPos();
407 }
408
409 if (node->getOp() == EOpSequence)
410 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300411 else if (node->getOp() == EOpFunction)
412 mInGlobalScope = true;
Olli Etuaho3fc93372015-08-11 14:50:59 +0300413
414 decrementDepth();
415 }
416
417 if (visit && postVisit)
418 visitAggregate(PostVisit, node);
419}
420
421void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
422{
423 bool visit = true;
424
425 TIntermSequence *sequence = node->getSequence();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300426 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300427 {
428 case EOpFunction:
429 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300430 TIntermAggregate *params = sequence->front()->getAsAggregate();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300431 ASSERT(params != nullptr);
432 ASSERT(params->getOp() == EOpParameters);
Olli Etuaho5f579b12015-08-14 17:44:43 +0300433 addToFunctionMap(node->getNameObj(), params->getSequence());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300434 break;
435 }
436 case EOpPrototype:
Olli Etuaho5f579b12015-08-14 17:44:43 +0300437 addToFunctionMap(node->getNameObj(), sequence);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300438 break;
439 default:
440 break;
441 }
442
Olli Etuaho27446bd2015-08-10 14:59:53 +0300443 if (preVisit)
444 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700446 if (visit)
447 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300448 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300449 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700450 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300451 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300452 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300453 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300454 // The function is not user-defined - it is likely built-in texture function.
455 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300456 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700457 }
458 }
459
Olli Etuaho27446bd2015-08-10 14:59:53 +0300460 incrementDepth(node);
Olli Etuaho56eea882015-05-18 12:41:03 +0300461
Olli Etuahoa26ad582015-08-04 13:51:47 +0300462 if (inFunctionMap)
463 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300464 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300465 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300466 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300467 {
468 ASSERT(paramIter != params->end());
469 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300470 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300471
Olli Etuaho27446bd2015-08-10 14:59:53 +0300472 child->traverse(this);
473 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300474 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300475 if (child != sequence->back())
476 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300477 }
478
479 ++paramIter;
480 }
481
Olli Etuaho27446bd2015-08-10 14:59:53 +0300482 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300483 }
484 else
485 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300486 if (node->getOp() == EOpSequence)
487 pushParentBlock(node);
Olli Etuahod4f4c112016-04-15 15:11:24 +0300488 else if (node->getOp() == EOpFunction)
489 mInGlobalScope = false;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300490
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300491 // Find the built-in function corresponding to this op so that we can determine the
492 // in/out qualifiers of its parameters.
493 TFunction *builtInFunc = nullptr;
494 TString opString = GetOperatorString(node->getOp());
495 if (!node->isConstructor() && !opString.empty())
496 {
497 // The return type doesn't affect the mangled name of the function, which is used
498 // to look it up from the symbol table.
499 TType dummyReturnType;
500 TFunction call(&opString, &dummyReturnType, node->getOp());
501 for (auto *child : *sequence)
502 {
503 TType *paramType = child->getAsTyped()->getTypePointer();
504 TConstParameter p(paramType);
505 call.addParameter(p);
506 }
507
508 TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
509 if (sym != nullptr && sym->isFunction())
510 {
511 builtInFunc = static_cast<TFunction *>(sym);
512 ASSERT(builtInFunc->getParamCount() == sequence->size());
513 }
514 }
515
516 size_t paramIndex = 0;
517
Olli Etuaho27446bd2015-08-10 14:59:53 +0300518 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300519 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300520 TQualifier qualifier = EvqIn;
521 if (builtInFunc != nullptr)
522 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
523 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300524 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300525
Olli Etuaho27446bd2015-08-10 14:59:53 +0300526 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300527 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300528 if (child != sequence->back())
529 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300530 }
531
Olli Etuaho27446bd2015-08-10 14:59:53 +0300532 if (node->getOp() == EOpSequence)
533 incrementParentBlockPos();
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300534
535 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300536 }
537
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300538 setInFunctionCallOutParameter(false);
539
Olli Etuaho27446bd2015-08-10 14:59:53 +0300540 if (node->getOp() == EOpSequence)
541 popParentBlock();
Olli Etuahod4f4c112016-04-15 15:11:24 +0300542 else if (node->getOp() == EOpFunction)
543 mInGlobalScope = true;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300544 }
545
Olli Etuaho27446bd2015-08-10 14:59:53 +0300546 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700547 }
548
Olli Etuaho27446bd2015-08-10 14:59:53 +0300549 if (visit && postVisit)
550 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000551}
552
553//
554// Traverse a selection node. Same comments in binary node apply here.
555//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300556void TIntermTraverser::traverseSelection(TIntermSelection *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700558 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000559
Olli Etuaho27446bd2015-08-10 14:59:53 +0300560 if (preVisit)
561 visit = visitSelection(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700563 if (visit)
564 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300565 incrementDepth(node);
566 node->getCondition()->traverse(this);
567 if (node->getTrueBlock())
568 node->getTrueBlock()->traverse(this);
569 if (node->getFalseBlock())
570 node->getFalseBlock()->traverse(this);
571 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700572 }
573
Olli Etuaho27446bd2015-08-10 14:59:53 +0300574 if (visit && postVisit)
575 visitSelection(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576}
577
578//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200579// Traverse a switch node. Same comments in binary node apply here.
580//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300581void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200582{
583 bool visit = true;
584
Olli Etuaho27446bd2015-08-10 14:59:53 +0300585 if (preVisit)
586 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200587
588 if (visit)
589 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300590 incrementDepth(node);
591 node->getInit()->traverse(this);
592 if (inVisit)
593 visit = visitSwitch(InVisit, node);
594 if (visit && node->getStatementList())
595 node->getStatementList()->traverse(this);
596 decrementDepth();
Olli Etuahoa3a36662015-02-17 13:46:51 +0200597 }
598
Olli Etuaho27446bd2015-08-10 14:59:53 +0300599 if (visit && postVisit)
600 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200601}
602
603//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300604// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200605//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300606void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200607{
608 bool visit = true;
609
Olli Etuaho27446bd2015-08-10 14:59:53 +0300610 if (preVisit)
611 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200612
Olli Etuaho27446bd2015-08-10 14:59:53 +0300613 if (visit && node->getCondition())
614 node->getCondition()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200615
Olli Etuaho27446bd2015-08-10 14:59:53 +0300616 if (visit && postVisit)
617 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200618}
619
620//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621// Traverse a loop node. Same comments in binary node apply here.
622//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300623void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000624{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700625 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000626
Olli Etuaho27446bd2015-08-10 14:59:53 +0300627 if (preVisit)
628 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000629
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700630 if (visit)
631 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300632 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000633
Olli Etuaho27446bd2015-08-10 14:59:53 +0300634 if (node->getInit())
635 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000636
Olli Etuaho27446bd2015-08-10 14:59:53 +0300637 if (node->getCondition())
638 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000639
Olli Etuaho27446bd2015-08-10 14:59:53 +0300640 if (node->getBody())
641 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700642
Olli Etuaho27446bd2015-08-10 14:59:53 +0300643 if (node->getExpression())
644 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000645
Olli Etuaho27446bd2015-08-10 14:59:53 +0300646 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700647 }
648
Olli Etuaho27446bd2015-08-10 14:59:53 +0300649 if (visit && postVisit)
650 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000651}
652
653//
654// Traverse a branch node. Same comments in binary node apply here.
655//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300656void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000657{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700658 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000659
Olli Etuaho27446bd2015-08-10 14:59:53 +0300660 if (preVisit)
661 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000662
Olli Etuaho27446bd2015-08-10 14:59:53 +0300663 if (visit && node->getExpression())
664 {
665 incrementDepth(node);
666 node->getExpression()->traverse(this);
667 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700668 }
669
Olli Etuaho27446bd2015-08-10 14:59:53 +0300670 if (visit && postVisit)
671 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000672}
673
Olli Etuaho27446bd2015-08-10 14:59:53 +0300674void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400675{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300676 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400677}