blob: 8c45d75b569a55909601b777521a9b4034d2cb3a [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 Etuaho195be942017-12-04 23:40:14 +0200116 mSymbolTable(symbolTable)
Jamie Madill03d863c2016-07-27 18:15:53 -0400117{
118}
119
120TIntermTraverser::~TIntermTraverser()
121{
122}
123
Olli Etuahobb27c3a2017-11-15 16:32:25 +0200124const TIntermBlock *TIntermTraverser::getParentBlock() const
125{
126 if (!mParentBlockStack.empty())
127 {
128 return mParentBlockStack.back().node;
129 }
130 return nullptr;
131}
132
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100133void TIntermTraverser::pushParentBlock(TIntermBlock *node)
Olli Etuaho56eea882015-05-18 12:41:03 +0300134{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300135 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +0300136}
137
138void TIntermTraverser::incrementParentBlockPos()
139{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300140 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +0300141}
142
143void TIntermTraverser::popParentBlock()
144{
145 ASSERT(!mParentBlockStack.empty());
146 mParentBlockStack.pop_back();
147}
148
149void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
150{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300151 TIntermSequence emptyInsertionsAfter;
152 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
153}
154
155void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
156 const TIntermSequence &insertionsAfter)
157{
Olli Etuaho56eea882015-05-18 12:41:03 +0300158 ASSERT(!mParentBlockStack.empty());
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000159 ParentBlock &parentBlock = mParentBlockStack.back();
160 if (mPath.back() == parentBlock.node)
161 {
162 ASSERT(mParentBlockStack.size() >= 2u);
163 // The current node is a block node, so the parent block is not the topmost one in the block
164 // stack, but the one below that.
165 parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
166 }
167 NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
168 insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300169 mInsertions.push_back(insert);
170}
171
Jamie Madill1048e432016-07-23 18:51:28 -0400172void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
173{
174 TIntermSequence insertions;
175 insertions.push_back(statement);
176 insertStatementsInParentBlock(insertions);
177}
178
Olli Etuahofe486322017-03-21 09:30:54 +0000179void TLValueTrackingTraverser::addToFunctionMap(const TSymbolUniqueId &id,
180 TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300181{
Olli Etuahofe486322017-03-21 09:30:54 +0000182 mFunctionMap[id.get()] = paramSequence;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300183}
184
Olli Etuaho3fc93372015-08-11 14:50:59 +0300185bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300186{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800187 ASSERT(callNode->getOp() == EOpCallFunctionInAST);
Olli Etuaho1bb85282017-12-14 13:39:53 +0200188 return (mFunctionMap.find(callNode->getFunction()->uniqueId().get()) != mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300189}
190
Olli Etuaho3fc93372015-08-11 14:50:59 +0300191TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300192{
193 ASSERT(isInFunctionMap(callNode));
Olli Etuaho1bb85282017-12-14 13:39:53 +0200194 return mFunctionMap[callNode->getFunction()->uniqueId().get()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300195}
196
Olli Etuaho3fc93372015-08-11 14:50:59 +0300197void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300198{
199 mInFunctionCallOutParameter = inOutParameter;
200}
201
Olli Etuaho3fc93372015-08-11 14:50:59 +0300202bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300203{
204 return mInFunctionCallOutParameter;
205}
206
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207//
208// Traverse the intermediate representation tree, and
209// call a node type specific function for each node.
210// Done recursively through the member function Traverse().
211// Node types can be skipped if their function to call is 0,
212// but their subtree will still be traversed.
213// Nodes with children can have their whole subtree skipped
214// if preVisit is turned on and the type specific function
215// returns false.
216//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217
218//
219// Traversal functions for terminals are straighforward....
220//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300221void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000223 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300224 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225}
226
Olli Etuaho27446bd2015-08-10 14:59:53 +0300227void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000229 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300230 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231}
232
Olli Etuahob6fa0432016-09-28 16:28:05 +0100233void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
234{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000235 ScopedNodeInTraversalPath addToPath(this, node);
236
Olli Etuahob6fa0432016-09-28 16:28:05 +0100237 bool visit = true;
238
239 if (preVisit)
240 visit = visitSwizzle(PreVisit, node);
241
242 if (visit)
243 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100244 node->getOperand()->traverse(this);
Olli Etuahob6fa0432016-09-28 16:28:05 +0100245 }
246
247 if (visit && postVisit)
248 visitSwizzle(PostVisit, node);
249}
250
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000251//
252// Traverse a binary node.
253//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300254void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000255{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000256 ScopedNodeInTraversalPath addToPath(this, node);
257
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700258 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700260 //
261 // visit the node before children if pre-visiting.
262 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300263 if (preVisit)
264 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000265
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700266 //
267 // Visit the children, in the right order.
268 //
269 if (visit)
270 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300271 if (node->getLeft())
272 node->getLeft()->traverse(this);
273
274 if (inVisit)
275 visit = visitBinary(InVisit, node);
276
277 if (visit && node->getRight())
278 node->getRight()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300279 }
280
281 //
282 // Visit the node after the children, if requested and the traversal
283 // hasn't been cancelled yet.
284 //
285 if (visit && postVisit)
286 visitBinary(PostVisit, node);
287}
288
289void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
290{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000291 ScopedNodeInTraversalPath addToPath(this, node);
292
Olli Etuaho3fc93372015-08-11 14:50:59 +0300293 bool visit = true;
294
295 //
296 // visit the node before children if pre-visiting.
297 //
298 if (preVisit)
299 visit = visitBinary(PreVisit, node);
300
301 //
302 // Visit the children, in the right order.
303 //
304 if (visit)
305 {
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300306 // Some binary operations like indexing can be inside an expression which must be an
307 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300308 bool parentOperatorRequiresLValue = operatorRequiresLValue();
309 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
310 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300311 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300312 ASSERT(!isLValueRequiredHere());
313 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300314 }
315
Olli Etuaho27446bd2015-08-10 14:59:53 +0300316 if (node->getLeft())
317 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318
Olli Etuaho27446bd2015-08-10 14:59:53 +0300319 if (inVisit)
320 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321
Olli Etuaho27446bd2015-08-10 14:59:53 +0300322 if (node->isAssignment())
323 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300324
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300325 // Index is not required to be an l-value even when the surrounding expression is required
326 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300327 TOperator op = node->getOp();
328 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
329 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300330 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300331 setOperatorRequiresLValue(false);
332 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300333 }
334
Olli Etuaho27446bd2015-08-10 14:59:53 +0300335 if (visit && node->getRight())
336 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700337
Olli Etuaho27446bd2015-08-10 14:59:53 +0300338 setOperatorRequiresLValue(parentOperatorRequiresLValue);
339 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700340 }
341
342 //
343 // Visit the node after the children, if requested and the traversal
344 // hasn't been cancelled yet.
345 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300346 if (visit && postVisit)
347 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348}
349
350//
351// Traverse a unary node. Same comments in binary node apply here.
352//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300353void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000355 ScopedNodeInTraversalPath addToPath(this, node);
356
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700357 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000358
Olli Etuaho27446bd2015-08-10 14:59:53 +0300359 if (preVisit)
360 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361
Olli Etuahoa26ad582015-08-04 13:51:47 +0300362 if (visit)
363 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300364 node->getOperand()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300365 }
366
367 if (visit && postVisit)
368 visitUnary(PostVisit, node);
369}
370
371void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
372{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000373 ScopedNodeInTraversalPath addToPath(this, node);
374
Olli Etuaho3fc93372015-08-11 14:50:59 +0300375 bool visit = true;
376
377 if (preVisit)
378 visit = visitUnary(PreVisit, node);
379
380 if (visit)
381 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300382 ASSERT(!operatorRequiresLValue());
383 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300384 {
385 case EOpPostIncrement:
386 case EOpPostDecrement:
387 case EOpPreIncrement:
388 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300389 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300390 break;
391 default:
392 break;
393 }
394
Olli Etuaho27446bd2015-08-10 14:59:53 +0300395 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300396
Olli Etuaho27446bd2015-08-10 14:59:53 +0300397 setOperatorRequiresLValue(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700398 }
399
Olli Etuaho27446bd2015-08-10 14:59:53 +0300400 if (visit && postVisit)
401 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402}
403
Olli Etuaho336b1472016-10-05 16:37:55 +0100404// Traverse a function definition node.
405void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
406{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000407 ScopedNodeInTraversalPath addToPath(this, node);
408
Olli Etuaho336b1472016-10-05 16:37:55 +0100409 bool visit = true;
410
411 if (preVisit)
412 visit = visitFunctionDefinition(PreVisit, node);
413
414 if (visit)
415 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100416 mInGlobalScope = false;
417
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000418 node->getFunctionPrototype()->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100419 if (inVisit)
420 visit = visitFunctionDefinition(InVisit, node);
421 node->getBody()->traverse(this);
422
423 mInGlobalScope = true;
Olli Etuaho336b1472016-10-05 16:37:55 +0100424 }
425
426 if (visit && postVisit)
427 visitFunctionDefinition(PostVisit, node);
428}
429
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100430// Traverse a block node.
431void TIntermTraverser::traverseBlock(TIntermBlock *node)
432{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000433 ScopedNodeInTraversalPath addToPath(this, node);
434 pushParentBlock(node);
435
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100436 bool visit = true;
437
438 TIntermSequence *sequence = node->getSequence();
439
440 if (preVisit)
441 visit = visitBlock(PreVisit, node);
442
443 if (visit)
444 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100445 for (auto *child : *sequence)
446 {
447 child->traverse(this);
448 if (visit && inVisit)
449 {
450 if (child != sequence->back())
451 visit = visitBlock(InVisit, node);
452 }
453
454 incrementParentBlockPos();
455 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100456 }
457
458 if (visit && postVisit)
459 visitBlock(PostVisit, node);
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000460
461 popParentBlock();
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100462}
463
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000464void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
465{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000466 ScopedNodeInTraversalPath addToPath(this, node);
467
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000468 bool visit = true;
469
470 if (preVisit)
471 {
472 visit = visitInvariantDeclaration(PreVisit, node);
473 }
474
475 if (visit)
476 {
477 node->getSymbol()->traverse(this);
478 if (postVisit)
479 {
480 visitInvariantDeclaration(PostVisit, node);
481 }
482 }
483}
484
Olli Etuaho13389b62016-10-16 11:48:18 +0100485// Traverse a declaration node.
486void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
487{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000488 ScopedNodeInTraversalPath addToPath(this, node);
489
Olli Etuaho13389b62016-10-16 11:48:18 +0100490 bool visit = true;
491
492 TIntermSequence *sequence = node->getSequence();
493
494 if (preVisit)
495 visit = visitDeclaration(PreVisit, node);
496
497 if (visit)
498 {
Olli Etuaho13389b62016-10-16 11:48:18 +0100499 for (auto *child : *sequence)
500 {
501 child->traverse(this);
502 if (visit && inVisit)
503 {
504 if (child != sequence->back())
505 visit = visitDeclaration(InVisit, node);
506 }
507 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100508 }
509
510 if (visit && postVisit)
511 visitDeclaration(PostVisit, node);
512}
513
Olli Etuaho16c745a2017-01-16 17:02:27 +0000514void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
515{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000516 ScopedNodeInTraversalPath addToPath(this, node);
517
Olli Etuaho16c745a2017-01-16 17:02:27 +0000518 bool visit = true;
519
520 TIntermSequence *sequence = node->getSequence();
521
522 if (preVisit)
523 visit = visitFunctionPrototype(PreVisit, node);
524
525 if (visit)
526 {
Olli Etuaho16c745a2017-01-16 17:02:27 +0000527 for (auto *child : *sequence)
528 {
529 child->traverse(this);
530 if (visit && inVisit)
531 {
532 if (child != sequence->back())
533 visit = visitFunctionPrototype(InVisit, node);
534 }
535 }
Olli Etuaho16c745a2017-01-16 17:02:27 +0000536 }
537
538 if (visit && postVisit)
539 visitFunctionPrototype(PostVisit, node);
540}
541
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000542// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300543void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000544{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000545 ScopedNodeInTraversalPath addToPath(this, node);
546
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700547 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548
Olli Etuaho27446bd2015-08-10 14:59:53 +0300549 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300550
551 if (preVisit)
552 visit = visitAggregate(PreVisit, node);
553
554 if (visit)
555 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300556 for (auto *child : *sequence)
557 {
558 child->traverse(this);
559 if (visit && inVisit)
560 {
561 if (child != sequence->back())
562 visit = visitAggregate(InVisit, node);
563 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300564 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300565 }
566
567 if (visit && postVisit)
568 visitAggregate(PostVisit, node);
569}
570
Olli Etuahocccf2b02017-07-05 14:50:54 +0300571bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
572 const NodeInsertMultipleEntry &b)
573{
574 if (a.parent != b.parent)
575 {
576 return a.parent > b.parent;
577 }
578 return a.position > b.position;
579}
580
581void TIntermTraverser::updateTree()
582{
583 // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
584 // the same parent node are handled correctly.
585 std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
586 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
587 {
588 // We can't know here what the intended ordering of two insertions to the same position is,
589 // so it is not supported.
590 ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
591 mInsertions[ii].parent != mInsertions[ii - 1].parent);
592 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
593 ASSERT(insertion.parent);
594 if (!insertion.insertionsAfter.empty())
595 {
596 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
597 insertion.insertionsAfter);
598 ASSERT(inserted);
599 }
600 if (!insertion.insertionsBefore.empty())
601 {
602 bool inserted =
603 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
604 ASSERT(inserted);
605 }
606 }
607 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
608 {
609 const NodeUpdateEntry &replacement = mReplacements[ii];
610 ASSERT(replacement.parent);
611 bool replaced =
612 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
613 ASSERT(replaced);
614
615 if (!replacement.originalBecomesChildOfReplacement)
616 {
617 // In AST traversing, a parent is visited before its children.
618 // After we replace a node, if its immediate child is to
619 // be replaced, we need to make sure we don't update the replaced
620 // node; instead, we update the replacement node.
621 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
622 {
623 NodeUpdateEntry &replacement2 = mReplacements[jj];
624 if (replacement2.parent == replacement.original)
625 replacement2.parent = replacement.replacement;
626 }
627 }
628 }
629 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
630 {
631 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
632 ASSERT(replacement.parent);
633 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
634 replacement.replacements);
635 ASSERT(replaced);
636 }
637
638 clearReplacementQueue();
639}
640
641void TIntermTraverser::clearReplacementQueue()
642{
643 mReplacements.clear();
644 mMultiReplacements.clear();
645 mInsertions.clear();
646}
647
Olli Etuahoea39a222017-07-06 12:47:59 +0300648void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
Olli Etuahocccf2b02017-07-05 14:50:54 +0300649{
Olli Etuahoea39a222017-07-06 12:47:59 +0300650 queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300651}
652
653void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
654 TIntermNode *original,
655 TIntermNode *replacement,
656 OriginalNode originalStatus)
657{
658 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
659 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
660}
661
Olli Etuahocccf2b02017-07-05 14:50:54 +0300662TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
663 bool inVisit,
664 bool postVisit,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300665 TSymbolTable *symbolTable,
Olli Etuahocccf2b02017-07-05 14:50:54 +0300666 int shaderVersion)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300667 : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
Olli Etuahocccf2b02017-07-05 14:50:54 +0300668 mOperatorRequiresLValue(false),
669 mInFunctionCallOutParameter(false),
Olli Etuahocccf2b02017-07-05 14:50:54 +0300670 mShaderVersion(shaderVersion)
671{
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300672 ASSERT(symbolTable);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300673}
674
Olli Etuaho16c745a2017-01-16 17:02:27 +0000675void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
676{
677 TIntermSequence *sequence = node->getSequence();
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200678 addToFunctionMap(node->getFunction()->uniqueId(), sequence);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000679
680 TIntermTraverser::traverseFunctionPrototype(node);
681}
682
Olli Etuaho3fc93372015-08-11 14:50:59 +0300683void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
684{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000685 ScopedNodeInTraversalPath addToPath(this, node);
686
Olli Etuaho3fc93372015-08-11 14:50:59 +0300687 bool visit = true;
688
689 TIntermSequence *sequence = node->getSequence();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300690
Olli Etuaho27446bd2015-08-10 14:59:53 +0300691 if (preVisit)
692 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000693
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700694 if (visit)
695 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800696 if (node->getOp() == EOpCallFunctionInAST)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700697 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800698 if (isInFunctionMap(node))
Olli Etuaho64f0be92015-06-03 17:38:34 +0300699 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800700 TIntermSequence *params = getFunctionParameters(node);
701 TIntermSequence::iterator paramIter = params->begin();
702 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300703 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800704 ASSERT(paramIter != params->end());
705 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
706 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300707
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800708 child->traverse(this);
709 if (visit && inVisit)
710 {
711 if (child != sequence->back())
712 visit = visitAggregate(InVisit, node);
713 }
714
715 ++paramIter;
716 }
717 }
718 else
719 {
720 // The node might not be in the function map in case we're in the middle of
721 // transforming the AST, and have inserted function call nodes without inserting the
722 // function definitions yet.
723 setInFunctionCallOutParameter(false);
724 for (auto *child : *sequence)
725 {
726 child->traverse(this);
727 if (visit && inVisit)
728 {
729 if (child != sequence->back())
730 visit = visitAggregate(InVisit, node);
731 }
732 }
Olli Etuahoa26ad582015-08-04 13:51:47 +0300733 }
734
Olli Etuaho27446bd2015-08-10 14:59:53 +0300735 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300736 }
737 else
738 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300739 // Find the built-in function corresponding to this op so that we can determine the
740 // in/out qualifiers of its parameters.
741 TFunction *builtInFunc = nullptr;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800742 if (!node->isFunctionCall() && !node->isConstructor())
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300743 {
Olli Etuahof2209f72017-04-01 12:45:55 +0300744 builtInFunc = static_cast<TFunction *>(
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300745 mSymbolTable->findBuiltIn(node->getSymbolTableMangledName(), mShaderVersion));
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300746 }
747
748 size_t paramIndex = 0;
749
Olli Etuaho27446bd2015-08-10 14:59:53 +0300750 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300751 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800752 // This assumes that raw functions called with
753 // EOpCallInternalRawFunction don't have out parameters.
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300754 TQualifier qualifier = EvqIn;
755 if (builtInFunc != nullptr)
756 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
757 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300758 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300759
Olli Etuaho27446bd2015-08-10 14:59:53 +0300760 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300761 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300762 if (child != sequence->back())
763 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300764 }
765
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300766 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300767 }
768
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300769 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300770 }
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700771 }
772
Olli Etuaho27446bd2015-08-10 14:59:53 +0300773 if (visit && postVisit)
774 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000775}
776
777//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300778// Traverse a ternary node. Same comments in binary node apply here.
779//
780void TIntermTraverser::traverseTernary(TIntermTernary *node)
781{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000782 ScopedNodeInTraversalPath addToPath(this, node);
783
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300784 bool visit = true;
785
786 if (preVisit)
787 visit = visitTernary(PreVisit, node);
788
789 if (visit)
790 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300791 node->getCondition()->traverse(this);
792 if (node->getTrueExpression())
793 node->getTrueExpression()->traverse(this);
794 if (node->getFalseExpression())
795 node->getFalseExpression()->traverse(this);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300796 }
797
798 if (visit && postVisit)
799 visitTernary(PostVisit, node);
800}
801
Olli Etuaho57961272016-09-14 13:57:46 +0300802// Traverse an if-else node. Same comments in binary node apply here.
803void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000804{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000805 ScopedNodeInTraversalPath addToPath(this, node);
806
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700807 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000808
Olli Etuaho27446bd2015-08-10 14:59:53 +0300809 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300810 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000811
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700812 if (visit)
813 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300814 node->getCondition()->traverse(this);
815 if (node->getTrueBlock())
816 node->getTrueBlock()->traverse(this);
817 if (node->getFalseBlock())
818 node->getFalseBlock()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700819 }
820
Olli Etuaho27446bd2015-08-10 14:59:53 +0300821 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300822 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823}
824
825//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200826// Traverse a switch node. Same comments in binary node apply here.
827//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300828void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200829{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000830 ScopedNodeInTraversalPath addToPath(this, node);
831
Olli Etuahoa3a36662015-02-17 13:46:51 +0200832 bool visit = true;
833
Olli Etuaho27446bd2015-08-10 14:59:53 +0300834 if (preVisit)
835 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200836
837 if (visit)
838 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300839 node->getInit()->traverse(this);
840 if (inVisit)
841 visit = visitSwitch(InVisit, node);
842 if (visit && node->getStatementList())
843 node->getStatementList()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200844 }
845
Olli Etuaho27446bd2015-08-10 14:59:53 +0300846 if (visit && postVisit)
847 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200848}
849
850//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300851// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200852//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300853void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200854{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000855 ScopedNodeInTraversalPath addToPath(this, node);
856
Olli Etuahoa3a36662015-02-17 13:46:51 +0200857 bool visit = true;
858
Olli Etuaho27446bd2015-08-10 14:59:53 +0300859 if (preVisit)
860 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200861
Olli Etuaho27446bd2015-08-10 14:59:53 +0300862 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100863 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300864 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100865 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200866
Olli Etuaho27446bd2015-08-10 14:59:53 +0300867 if (visit && postVisit)
868 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200869}
870
871//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000872// Traverse a loop node. Same comments in binary node apply here.
873//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300874void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000875{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000876 ScopedNodeInTraversalPath addToPath(this, node);
877
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700878 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000879
Olli Etuaho27446bd2015-08-10 14:59:53 +0300880 if (preVisit)
881 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000882
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700883 if (visit)
884 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300885 if (node->getInit())
886 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000887
Olli Etuaho27446bd2015-08-10 14:59:53 +0300888 if (node->getCondition())
889 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000890
Olli Etuaho27446bd2015-08-10 14:59:53 +0300891 if (node->getBody())
892 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700893
Olli Etuaho27446bd2015-08-10 14:59:53 +0300894 if (node->getExpression())
895 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700896 }
897
Olli Etuaho27446bd2015-08-10 14:59:53 +0300898 if (visit && postVisit)
899 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000900}
901
902//
903// Traverse a branch node. Same comments in binary node apply here.
904//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300905void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000907 ScopedNodeInTraversalPath addToPath(this, node);
908
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700909 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000910
Olli Etuaho27446bd2015-08-10 14:59:53 +0300911 if (preVisit)
912 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000913
Olli Etuaho27446bd2015-08-10 14:59:53 +0300914 if (visit && node->getExpression())
915 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300916 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700917 }
918
Olli Etuaho27446bd2015-08-10 14:59:53 +0300919 if (visit && postVisit)
920 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000921}
922
Olli Etuaho27446bd2015-08-10 14:59:53 +0300923void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400924{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000925 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300926 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400927}
Jamie Madill45bcc782016-11-07 13:58:48 -0500928
929} // namespace sh