blob: 6c25c6c35a5dbf80b9539928359e6f313a9ca80d [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
Olli Etuahocccf2b02017-07-05 14:50:54 +03007#include "compiler/translator/IntermTraverse.h"
8
Olli Etuahod4f303e2015-05-20 17:09:06 +03009#include "compiler/translator/InfoSink.h"
Olli Etuaho180f43c2017-10-09 17:00:44 +030010#include "compiler/translator/IntermNode_util.h"
Olli Etuaho217fe6e2015-08-05 13:25:08 +030011#include "compiler/translator/SymbolTable.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000012
Jamie Madill45bcc782016-11-07 13:58:48 -050013namespace sh
14{
15
Olli Etuaho27446bd2015-08-10 14:59:53 +030016void TIntermSymbol::traverse(TIntermTraverser *it)
17{
18 it->traverseSymbol(this);
19}
20
21void TIntermRaw::traverse(TIntermTraverser *it)
22{
23 it->traverseRaw(this);
24}
25
26void TIntermConstantUnion::traverse(TIntermTraverser *it)
27{
28 it->traverseConstantUnion(this);
29}
30
Olli Etuahob6fa0432016-09-28 16:28:05 +010031void TIntermSwizzle::traverse(TIntermTraverser *it)
32{
33 it->traverseSwizzle(this);
34}
35
Olli Etuaho27446bd2015-08-10 14:59:53 +030036void TIntermBinary::traverse(TIntermTraverser *it)
37{
38 it->traverseBinary(this);
39}
40
41void TIntermUnary::traverse(TIntermTraverser *it)
42{
43 it->traverseUnary(this);
44}
45
Olli Etuahod0bad2c2016-09-09 18:01:16 +030046void TIntermTernary::traverse(TIntermTraverser *it)
47{
48 it->traverseTernary(this);
49}
50
Olli Etuaho57961272016-09-14 13:57:46 +030051void TIntermIfElse::traverse(TIntermTraverser *it)
Olli Etuaho27446bd2015-08-10 14:59:53 +030052{
Olli Etuaho57961272016-09-14 13:57:46 +030053 it->traverseIfElse(this);
Olli Etuaho27446bd2015-08-10 14:59:53 +030054}
55
56void TIntermSwitch::traverse(TIntermTraverser *it)
57{
58 it->traverseSwitch(this);
59}
60
61void TIntermCase::traverse(TIntermTraverser *it)
62{
63 it->traverseCase(this);
64}
65
Olli Etuaho336b1472016-10-05 16:37:55 +010066void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
67{
68 it->traverseFunctionDefinition(this);
69}
70
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010071void TIntermBlock::traverse(TIntermTraverser *it)
72{
73 it->traverseBlock(this);
74}
75
Olli Etuahobf4e1b72016-12-09 11:30:15 +000076void TIntermInvariantDeclaration::traverse(TIntermTraverser *it)
77{
78 it->traverseInvariantDeclaration(this);
79}
80
Olli Etuaho13389b62016-10-16 11:48:18 +010081void TIntermDeclaration::traverse(TIntermTraverser *it)
82{
83 it->traverseDeclaration(this);
84}
85
Olli Etuaho16c745a2017-01-16 17:02:27 +000086void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
87{
88 it->traverseFunctionPrototype(this);
89}
90
Olli Etuaho27446bd2015-08-10 14:59:53 +030091void TIntermAggregate::traverse(TIntermTraverser *it)
92{
93 it->traverseAggregate(this);
94}
95
96void TIntermLoop::traverse(TIntermTraverser *it)
97{
98 it->traverseLoop(this);
99}
100
101void TIntermBranch::traverse(TIntermTraverser *it)
102{
103 it->traverseBranch(this);
104}
105
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300106TIntermTraverser::TIntermTraverser(bool preVisit,
107 bool inVisit,
108 bool postVisit,
109 TSymbolTable *symbolTable)
Jamie Madill03d863c2016-07-27 18:15:53 -0400110 : preVisit(preVisit),
111 inVisit(inVisit),
112 postVisit(postVisit),
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000113 mDepth(-1),
Jamie Madill03d863c2016-07-27 18:15:53 -0400114 mMaxDepth(0),
115 mInGlobalScope(true),
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300116 mSymbolTable(symbolTable),
Olli Etuaho4dd06d52017-07-05 12:41:06 +0300117 mTemporaryId(nullptr)
Jamie Madill03d863c2016-07-27 18:15:53 -0400118{
119}
120
121TIntermTraverser::~TIntermTraverser()
122{
123}
124
Olli Etuahobb27c3a2017-11-15 16:32:25 +0200125const TIntermBlock *TIntermTraverser::getParentBlock() const
126{
127 if (!mParentBlockStack.empty())
128 {
129 return mParentBlockStack.back().node;
130 }
131 return nullptr;
132}
133
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100134void TIntermTraverser::pushParentBlock(TIntermBlock *node)
Olli Etuaho56eea882015-05-18 12:41:03 +0300135{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300136 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +0300137}
138
139void TIntermTraverser::incrementParentBlockPos()
140{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300141 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +0300142}
143
144void TIntermTraverser::popParentBlock()
145{
146 ASSERT(!mParentBlockStack.empty());
147 mParentBlockStack.pop_back();
148}
149
150void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
151{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300152 TIntermSequence emptyInsertionsAfter;
153 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
154}
155
156void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
157 const TIntermSequence &insertionsAfter)
158{
Olli Etuaho56eea882015-05-18 12:41:03 +0300159 ASSERT(!mParentBlockStack.empty());
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000160 ParentBlock &parentBlock = mParentBlockStack.back();
161 if (mPath.back() == parentBlock.node)
162 {
163 ASSERT(mParentBlockStack.size() >= 2u);
164 // The current node is a block node, so the parent block is not the topmost one in the block
165 // stack, but the one below that.
166 parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
167 }
168 NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
169 insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300170 mInsertions.push_back(insert);
171}
172
Jamie Madill1048e432016-07-23 18:51:28 -0400173void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
174{
175 TIntermSequence insertions;
176 insertions.push_back(statement);
177 insertStatementsInParentBlock(insertions);
178}
179
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300180TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300181{
Olli Etuaho4dd06d52017-07-05 12:41:06 +0300182 ASSERT(mTemporaryId != nullptr);
Olli Etuaho180f43c2017-10-09 17:00:44 +0300183 // nextTemporaryId() needs to be called when the code wants to start using another temporary
184 // symbol.
185 return CreateTempSymbolNode(*mTemporaryId, type, qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300186}
187
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300188TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
189{
190 return createTempSymbol(type, EvqTemporary);
191}
192
Olli Etuaho13389b62016-10-16 11:48:18 +0100193TIntermDeclaration *TIntermTraverser::createTempDeclaration(const TType &type)
Olli Etuaho4f1af782015-05-25 11:55:07 +0300194{
Olli Etuaho180f43c2017-10-09 17:00:44 +0300195 ASSERT(mTemporaryId != nullptr);
Olli Etuaho13389b62016-10-16 11:48:18 +0100196 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
Olli Etuaho180f43c2017-10-09 17:00:44 +0300197 tempDeclaration->appendDeclarator(CreateTempSymbolNode(*mTemporaryId, type, EvqTemporary));
Olli Etuaho4f1af782015-05-25 11:55:07 +0300198 return tempDeclaration;
199}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300200
Olli Etuaho13389b62016-10-16 11:48:18 +0100201TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer,
202 TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300203{
Olli Etuaho180f43c2017-10-09 17:00:44 +0300204 ASSERT(mTemporaryId != nullptr);
205 return CreateTempInitDeclarationNode(*mTemporaryId, initializer, qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300206}
207
Olli Etuaho13389b62016-10-16 11:48:18 +0100208TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300209{
210 return createTempInitDeclaration(initializer, EvqTemporary);
211}
212
Olli Etuahod4f303e2015-05-20 17:09:06 +0300213TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
214{
215 ASSERT(rightNode != nullptr);
216 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300217 TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300218 return assignment;
219}
220
Olli Etuaho4dd06d52017-07-05 12:41:06 +0300221void TIntermTraverser::nextTemporaryId()
Olli Etuahod4f303e2015-05-20 17:09:06 +0300222{
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300223 ASSERT(mSymbolTable);
224 if (!mTemporaryId)
225 {
226 mTemporaryId = new TSymbolUniqueId(mSymbolTable);
227 return;
228 }
229 *mTemporaryId = TSymbolUniqueId(mSymbolTable);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300230}
231
Olli Etuahofe486322017-03-21 09:30:54 +0000232void TLValueTrackingTraverser::addToFunctionMap(const TSymbolUniqueId &id,
233 TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300234{
Olli Etuahofe486322017-03-21 09:30:54 +0000235 mFunctionMap[id.get()] = paramSequence;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300236}
237
Olli Etuaho3fc93372015-08-11 14:50:59 +0300238bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300239{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800240 ASSERT(callNode->getOp() == EOpCallFunctionInAST);
Olli Etuahofe486322017-03-21 09:30:54 +0000241 return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getId().get()) !=
Olli Etuahobd674552016-10-06 13:28:42 +0100242 mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300243}
244
Olli Etuaho3fc93372015-08-11 14:50:59 +0300245TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300246{
247 ASSERT(isInFunctionMap(callNode));
Olli Etuahofe486322017-03-21 09:30:54 +0000248 return mFunctionMap[callNode->getFunctionSymbolInfo()->getId().get()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300249}
250
Olli Etuaho3fc93372015-08-11 14:50:59 +0300251void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300252{
253 mInFunctionCallOutParameter = inOutParameter;
254}
255
Olli Etuaho3fc93372015-08-11 14:50:59 +0300256bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300257{
258 return mInFunctionCallOutParameter;
259}
260
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261//
262// Traverse the intermediate representation tree, and
263// call a node type specific function for each node.
264// Done recursively through the member function Traverse().
265// Node types can be skipped if their function to call is 0,
266// but their subtree will still be traversed.
267// Nodes with children can have their whole subtree skipped
268// if preVisit is turned on and the type specific function
269// returns false.
270//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271
272//
273// Traversal functions for terminals are straighforward....
274//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300275void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000277 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300278 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279}
280
Olli Etuaho27446bd2015-08-10 14:59:53 +0300281void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000282{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000283 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300284 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285}
286
Olli Etuahob6fa0432016-09-28 16:28:05 +0100287void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
288{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000289 ScopedNodeInTraversalPath addToPath(this, node);
290
Olli Etuahob6fa0432016-09-28 16:28:05 +0100291 bool visit = true;
292
293 if (preVisit)
294 visit = visitSwizzle(PreVisit, node);
295
296 if (visit)
297 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100298 node->getOperand()->traverse(this);
Olli Etuahob6fa0432016-09-28 16:28:05 +0100299 }
300
301 if (visit && postVisit)
302 visitSwizzle(PostVisit, node);
303}
304
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305//
306// Traverse a binary node.
307//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300308void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000310 ScopedNodeInTraversalPath addToPath(this, node);
311
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700312 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700314 //
315 // visit the node before children if pre-visiting.
316 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300317 if (preVisit)
318 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700320 //
321 // Visit the children, in the right order.
322 //
323 if (visit)
324 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300325 if (node->getLeft())
326 node->getLeft()->traverse(this);
327
328 if (inVisit)
329 visit = visitBinary(InVisit, node);
330
331 if (visit && node->getRight())
332 node->getRight()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300333 }
334
335 //
336 // Visit the node after the children, if requested and the traversal
337 // hasn't been cancelled yet.
338 //
339 if (visit && postVisit)
340 visitBinary(PostVisit, node);
341}
342
343void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
344{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000345 ScopedNodeInTraversalPath addToPath(this, node);
346
Olli Etuaho3fc93372015-08-11 14:50:59 +0300347 bool visit = true;
348
349 //
350 // visit the node before children if pre-visiting.
351 //
352 if (preVisit)
353 visit = visitBinary(PreVisit, node);
354
355 //
356 // Visit the children, in the right order.
357 //
358 if (visit)
359 {
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300360 // Some binary operations like indexing can be inside an expression which must be an
361 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300362 bool parentOperatorRequiresLValue = operatorRequiresLValue();
363 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
364 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300365 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300366 ASSERT(!isLValueRequiredHere());
367 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300368 }
369
Olli Etuaho27446bd2015-08-10 14:59:53 +0300370 if (node->getLeft())
371 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000372
Olli Etuaho27446bd2015-08-10 14:59:53 +0300373 if (inVisit)
374 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000375
Olli Etuaho27446bd2015-08-10 14:59:53 +0300376 if (node->isAssignment())
377 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300378
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300379 // Index is not required to be an l-value even when the surrounding expression is required
380 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300381 TOperator op = node->getOp();
382 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
383 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300384 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300385 setOperatorRequiresLValue(false);
386 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300387 }
388
Olli Etuaho27446bd2015-08-10 14:59:53 +0300389 if (visit && node->getRight())
390 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700391
Olli Etuaho27446bd2015-08-10 14:59:53 +0300392 setOperatorRequiresLValue(parentOperatorRequiresLValue);
393 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700394 }
395
396 //
397 // Visit the node after the children, if requested and the traversal
398 // hasn't been cancelled yet.
399 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300400 if (visit && postVisit)
401 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402}
403
404//
405// Traverse a unary node. Same comments in binary node apply here.
406//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300407void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000408{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000409 ScopedNodeInTraversalPath addToPath(this, node);
410
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700411 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000412
Olli Etuaho27446bd2015-08-10 14:59:53 +0300413 if (preVisit)
414 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415
Olli Etuahoa26ad582015-08-04 13:51:47 +0300416 if (visit)
417 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300418 node->getOperand()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300419 }
420
421 if (visit && postVisit)
422 visitUnary(PostVisit, node);
423}
424
425void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
426{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000427 ScopedNodeInTraversalPath addToPath(this, node);
428
Olli Etuaho3fc93372015-08-11 14:50:59 +0300429 bool visit = true;
430
431 if (preVisit)
432 visit = visitUnary(PreVisit, node);
433
434 if (visit)
435 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300436 ASSERT(!operatorRequiresLValue());
437 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300438 {
439 case EOpPostIncrement:
440 case EOpPostDecrement:
441 case EOpPreIncrement:
442 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300443 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300444 break;
445 default:
446 break;
447 }
448
Olli Etuaho27446bd2015-08-10 14:59:53 +0300449 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300450
Olli Etuaho27446bd2015-08-10 14:59:53 +0300451 setOperatorRequiresLValue(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700452 }
453
Olli Etuaho27446bd2015-08-10 14:59:53 +0300454 if (visit && postVisit)
455 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456}
457
Olli Etuaho336b1472016-10-05 16:37:55 +0100458// Traverse a function definition node.
459void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
460{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000461 ScopedNodeInTraversalPath addToPath(this, node);
462
Olli Etuaho336b1472016-10-05 16:37:55 +0100463 bool visit = true;
464
465 if (preVisit)
466 visit = visitFunctionDefinition(PreVisit, node);
467
468 if (visit)
469 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100470 mInGlobalScope = false;
471
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000472 node->getFunctionPrototype()->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100473 if (inVisit)
474 visit = visitFunctionDefinition(InVisit, node);
475 node->getBody()->traverse(this);
476
477 mInGlobalScope = true;
Olli Etuaho336b1472016-10-05 16:37:55 +0100478 }
479
480 if (visit && postVisit)
481 visitFunctionDefinition(PostVisit, node);
482}
483
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100484// Traverse a block node.
485void TIntermTraverser::traverseBlock(TIntermBlock *node)
486{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000487 ScopedNodeInTraversalPath addToPath(this, node);
488 pushParentBlock(node);
489
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100490 bool visit = true;
491
492 TIntermSequence *sequence = node->getSequence();
493
494 if (preVisit)
495 visit = visitBlock(PreVisit, node);
496
497 if (visit)
498 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100499 for (auto *child : *sequence)
500 {
501 child->traverse(this);
502 if (visit && inVisit)
503 {
504 if (child != sequence->back())
505 visit = visitBlock(InVisit, node);
506 }
507
508 incrementParentBlockPos();
509 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100510 }
511
512 if (visit && postVisit)
513 visitBlock(PostVisit, node);
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000514
515 popParentBlock();
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100516}
517
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000518void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
519{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000520 ScopedNodeInTraversalPath addToPath(this, node);
521
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000522 bool visit = true;
523
524 if (preVisit)
525 {
526 visit = visitInvariantDeclaration(PreVisit, node);
527 }
528
529 if (visit)
530 {
531 node->getSymbol()->traverse(this);
532 if (postVisit)
533 {
534 visitInvariantDeclaration(PostVisit, node);
535 }
536 }
537}
538
Olli Etuaho13389b62016-10-16 11:48:18 +0100539// Traverse a declaration node.
540void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
541{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000542 ScopedNodeInTraversalPath addToPath(this, node);
543
Olli Etuaho13389b62016-10-16 11:48:18 +0100544 bool visit = true;
545
546 TIntermSequence *sequence = node->getSequence();
547
548 if (preVisit)
549 visit = visitDeclaration(PreVisit, node);
550
551 if (visit)
552 {
Olli Etuaho13389b62016-10-16 11:48:18 +0100553 for (auto *child : *sequence)
554 {
555 child->traverse(this);
556 if (visit && inVisit)
557 {
558 if (child != sequence->back())
559 visit = visitDeclaration(InVisit, node);
560 }
561 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100562 }
563
564 if (visit && postVisit)
565 visitDeclaration(PostVisit, node);
566}
567
Olli Etuaho16c745a2017-01-16 17:02:27 +0000568void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
569{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000570 ScopedNodeInTraversalPath addToPath(this, node);
571
Olli Etuaho16c745a2017-01-16 17:02:27 +0000572 bool visit = true;
573
574 TIntermSequence *sequence = node->getSequence();
575
576 if (preVisit)
577 visit = visitFunctionPrototype(PreVisit, node);
578
579 if (visit)
580 {
Olli Etuaho16c745a2017-01-16 17:02:27 +0000581 for (auto *child : *sequence)
582 {
583 child->traverse(this);
584 if (visit && inVisit)
585 {
586 if (child != sequence->back())
587 visit = visitFunctionPrototype(InVisit, node);
588 }
589 }
Olli Etuaho16c745a2017-01-16 17:02:27 +0000590 }
591
592 if (visit && postVisit)
593 visitFunctionPrototype(PostVisit, node);
594}
595
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000596// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300597void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000598{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000599 ScopedNodeInTraversalPath addToPath(this, node);
600
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700601 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000602
Olli Etuaho27446bd2015-08-10 14:59:53 +0300603 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300604
605 if (preVisit)
606 visit = visitAggregate(PreVisit, node);
607
608 if (visit)
609 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300610 for (auto *child : *sequence)
611 {
612 child->traverse(this);
613 if (visit && inVisit)
614 {
615 if (child != sequence->back())
616 visit = visitAggregate(InVisit, node);
617 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300618 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300619 }
620
621 if (visit && postVisit)
622 visitAggregate(PostVisit, node);
623}
624
Olli Etuahocccf2b02017-07-05 14:50:54 +0300625bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
626 const NodeInsertMultipleEntry &b)
627{
628 if (a.parent != b.parent)
629 {
630 return a.parent > b.parent;
631 }
632 return a.position > b.position;
633}
634
635void TIntermTraverser::updateTree()
636{
637 // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
638 // the same parent node are handled correctly.
639 std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
640 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
641 {
642 // We can't know here what the intended ordering of two insertions to the same position is,
643 // so it is not supported.
644 ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
645 mInsertions[ii].parent != mInsertions[ii - 1].parent);
646 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
647 ASSERT(insertion.parent);
648 if (!insertion.insertionsAfter.empty())
649 {
650 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
651 insertion.insertionsAfter);
652 ASSERT(inserted);
653 }
654 if (!insertion.insertionsBefore.empty())
655 {
656 bool inserted =
657 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
658 ASSERT(inserted);
659 }
660 }
661 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
662 {
663 const NodeUpdateEntry &replacement = mReplacements[ii];
664 ASSERT(replacement.parent);
665 bool replaced =
666 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
667 ASSERT(replaced);
668
669 if (!replacement.originalBecomesChildOfReplacement)
670 {
671 // In AST traversing, a parent is visited before its children.
672 // After we replace a node, if its immediate child is to
673 // be replaced, we need to make sure we don't update the replaced
674 // node; instead, we update the replacement node.
675 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
676 {
677 NodeUpdateEntry &replacement2 = mReplacements[jj];
678 if (replacement2.parent == replacement.original)
679 replacement2.parent = replacement.replacement;
680 }
681 }
682 }
683 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
684 {
685 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
686 ASSERT(replacement.parent);
687 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
688 replacement.replacements);
689 ASSERT(replaced);
690 }
691
692 clearReplacementQueue();
693}
694
695void TIntermTraverser::clearReplacementQueue()
696{
697 mReplacements.clear();
698 mMultiReplacements.clear();
699 mInsertions.clear();
700}
701
Olli Etuahoea39a222017-07-06 12:47:59 +0300702void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
Olli Etuahocccf2b02017-07-05 14:50:54 +0300703{
Olli Etuahoea39a222017-07-06 12:47:59 +0300704 queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300705}
706
707void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
708 TIntermNode *original,
709 TIntermNode *replacement,
710 OriginalNode originalStatus)
711{
712 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
713 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
714}
715
Olli Etuahocccf2b02017-07-05 14:50:54 +0300716TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
717 bool inVisit,
718 bool postVisit,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300719 TSymbolTable *symbolTable,
Olli Etuahocccf2b02017-07-05 14:50:54 +0300720 int shaderVersion)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300721 : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
Olli Etuahocccf2b02017-07-05 14:50:54 +0300722 mOperatorRequiresLValue(false),
723 mInFunctionCallOutParameter(false),
Olli Etuahocccf2b02017-07-05 14:50:54 +0300724 mShaderVersion(shaderVersion)
725{
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300726 ASSERT(symbolTable);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300727}
728
Olli Etuaho16c745a2017-01-16 17:02:27 +0000729void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
730{
731 TIntermSequence *sequence = node->getSequence();
Olli Etuahofe486322017-03-21 09:30:54 +0000732 addToFunctionMap(node->getFunctionSymbolInfo()->getId(), sequence);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000733
734 TIntermTraverser::traverseFunctionPrototype(node);
735}
736
Olli Etuaho3fc93372015-08-11 14:50:59 +0300737void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
738{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000739 ScopedNodeInTraversalPath addToPath(this, node);
740
Olli Etuaho3fc93372015-08-11 14:50:59 +0300741 bool visit = true;
742
743 TIntermSequence *sequence = node->getSequence();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300744
Olli Etuaho27446bd2015-08-10 14:59:53 +0300745 if (preVisit)
746 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000747
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700748 if (visit)
749 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800750 if (node->getOp() == EOpCallFunctionInAST)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700751 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800752 if (isInFunctionMap(node))
Olli Etuaho64f0be92015-06-03 17:38:34 +0300753 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800754 TIntermSequence *params = getFunctionParameters(node);
755 TIntermSequence::iterator paramIter = params->begin();
756 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300757 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800758 ASSERT(paramIter != params->end());
759 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
760 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300761
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800762 child->traverse(this);
763 if (visit && inVisit)
764 {
765 if (child != sequence->back())
766 visit = visitAggregate(InVisit, node);
767 }
768
769 ++paramIter;
770 }
771 }
772 else
773 {
774 // The node might not be in the function map in case we're in the middle of
775 // transforming the AST, and have inserted function call nodes without inserting the
776 // function definitions yet.
777 setInFunctionCallOutParameter(false);
778 for (auto *child : *sequence)
779 {
780 child->traverse(this);
781 if (visit && inVisit)
782 {
783 if (child != sequence->back())
784 visit = visitAggregate(InVisit, node);
785 }
786 }
Olli Etuahoa26ad582015-08-04 13:51:47 +0300787 }
788
Olli Etuaho27446bd2015-08-10 14:59:53 +0300789 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300790 }
791 else
792 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300793 // Find the built-in function corresponding to this op so that we can determine the
794 // in/out qualifiers of its parameters.
795 TFunction *builtInFunc = nullptr;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800796 if (!node->isFunctionCall() && !node->isConstructor())
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300797 {
Olli Etuahof2209f72017-04-01 12:45:55 +0300798 builtInFunc = static_cast<TFunction *>(
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300799 mSymbolTable->findBuiltIn(node->getSymbolTableMangledName(), mShaderVersion));
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300800 }
801
802 size_t paramIndex = 0;
803
Olli Etuaho27446bd2015-08-10 14:59:53 +0300804 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300805 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800806 // This assumes that raw functions called with
807 // EOpCallInternalRawFunction don't have out parameters.
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300808 TQualifier qualifier = EvqIn;
809 if (builtInFunc != nullptr)
810 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
811 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300812 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300813
Olli Etuaho27446bd2015-08-10 14:59:53 +0300814 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300815 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300816 if (child != sequence->back())
817 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300818 }
819
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300820 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300821 }
822
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300823 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300824 }
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700825 }
826
Olli Etuaho27446bd2015-08-10 14:59:53 +0300827 if (visit && postVisit)
828 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000829}
830
831//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300832// Traverse a ternary node. Same comments in binary node apply here.
833//
834void TIntermTraverser::traverseTernary(TIntermTernary *node)
835{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000836 ScopedNodeInTraversalPath addToPath(this, node);
837
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300838 bool visit = true;
839
840 if (preVisit)
841 visit = visitTernary(PreVisit, node);
842
843 if (visit)
844 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300845 node->getCondition()->traverse(this);
846 if (node->getTrueExpression())
847 node->getTrueExpression()->traverse(this);
848 if (node->getFalseExpression())
849 node->getFalseExpression()->traverse(this);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300850 }
851
852 if (visit && postVisit)
853 visitTernary(PostVisit, node);
854}
855
Olli Etuaho57961272016-09-14 13:57:46 +0300856// Traverse an if-else node. Same comments in binary node apply here.
857void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000858{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000859 ScopedNodeInTraversalPath addToPath(this, node);
860
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700861 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000862
Olli Etuaho27446bd2015-08-10 14:59:53 +0300863 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300864 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000865
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700866 if (visit)
867 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300868 node->getCondition()->traverse(this);
869 if (node->getTrueBlock())
870 node->getTrueBlock()->traverse(this);
871 if (node->getFalseBlock())
872 node->getFalseBlock()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700873 }
874
Olli Etuaho27446bd2015-08-10 14:59:53 +0300875 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300876 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000877}
878
879//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200880// Traverse a switch node. Same comments in binary node apply here.
881//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300882void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200883{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000884 ScopedNodeInTraversalPath addToPath(this, node);
885
Olli Etuahoa3a36662015-02-17 13:46:51 +0200886 bool visit = true;
887
Olli Etuaho27446bd2015-08-10 14:59:53 +0300888 if (preVisit)
889 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200890
891 if (visit)
892 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300893 node->getInit()->traverse(this);
894 if (inVisit)
895 visit = visitSwitch(InVisit, node);
896 if (visit && node->getStatementList())
897 node->getStatementList()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200898 }
899
Olli Etuaho27446bd2015-08-10 14:59:53 +0300900 if (visit && postVisit)
901 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200902}
903
904//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300905// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200906//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300907void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200908{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000909 ScopedNodeInTraversalPath addToPath(this, node);
910
Olli Etuahoa3a36662015-02-17 13:46:51 +0200911 bool visit = true;
912
Olli Etuaho27446bd2015-08-10 14:59:53 +0300913 if (preVisit)
914 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200915
Olli Etuaho27446bd2015-08-10 14:59:53 +0300916 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100917 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300918 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100919 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200920
Olli Etuaho27446bd2015-08-10 14:59:53 +0300921 if (visit && postVisit)
922 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200923}
924
925//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000926// Traverse a loop node. Same comments in binary node apply here.
927//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300928void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000929{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000930 ScopedNodeInTraversalPath addToPath(this, node);
931
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700932 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000933
Olli Etuaho27446bd2015-08-10 14:59:53 +0300934 if (preVisit)
935 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000936
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700937 if (visit)
938 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300939 if (node->getInit())
940 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000941
Olli Etuaho27446bd2015-08-10 14:59:53 +0300942 if (node->getCondition())
943 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000944
Olli Etuaho27446bd2015-08-10 14:59:53 +0300945 if (node->getBody())
946 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700947
Olli Etuaho27446bd2015-08-10 14:59:53 +0300948 if (node->getExpression())
949 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700950 }
951
Olli Etuaho27446bd2015-08-10 14:59:53 +0300952 if (visit && postVisit)
953 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954}
955
956//
957// Traverse a branch node. Same comments in binary node apply here.
958//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300959void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000960{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000961 ScopedNodeInTraversalPath addToPath(this, node);
962
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700963 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964
Olli Etuaho27446bd2015-08-10 14:59:53 +0300965 if (preVisit)
966 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000967
Olli Etuaho27446bd2015-08-10 14:59:53 +0300968 if (visit && node->getExpression())
969 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300970 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700971 }
972
Olli Etuaho27446bd2015-08-10 14:59:53 +0300973 if (visit && postVisit)
974 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000975}
976
Olli Etuaho27446bd2015-08-10 14:59:53 +0300977void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400978{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000979 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300980 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400981}
Jamie Madill45bcc782016-11-07 13:58:48 -0500982
983} // namespace sh