blob: 65fe819c1a4033e6082a3af08ab7dfa43fb6a373 [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 Etuahofe486322017-03-21 09:30:54 +0000188 return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getId().get()) !=
Olli Etuahobd674552016-10-06 13:28:42 +0100189 mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300190}
191
Olli Etuaho3fc93372015-08-11 14:50:59 +0300192TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300193{
194 ASSERT(isInFunctionMap(callNode));
Olli Etuahofe486322017-03-21 09:30:54 +0000195 return mFunctionMap[callNode->getFunctionSymbolInfo()->getId().get()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300196}
197
Olli Etuaho3fc93372015-08-11 14:50:59 +0300198void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300199{
200 mInFunctionCallOutParameter = inOutParameter;
201}
202
Olli Etuaho3fc93372015-08-11 14:50:59 +0300203bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300204{
205 return mInFunctionCallOutParameter;
206}
207
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208//
209// Traverse the intermediate representation tree, and
210// call a node type specific function for each node.
211// Done recursively through the member function Traverse().
212// Node types can be skipped if their function to call is 0,
213// but their subtree will still be traversed.
214// Nodes with children can have their whole subtree skipped
215// if preVisit is turned on and the type specific function
216// returns false.
217//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000218
219//
220// Traversal functions for terminals are straighforward....
221//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300222void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000224 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300225 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226}
227
Olli Etuaho27446bd2015-08-10 14:59:53 +0300228void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000230 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300231 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232}
233
Olli Etuahob6fa0432016-09-28 16:28:05 +0100234void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
235{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000236 ScopedNodeInTraversalPath addToPath(this, node);
237
Olli Etuahob6fa0432016-09-28 16:28:05 +0100238 bool visit = true;
239
240 if (preVisit)
241 visit = visitSwizzle(PreVisit, node);
242
243 if (visit)
244 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100245 node->getOperand()->traverse(this);
Olli Etuahob6fa0432016-09-28 16:28:05 +0100246 }
247
248 if (visit && postVisit)
249 visitSwizzle(PostVisit, node);
250}
251
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252//
253// Traverse a binary node.
254//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300255void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000257 ScopedNodeInTraversalPath addToPath(this, node);
258
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700259 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700261 //
262 // visit the node before children if pre-visiting.
263 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300264 if (preVisit)
265 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700267 //
268 // Visit the children, in the right order.
269 //
270 if (visit)
271 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300272 if (node->getLeft())
273 node->getLeft()->traverse(this);
274
275 if (inVisit)
276 visit = visitBinary(InVisit, node);
277
278 if (visit && node->getRight())
279 node->getRight()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300280 }
281
282 //
283 // Visit the node after the children, if requested and the traversal
284 // hasn't been cancelled yet.
285 //
286 if (visit && postVisit)
287 visitBinary(PostVisit, node);
288}
289
290void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
291{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000292 ScopedNodeInTraversalPath addToPath(this, node);
293
Olli Etuaho3fc93372015-08-11 14:50:59 +0300294 bool visit = true;
295
296 //
297 // visit the node before children if pre-visiting.
298 //
299 if (preVisit)
300 visit = visitBinary(PreVisit, node);
301
302 //
303 // Visit the children, in the right order.
304 //
305 if (visit)
306 {
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300307 // Some binary operations like indexing can be inside an expression which must be an
308 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300309 bool parentOperatorRequiresLValue = operatorRequiresLValue();
310 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
311 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300312 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300313 ASSERT(!isLValueRequiredHere());
314 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300315 }
316
Olli Etuaho27446bd2015-08-10 14:59:53 +0300317 if (node->getLeft())
318 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319
Olli Etuaho27446bd2015-08-10 14:59:53 +0300320 if (inVisit)
321 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322
Olli Etuaho27446bd2015-08-10 14:59:53 +0300323 if (node->isAssignment())
324 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300325
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300326 // Index is not required to be an l-value even when the surrounding expression is required
327 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300328 TOperator op = node->getOp();
329 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
330 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300331 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300332 setOperatorRequiresLValue(false);
333 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300334 }
335
Olli Etuaho27446bd2015-08-10 14:59:53 +0300336 if (visit && node->getRight())
337 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700338
Olli Etuaho27446bd2015-08-10 14:59:53 +0300339 setOperatorRequiresLValue(parentOperatorRequiresLValue);
340 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700341 }
342
343 //
344 // Visit the node after the children, if requested and the traversal
345 // hasn't been cancelled yet.
346 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300347 if (visit && postVisit)
348 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349}
350
351//
352// Traverse a unary node. Same comments in binary node apply here.
353//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300354void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000356 ScopedNodeInTraversalPath addToPath(this, node);
357
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700358 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359
Olli Etuaho27446bd2015-08-10 14:59:53 +0300360 if (preVisit)
361 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362
Olli Etuahoa26ad582015-08-04 13:51:47 +0300363 if (visit)
364 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300365 node->getOperand()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300366 }
367
368 if (visit && postVisit)
369 visitUnary(PostVisit, node);
370}
371
372void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
373{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000374 ScopedNodeInTraversalPath addToPath(this, node);
375
Olli Etuaho3fc93372015-08-11 14:50:59 +0300376 bool visit = true;
377
378 if (preVisit)
379 visit = visitUnary(PreVisit, node);
380
381 if (visit)
382 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300383 ASSERT(!operatorRequiresLValue());
384 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300385 {
386 case EOpPostIncrement:
387 case EOpPostDecrement:
388 case EOpPreIncrement:
389 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300390 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300391 break;
392 default:
393 break;
394 }
395
Olli Etuaho27446bd2015-08-10 14:59:53 +0300396 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300397
Olli Etuaho27446bd2015-08-10 14:59:53 +0300398 setOperatorRequiresLValue(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700399 }
400
Olli Etuaho27446bd2015-08-10 14:59:53 +0300401 if (visit && postVisit)
402 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403}
404
Olli Etuaho336b1472016-10-05 16:37:55 +0100405// Traverse a function definition node.
406void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
407{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000408 ScopedNodeInTraversalPath addToPath(this, node);
409
Olli Etuaho336b1472016-10-05 16:37:55 +0100410 bool visit = true;
411
412 if (preVisit)
413 visit = visitFunctionDefinition(PreVisit, node);
414
415 if (visit)
416 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100417 mInGlobalScope = false;
418
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000419 node->getFunctionPrototype()->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100420 if (inVisit)
421 visit = visitFunctionDefinition(InVisit, node);
422 node->getBody()->traverse(this);
423
424 mInGlobalScope = true;
Olli Etuaho336b1472016-10-05 16:37:55 +0100425 }
426
427 if (visit && postVisit)
428 visitFunctionDefinition(PostVisit, node);
429}
430
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100431// Traverse a block node.
432void TIntermTraverser::traverseBlock(TIntermBlock *node)
433{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000434 ScopedNodeInTraversalPath addToPath(this, node);
435 pushParentBlock(node);
436
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100437 bool visit = true;
438
439 TIntermSequence *sequence = node->getSequence();
440
441 if (preVisit)
442 visit = visitBlock(PreVisit, node);
443
444 if (visit)
445 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100446 for (auto *child : *sequence)
447 {
448 child->traverse(this);
449 if (visit && inVisit)
450 {
451 if (child != sequence->back())
452 visit = visitBlock(InVisit, node);
453 }
454
455 incrementParentBlockPos();
456 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100457 }
458
459 if (visit && postVisit)
460 visitBlock(PostVisit, node);
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000461
462 popParentBlock();
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100463}
464
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000465void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
466{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000467 ScopedNodeInTraversalPath addToPath(this, node);
468
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000469 bool visit = true;
470
471 if (preVisit)
472 {
473 visit = visitInvariantDeclaration(PreVisit, node);
474 }
475
476 if (visit)
477 {
478 node->getSymbol()->traverse(this);
479 if (postVisit)
480 {
481 visitInvariantDeclaration(PostVisit, node);
482 }
483 }
484}
485
Olli Etuaho13389b62016-10-16 11:48:18 +0100486// Traverse a declaration node.
487void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
488{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000489 ScopedNodeInTraversalPath addToPath(this, node);
490
Olli Etuaho13389b62016-10-16 11:48:18 +0100491 bool visit = true;
492
493 TIntermSequence *sequence = node->getSequence();
494
495 if (preVisit)
496 visit = visitDeclaration(PreVisit, node);
497
498 if (visit)
499 {
Olli Etuaho13389b62016-10-16 11:48:18 +0100500 for (auto *child : *sequence)
501 {
502 child->traverse(this);
503 if (visit && inVisit)
504 {
505 if (child != sequence->back())
506 visit = visitDeclaration(InVisit, node);
507 }
508 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100509 }
510
511 if (visit && postVisit)
512 visitDeclaration(PostVisit, node);
513}
514
Olli Etuaho16c745a2017-01-16 17:02:27 +0000515void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
516{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000517 ScopedNodeInTraversalPath addToPath(this, node);
518
Olli Etuaho16c745a2017-01-16 17:02:27 +0000519 bool visit = true;
520
521 TIntermSequence *sequence = node->getSequence();
522
523 if (preVisit)
524 visit = visitFunctionPrototype(PreVisit, node);
525
526 if (visit)
527 {
Olli Etuaho16c745a2017-01-16 17:02:27 +0000528 for (auto *child : *sequence)
529 {
530 child->traverse(this);
531 if (visit && inVisit)
532 {
533 if (child != sequence->back())
534 visit = visitFunctionPrototype(InVisit, node);
535 }
536 }
Olli Etuaho16c745a2017-01-16 17:02:27 +0000537 }
538
539 if (visit && postVisit)
540 visitFunctionPrototype(PostVisit, node);
541}
542
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000543// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300544void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000546 ScopedNodeInTraversalPath addToPath(this, node);
547
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700548 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549
Olli Etuaho27446bd2015-08-10 14:59:53 +0300550 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300551
552 if (preVisit)
553 visit = visitAggregate(PreVisit, node);
554
555 if (visit)
556 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300557 for (auto *child : *sequence)
558 {
559 child->traverse(this);
560 if (visit && inVisit)
561 {
562 if (child != sequence->back())
563 visit = visitAggregate(InVisit, node);
564 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300565 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300566 }
567
568 if (visit && postVisit)
569 visitAggregate(PostVisit, node);
570}
571
Olli Etuahocccf2b02017-07-05 14:50:54 +0300572bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
573 const NodeInsertMultipleEntry &b)
574{
575 if (a.parent != b.parent)
576 {
577 return a.parent > b.parent;
578 }
579 return a.position > b.position;
580}
581
582void TIntermTraverser::updateTree()
583{
584 // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
585 // the same parent node are handled correctly.
586 std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
587 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
588 {
589 // We can't know here what the intended ordering of two insertions to the same position is,
590 // so it is not supported.
591 ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
592 mInsertions[ii].parent != mInsertions[ii - 1].parent);
593 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
594 ASSERT(insertion.parent);
595 if (!insertion.insertionsAfter.empty())
596 {
597 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
598 insertion.insertionsAfter);
599 ASSERT(inserted);
600 }
601 if (!insertion.insertionsBefore.empty())
602 {
603 bool inserted =
604 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
605 ASSERT(inserted);
606 }
607 }
608 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
609 {
610 const NodeUpdateEntry &replacement = mReplacements[ii];
611 ASSERT(replacement.parent);
612 bool replaced =
613 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
614 ASSERT(replaced);
615
616 if (!replacement.originalBecomesChildOfReplacement)
617 {
618 // In AST traversing, a parent is visited before its children.
619 // After we replace a node, if its immediate child is to
620 // be replaced, we need to make sure we don't update the replaced
621 // node; instead, we update the replacement node.
622 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
623 {
624 NodeUpdateEntry &replacement2 = mReplacements[jj];
625 if (replacement2.parent == replacement.original)
626 replacement2.parent = replacement.replacement;
627 }
628 }
629 }
630 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
631 {
632 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
633 ASSERT(replacement.parent);
634 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
635 replacement.replacements);
636 ASSERT(replaced);
637 }
638
639 clearReplacementQueue();
640}
641
642void TIntermTraverser::clearReplacementQueue()
643{
644 mReplacements.clear();
645 mMultiReplacements.clear();
646 mInsertions.clear();
647}
648
Olli Etuahoea39a222017-07-06 12:47:59 +0300649void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
Olli Etuahocccf2b02017-07-05 14:50:54 +0300650{
Olli Etuahoea39a222017-07-06 12:47:59 +0300651 queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300652}
653
654void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
655 TIntermNode *original,
656 TIntermNode *replacement,
657 OriginalNode originalStatus)
658{
659 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
660 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
661}
662
Olli Etuahocccf2b02017-07-05 14:50:54 +0300663TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
664 bool inVisit,
665 bool postVisit,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300666 TSymbolTable *symbolTable,
Olli Etuahocccf2b02017-07-05 14:50:54 +0300667 int shaderVersion)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300668 : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
Olli Etuahocccf2b02017-07-05 14:50:54 +0300669 mOperatorRequiresLValue(false),
670 mInFunctionCallOutParameter(false),
Olli Etuahocccf2b02017-07-05 14:50:54 +0300671 mShaderVersion(shaderVersion)
672{
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300673 ASSERT(symbolTable);
Olli Etuahocccf2b02017-07-05 14:50:54 +0300674}
675
Olli Etuaho16c745a2017-01-16 17:02:27 +0000676void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
677{
678 TIntermSequence *sequence = node->getSequence();
Olli Etuahofe486322017-03-21 09:30:54 +0000679 addToFunctionMap(node->getFunctionSymbolInfo()->getId(), sequence);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000680
681 TIntermTraverser::traverseFunctionPrototype(node);
682}
683
Olli Etuaho3fc93372015-08-11 14:50:59 +0300684void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
685{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000686 ScopedNodeInTraversalPath addToPath(this, node);
687
Olli Etuaho3fc93372015-08-11 14:50:59 +0300688 bool visit = true;
689
690 TIntermSequence *sequence = node->getSequence();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300691
Olli Etuaho27446bd2015-08-10 14:59:53 +0300692 if (preVisit)
693 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000694
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700695 if (visit)
696 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800697 if (node->getOp() == EOpCallFunctionInAST)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700698 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800699 if (isInFunctionMap(node))
Olli Etuaho64f0be92015-06-03 17:38:34 +0300700 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800701 TIntermSequence *params = getFunctionParameters(node);
702 TIntermSequence::iterator paramIter = params->begin();
703 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300704 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800705 ASSERT(paramIter != params->end());
706 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
707 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300708
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800709 child->traverse(this);
710 if (visit && inVisit)
711 {
712 if (child != sequence->back())
713 visit = visitAggregate(InVisit, node);
714 }
715
716 ++paramIter;
717 }
718 }
719 else
720 {
721 // The node might not be in the function map in case we're in the middle of
722 // transforming the AST, and have inserted function call nodes without inserting the
723 // function definitions yet.
724 setInFunctionCallOutParameter(false);
725 for (auto *child : *sequence)
726 {
727 child->traverse(this);
728 if (visit && inVisit)
729 {
730 if (child != sequence->back())
731 visit = visitAggregate(InVisit, node);
732 }
733 }
Olli Etuahoa26ad582015-08-04 13:51:47 +0300734 }
735
Olli Etuaho27446bd2015-08-10 14:59:53 +0300736 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300737 }
738 else
739 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300740 // Find the built-in function corresponding to this op so that we can determine the
741 // in/out qualifiers of its parameters.
742 TFunction *builtInFunc = nullptr;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800743 if (!node->isFunctionCall() && !node->isConstructor())
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300744 {
Olli Etuahof2209f72017-04-01 12:45:55 +0300745 builtInFunc = static_cast<TFunction *>(
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300746 mSymbolTable->findBuiltIn(node->getSymbolTableMangledName(), mShaderVersion));
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300747 }
748
749 size_t paramIndex = 0;
750
Olli Etuaho27446bd2015-08-10 14:59:53 +0300751 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300752 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800753 // This assumes that raw functions called with
754 // EOpCallInternalRawFunction don't have out parameters.
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300755 TQualifier qualifier = EvqIn;
756 if (builtInFunc != nullptr)
757 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
758 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300759 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300760
Olli Etuaho27446bd2015-08-10 14:59:53 +0300761 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300762 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300763 if (child != sequence->back())
764 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300765 }
766
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300767 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300768 }
769
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300770 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300771 }
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700772 }
773
Olli Etuaho27446bd2015-08-10 14:59:53 +0300774 if (visit && postVisit)
775 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000776}
777
778//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300779// Traverse a ternary node. Same comments in binary node apply here.
780//
781void TIntermTraverser::traverseTernary(TIntermTernary *node)
782{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000783 ScopedNodeInTraversalPath addToPath(this, node);
784
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300785 bool visit = true;
786
787 if (preVisit)
788 visit = visitTernary(PreVisit, node);
789
790 if (visit)
791 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300792 node->getCondition()->traverse(this);
793 if (node->getTrueExpression())
794 node->getTrueExpression()->traverse(this);
795 if (node->getFalseExpression())
796 node->getFalseExpression()->traverse(this);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300797 }
798
799 if (visit && postVisit)
800 visitTernary(PostVisit, node);
801}
802
Olli Etuaho57961272016-09-14 13:57:46 +0300803// Traverse an if-else node. Same comments in binary node apply here.
804void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000805{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000806 ScopedNodeInTraversalPath addToPath(this, node);
807
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700808 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000809
Olli Etuaho27446bd2015-08-10 14:59:53 +0300810 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300811 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000812
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700813 if (visit)
814 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300815 node->getCondition()->traverse(this);
816 if (node->getTrueBlock())
817 node->getTrueBlock()->traverse(this);
818 if (node->getFalseBlock())
819 node->getFalseBlock()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700820 }
821
Olli Etuaho27446bd2015-08-10 14:59:53 +0300822 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300823 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000824}
825
826//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200827// Traverse a switch node. Same comments in binary node apply here.
828//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300829void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200830{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000831 ScopedNodeInTraversalPath addToPath(this, node);
832
Olli Etuahoa3a36662015-02-17 13:46:51 +0200833 bool visit = true;
834
Olli Etuaho27446bd2015-08-10 14:59:53 +0300835 if (preVisit)
836 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200837
838 if (visit)
839 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300840 node->getInit()->traverse(this);
841 if (inVisit)
842 visit = visitSwitch(InVisit, node);
843 if (visit && node->getStatementList())
844 node->getStatementList()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200845 }
846
Olli Etuaho27446bd2015-08-10 14:59:53 +0300847 if (visit && postVisit)
848 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200849}
850
851//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300852// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200853//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300854void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200855{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000856 ScopedNodeInTraversalPath addToPath(this, node);
857
Olli Etuahoa3a36662015-02-17 13:46:51 +0200858 bool visit = true;
859
Olli Etuaho27446bd2015-08-10 14:59:53 +0300860 if (preVisit)
861 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200862
Olli Etuaho27446bd2015-08-10 14:59:53 +0300863 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100864 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300865 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100866 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200867
Olli Etuaho27446bd2015-08-10 14:59:53 +0300868 if (visit && postVisit)
869 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200870}
871
872//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000873// Traverse a loop node. Same comments in binary node apply here.
874//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300875void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000876{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000877 ScopedNodeInTraversalPath addToPath(this, node);
878
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700879 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000880
Olli Etuaho27446bd2015-08-10 14:59:53 +0300881 if (preVisit)
882 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000883
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700884 if (visit)
885 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300886 if (node->getInit())
887 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000888
Olli Etuaho27446bd2015-08-10 14:59:53 +0300889 if (node->getCondition())
890 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000891
Olli Etuaho27446bd2015-08-10 14:59:53 +0300892 if (node->getBody())
893 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700894
Olli Etuaho27446bd2015-08-10 14:59:53 +0300895 if (node->getExpression())
896 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700897 }
898
Olli Etuaho27446bd2015-08-10 14:59:53 +0300899 if (visit && postVisit)
900 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000901}
902
903//
904// Traverse a branch node. Same comments in binary node apply here.
905//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300906void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000907{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000908 ScopedNodeInTraversalPath addToPath(this, node);
909
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700910 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000911
Olli Etuaho27446bd2015-08-10 14:59:53 +0300912 if (preVisit)
913 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000914
Olli Etuaho27446bd2015-08-10 14:59:53 +0300915 if (visit && node->getExpression())
916 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300917 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700918 }
919
Olli Etuaho27446bd2015-08-10 14:59:53 +0300920 if (visit && postVisit)
921 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000922}
923
Olli Etuaho27446bd2015-08-10 14:59:53 +0300924void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400925{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000926 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300927 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400928}
Jamie Madill45bcc782016-11-07 13:58:48 -0500929
930} // namespace sh