blob: 552979d59c9c4dbfcd88574e5dba10055603381b [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madillb1a85f42014-08-19 15:23:24 -04007#include "compiler/translator/IntermNode.h"
Olli Etuahod4f303e2015-05-20 17:09:06 +03008#include "compiler/translator/InfoSink.h"
Olli Etuaho217fe6e2015-08-05 13:25:08 +03009#include "compiler/translator/SymbolTable.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000010
Jamie Madill45bcc782016-11-07 13:58:48 -050011namespace sh
12{
13
Olli Etuaho27446bd2015-08-10 14:59:53 +030014void TIntermSymbol::traverse(TIntermTraverser *it)
15{
16 it->traverseSymbol(this);
17}
18
19void TIntermRaw::traverse(TIntermTraverser *it)
20{
21 it->traverseRaw(this);
22}
23
24void TIntermConstantUnion::traverse(TIntermTraverser *it)
25{
26 it->traverseConstantUnion(this);
27}
28
Olli Etuahob6fa0432016-09-28 16:28:05 +010029void TIntermSwizzle::traverse(TIntermTraverser *it)
30{
31 it->traverseSwizzle(this);
32}
33
Olli Etuaho27446bd2015-08-10 14:59:53 +030034void TIntermBinary::traverse(TIntermTraverser *it)
35{
36 it->traverseBinary(this);
37}
38
39void TIntermUnary::traverse(TIntermTraverser *it)
40{
41 it->traverseUnary(this);
42}
43
Olli Etuahod0bad2c2016-09-09 18:01:16 +030044void TIntermTernary::traverse(TIntermTraverser *it)
45{
46 it->traverseTernary(this);
47}
48
Olli Etuaho57961272016-09-14 13:57:46 +030049void TIntermIfElse::traverse(TIntermTraverser *it)
Olli Etuaho27446bd2015-08-10 14:59:53 +030050{
Olli Etuaho57961272016-09-14 13:57:46 +030051 it->traverseIfElse(this);
Olli Etuaho27446bd2015-08-10 14:59:53 +030052}
53
54void TIntermSwitch::traverse(TIntermTraverser *it)
55{
56 it->traverseSwitch(this);
57}
58
59void TIntermCase::traverse(TIntermTraverser *it)
60{
61 it->traverseCase(this);
62}
63
Olli Etuaho336b1472016-10-05 16:37:55 +010064void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
65{
66 it->traverseFunctionDefinition(this);
67}
68
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010069void TIntermBlock::traverse(TIntermTraverser *it)
70{
71 it->traverseBlock(this);
72}
73
Olli Etuahobf4e1b72016-12-09 11:30:15 +000074void TIntermInvariantDeclaration::traverse(TIntermTraverser *it)
75{
76 it->traverseInvariantDeclaration(this);
77}
78
Olli Etuaho13389b62016-10-16 11:48:18 +010079void TIntermDeclaration::traverse(TIntermTraverser *it)
80{
81 it->traverseDeclaration(this);
82}
83
Olli Etuaho16c745a2017-01-16 17:02:27 +000084void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
85{
86 it->traverseFunctionPrototype(this);
87}
88
Olli Etuaho27446bd2015-08-10 14:59:53 +030089void TIntermAggregate::traverse(TIntermTraverser *it)
90{
91 it->traverseAggregate(this);
92}
93
94void TIntermLoop::traverse(TIntermTraverser *it)
95{
96 it->traverseLoop(this);
97}
98
99void TIntermBranch::traverse(TIntermTraverser *it)
100{
101 it->traverseBranch(this);
102}
103
Jamie Madill03d863c2016-07-27 18:15:53 -0400104TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
105 : preVisit(preVisit),
106 inVisit(inVisit),
107 postVisit(postVisit),
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000108 mDepth(-1),
Jamie Madill03d863c2016-07-27 18:15:53 -0400109 mMaxDepth(0),
110 mInGlobalScope(true),
111 mTemporaryIndex(nullptr)
112{
113}
114
115TIntermTraverser::~TIntermTraverser()
116{
117}
118
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100119void TIntermTraverser::pushParentBlock(TIntermBlock *node)
Olli Etuaho56eea882015-05-18 12:41:03 +0300120{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300121 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +0300122}
123
124void TIntermTraverser::incrementParentBlockPos()
125{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300126 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +0300127}
128
129void TIntermTraverser::popParentBlock()
130{
131 ASSERT(!mParentBlockStack.empty());
132 mParentBlockStack.pop_back();
133}
134
135void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
136{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300137 TIntermSequence emptyInsertionsAfter;
138 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
139}
140
141void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
142 const TIntermSequence &insertionsAfter)
143{
Olli Etuaho56eea882015-05-18 12:41:03 +0300144 ASSERT(!mParentBlockStack.empty());
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000145 ParentBlock &parentBlock = mParentBlockStack.back();
146 if (mPath.back() == parentBlock.node)
147 {
148 ASSERT(mParentBlockStack.size() >= 2u);
149 // The current node is a block node, so the parent block is not the topmost one in the block
150 // stack, but the one below that.
151 parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
152 }
153 NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
154 insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300155 mInsertions.push_back(insert);
156}
157
Jamie Madill1048e432016-07-23 18:51:28 -0400158void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
159{
160 TIntermSequence insertions;
161 insertions.push_back(statement);
162 insertStatementsInParentBlock(insertions);
163}
164
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300165TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300166{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500167 // Each traversal uses at most one temporary variable, so the index stays the same within a
168 // single traversal.
Olli Etuahod4f303e2015-05-20 17:09:06 +0300169 TInfoSinkBase symbolNameOut;
170 ASSERT(mTemporaryIndex != nullptr);
171 symbolNameOut << "s" << (*mTemporaryIndex);
172 TString symbolName = symbolNameOut.c_str();
173
174 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
175 node->setInternal(true);
Olli Etuahob990b552016-10-27 12:29:17 +0100176
177 ASSERT(qualifier == EvqTemporary || qualifier == EvqConst || qualifier == EvqGlobal);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300178 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahob990b552016-10-27 12:29:17 +0100179 // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
180 // symbol. This might need to be done in other places as well.
Olli Etuahod4f303e2015-05-20 17:09:06 +0300181 return node;
182}
183
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300184TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
185{
186 return createTempSymbol(type, EvqTemporary);
187}
188
Olli Etuaho13389b62016-10-16 11:48:18 +0100189TIntermDeclaration *TIntermTraverser::createTempDeclaration(const TType &type)
Olli Etuaho4f1af782015-05-25 11:55:07 +0300190{
Olli Etuaho13389b62016-10-16 11:48:18 +0100191 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
192 tempDeclaration->appendDeclarator(createTempSymbol(type));
Olli Etuaho4f1af782015-05-25 11:55:07 +0300193 return tempDeclaration;
194}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300195
Olli Etuaho13389b62016-10-16 11:48:18 +0100196TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer,
197 TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300198{
199 ASSERT(initializer != nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500200 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuaho13389b62016-10-16 11:48:18 +0100201 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500202 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
Olli Etuaho13389b62016-10-16 11:48:18 +0100203 tempDeclaration->appendDeclarator(tempInit);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300204 return tempDeclaration;
205}
206
Olli Etuaho13389b62016-10-16 11:48:18 +0100207TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300208{
209 return createTempInitDeclaration(initializer, EvqTemporary);
210}
211
Olli Etuahod4f303e2015-05-20 17:09:06 +0300212TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
213{
214 ASSERT(rightNode != nullptr);
215 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300216 TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300217 return assignment;
218}
219
220void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
221{
222 mTemporaryIndex = temporaryIndex;
223}
224
225void TIntermTraverser::nextTemporaryIndex()
226{
227 ASSERT(mTemporaryIndex != nullptr);
228 ++(*mTemporaryIndex);
229}
230
Olli Etuahofe486322017-03-21 09:30:54 +0000231void TLValueTrackingTraverser::addToFunctionMap(const TSymbolUniqueId &id,
232 TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300233{
Olli Etuahofe486322017-03-21 09:30:54 +0000234 mFunctionMap[id.get()] = paramSequence;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300235}
236
Olli Etuaho3fc93372015-08-11 14:50:59 +0300237bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300238{
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800239 ASSERT(callNode->getOp() == EOpCallFunctionInAST);
Olli Etuahofe486322017-03-21 09:30:54 +0000240 return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getId().get()) !=
Olli Etuahobd674552016-10-06 13:28:42 +0100241 mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300242}
243
Olli Etuaho3fc93372015-08-11 14:50:59 +0300244TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300245{
246 ASSERT(isInFunctionMap(callNode));
Olli Etuahofe486322017-03-21 09:30:54 +0000247 return mFunctionMap[callNode->getFunctionSymbolInfo()->getId().get()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300248}
249
Olli Etuaho3fc93372015-08-11 14:50:59 +0300250void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300251{
252 mInFunctionCallOutParameter = inOutParameter;
253}
254
Olli Etuaho3fc93372015-08-11 14:50:59 +0300255bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300256{
257 return mInFunctionCallOutParameter;
258}
259
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000260//
261// Traverse the intermediate representation tree, and
262// call a node type specific function for each node.
263// Done recursively through the member function Traverse().
264// Node types can be skipped if their function to call is 0,
265// but their subtree will still be traversed.
266// Nodes with children can have their whole subtree skipped
267// if preVisit is turned on and the type specific function
268// returns false.
269//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270
271//
272// Traversal functions for terminals are straighforward....
273//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300274void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000275{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000276 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300277 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278}
279
Olli Etuaho27446bd2015-08-10 14:59:53 +0300280void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000281{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000282 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300283 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284}
285
Olli Etuahob6fa0432016-09-28 16:28:05 +0100286void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
287{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000288 ScopedNodeInTraversalPath addToPath(this, node);
289
Olli Etuahob6fa0432016-09-28 16:28:05 +0100290 bool visit = true;
291
292 if (preVisit)
293 visit = visitSwizzle(PreVisit, node);
294
295 if (visit)
296 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100297 node->getOperand()->traverse(this);
Olli Etuahob6fa0432016-09-28 16:28:05 +0100298 }
299
300 if (visit && postVisit)
301 visitSwizzle(PostVisit, node);
302}
303
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000304//
305// Traverse a binary node.
306//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300307void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000309 ScopedNodeInTraversalPath addToPath(this, node);
310
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700311 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700313 //
314 // visit the node before children if pre-visiting.
315 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300316 if (preVisit)
317 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700319 //
320 // Visit the children, in the right order.
321 //
322 if (visit)
323 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300324 if (node->getLeft())
325 node->getLeft()->traverse(this);
326
327 if (inVisit)
328 visit = visitBinary(InVisit, node);
329
330 if (visit && node->getRight())
331 node->getRight()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300332 }
333
334 //
335 // Visit the node after the children, if requested and the traversal
336 // hasn't been cancelled yet.
337 //
338 if (visit && postVisit)
339 visitBinary(PostVisit, node);
340}
341
342void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
343{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000344 ScopedNodeInTraversalPath addToPath(this, node);
345
Olli Etuaho3fc93372015-08-11 14:50:59 +0300346 bool visit = true;
347
348 //
349 // visit the node before children if pre-visiting.
350 //
351 if (preVisit)
352 visit = visitBinary(PreVisit, node);
353
354 //
355 // Visit the children, in the right order.
356 //
357 if (visit)
358 {
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300359 // Some binary operations like indexing can be inside an expression which must be an
360 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300361 bool parentOperatorRequiresLValue = operatorRequiresLValue();
362 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
363 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300364 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300365 ASSERT(!isLValueRequiredHere());
366 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300367 }
368
Olli Etuaho27446bd2015-08-10 14:59:53 +0300369 if (node->getLeft())
370 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000371
Olli Etuaho27446bd2015-08-10 14:59:53 +0300372 if (inVisit)
373 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000374
Olli Etuaho27446bd2015-08-10 14:59:53 +0300375 if (node->isAssignment())
376 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300377
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300378 // Index is not required to be an l-value even when the surrounding expression is required
379 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300380 TOperator op = node->getOp();
381 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
382 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300383 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300384 setOperatorRequiresLValue(false);
385 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300386 }
387
Olli Etuaho27446bd2015-08-10 14:59:53 +0300388 if (visit && node->getRight())
389 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700390
Olli Etuaho27446bd2015-08-10 14:59:53 +0300391 setOperatorRequiresLValue(parentOperatorRequiresLValue);
392 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700393 }
394
395 //
396 // Visit the node after the children, if requested and the traversal
397 // hasn't been cancelled yet.
398 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300399 if (visit && postVisit)
400 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000401}
402
403//
404// Traverse a unary node. Same comments in binary node apply here.
405//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300406void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000408 ScopedNodeInTraversalPath addToPath(this, node);
409
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700410 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411
Olli Etuaho27446bd2015-08-10 14:59:53 +0300412 if (preVisit)
413 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000414
Olli Etuahoa26ad582015-08-04 13:51:47 +0300415 if (visit)
416 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300417 node->getOperand()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300418 }
419
420 if (visit && postVisit)
421 visitUnary(PostVisit, node);
422}
423
424void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
425{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000426 ScopedNodeInTraversalPath addToPath(this, node);
427
Olli Etuaho3fc93372015-08-11 14:50:59 +0300428 bool visit = true;
429
430 if (preVisit)
431 visit = visitUnary(PreVisit, node);
432
433 if (visit)
434 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300435 ASSERT(!operatorRequiresLValue());
436 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300437 {
438 case EOpPostIncrement:
439 case EOpPostDecrement:
440 case EOpPreIncrement:
441 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300442 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300443 break;
444 default:
445 break;
446 }
447
Olli Etuaho27446bd2015-08-10 14:59:53 +0300448 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300449
Olli Etuaho27446bd2015-08-10 14:59:53 +0300450 setOperatorRequiresLValue(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700451 }
452
Olli Etuaho27446bd2015-08-10 14:59:53 +0300453 if (visit && postVisit)
454 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455}
456
Olli Etuaho336b1472016-10-05 16:37:55 +0100457// Traverse a function definition node.
458void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
459{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000460 ScopedNodeInTraversalPath addToPath(this, node);
461
Olli Etuaho336b1472016-10-05 16:37:55 +0100462 bool visit = true;
463
464 if (preVisit)
465 visit = visitFunctionDefinition(PreVisit, node);
466
467 if (visit)
468 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100469 mInGlobalScope = false;
470
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000471 node->getFunctionPrototype()->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100472 if (inVisit)
473 visit = visitFunctionDefinition(InVisit, node);
474 node->getBody()->traverse(this);
475
476 mInGlobalScope = true;
Olli Etuaho336b1472016-10-05 16:37:55 +0100477 }
478
479 if (visit && postVisit)
480 visitFunctionDefinition(PostVisit, node);
481}
482
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100483// Traverse a block node.
484void TIntermTraverser::traverseBlock(TIntermBlock *node)
485{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000486 ScopedNodeInTraversalPath addToPath(this, node);
487 pushParentBlock(node);
488
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100489 bool visit = true;
490
491 TIntermSequence *sequence = node->getSequence();
492
493 if (preVisit)
494 visit = visitBlock(PreVisit, node);
495
496 if (visit)
497 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100498 for (auto *child : *sequence)
499 {
500 child->traverse(this);
501 if (visit && inVisit)
502 {
503 if (child != sequence->back())
504 visit = visitBlock(InVisit, node);
505 }
506
507 incrementParentBlockPos();
508 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100509 }
510
511 if (visit && postVisit)
512 visitBlock(PostVisit, node);
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000513
514 popParentBlock();
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100515}
516
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000517void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
518{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000519 ScopedNodeInTraversalPath addToPath(this, node);
520
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000521 bool visit = true;
522
523 if (preVisit)
524 {
525 visit = visitInvariantDeclaration(PreVisit, node);
526 }
527
528 if (visit)
529 {
530 node->getSymbol()->traverse(this);
531 if (postVisit)
532 {
533 visitInvariantDeclaration(PostVisit, node);
534 }
535 }
536}
537
Olli Etuaho13389b62016-10-16 11:48:18 +0100538// Traverse a declaration node.
539void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
540{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000541 ScopedNodeInTraversalPath addToPath(this, node);
542
Olli Etuaho13389b62016-10-16 11:48:18 +0100543 bool visit = true;
544
545 TIntermSequence *sequence = node->getSequence();
546
547 if (preVisit)
548 visit = visitDeclaration(PreVisit, node);
549
550 if (visit)
551 {
Olli Etuaho13389b62016-10-16 11:48:18 +0100552 for (auto *child : *sequence)
553 {
554 child->traverse(this);
555 if (visit && inVisit)
556 {
557 if (child != sequence->back())
558 visit = visitDeclaration(InVisit, node);
559 }
560 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100561 }
562
563 if (visit && postVisit)
564 visitDeclaration(PostVisit, node);
565}
566
Olli Etuaho16c745a2017-01-16 17:02:27 +0000567void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
568{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000569 ScopedNodeInTraversalPath addToPath(this, node);
570
Olli Etuaho16c745a2017-01-16 17:02:27 +0000571 bool visit = true;
572
573 TIntermSequence *sequence = node->getSequence();
574
575 if (preVisit)
576 visit = visitFunctionPrototype(PreVisit, node);
577
578 if (visit)
579 {
Olli Etuaho16c745a2017-01-16 17:02:27 +0000580 for (auto *child : *sequence)
581 {
582 child->traverse(this);
583 if (visit && inVisit)
584 {
585 if (child != sequence->back())
586 visit = visitFunctionPrototype(InVisit, node);
587 }
588 }
Olli Etuaho16c745a2017-01-16 17:02:27 +0000589 }
590
591 if (visit && postVisit)
592 visitFunctionPrototype(PostVisit, node);
593}
594
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000595// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300596void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000597{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000598 ScopedNodeInTraversalPath addToPath(this, node);
599
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700600 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000601
Olli Etuaho27446bd2015-08-10 14:59:53 +0300602 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300603
604 if (preVisit)
605 visit = visitAggregate(PreVisit, node);
606
607 if (visit)
608 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300609 for (auto *child : *sequence)
610 {
611 child->traverse(this);
612 if (visit && inVisit)
613 {
614 if (child != sequence->back())
615 visit = visitAggregate(InVisit, node);
616 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300617 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300618 }
619
620 if (visit && postVisit)
621 visitAggregate(PostVisit, node);
622}
623
Olli Etuaho16c745a2017-01-16 17:02:27 +0000624void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
625{
626 TIntermSequence *sequence = node->getSequence();
Olli Etuahofe486322017-03-21 09:30:54 +0000627 addToFunctionMap(node->getFunctionSymbolInfo()->getId(), sequence);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000628
629 TIntermTraverser::traverseFunctionPrototype(node);
630}
631
Olli Etuaho3fc93372015-08-11 14:50:59 +0300632void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
633{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000634 ScopedNodeInTraversalPath addToPath(this, node);
635
Olli Etuaho3fc93372015-08-11 14:50:59 +0300636 bool visit = true;
637
638 TIntermSequence *sequence = node->getSequence();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300639
Olli Etuaho27446bd2015-08-10 14:59:53 +0300640 if (preVisit)
641 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700643 if (visit)
644 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800645 if (node->getOp() == EOpCallFunctionInAST)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700646 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800647 if (isInFunctionMap(node))
Olli Etuaho64f0be92015-06-03 17:38:34 +0300648 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800649 TIntermSequence *params = getFunctionParameters(node);
650 TIntermSequence::iterator paramIter = params->begin();
651 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300652 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800653 ASSERT(paramIter != params->end());
654 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
655 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300656
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800657 child->traverse(this);
658 if (visit && inVisit)
659 {
660 if (child != sequence->back())
661 visit = visitAggregate(InVisit, node);
662 }
663
664 ++paramIter;
665 }
666 }
667 else
668 {
669 // The node might not be in the function map in case we're in the middle of
670 // transforming the AST, and have inserted function call nodes without inserting the
671 // function definitions yet.
672 setInFunctionCallOutParameter(false);
673 for (auto *child : *sequence)
674 {
675 child->traverse(this);
676 if (visit && inVisit)
677 {
678 if (child != sequence->back())
679 visit = visitAggregate(InVisit, node);
680 }
681 }
Olli Etuahoa26ad582015-08-04 13:51:47 +0300682 }
683
Olli Etuaho27446bd2015-08-10 14:59:53 +0300684 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300685 }
686 else
687 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300688 // Find the built-in function corresponding to this op so that we can determine the
689 // in/out qualifiers of its parameters.
690 TFunction *builtInFunc = nullptr;
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800691 if (!node->isFunctionCall() && !node->isConstructor())
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300692 {
Olli Etuaho01d0ad02017-01-22 14:51:23 -0800693 builtInFunc = mSymbolTable.findBuiltInOp(node, mShaderVersion);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300694 }
695
696 size_t paramIndex = 0;
697
Olli Etuaho27446bd2015-08-10 14:59:53 +0300698 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300699 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800700 // This assumes that raw functions called with
701 // EOpCallInternalRawFunction don't have out parameters.
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300702 TQualifier qualifier = EvqIn;
703 if (builtInFunc != nullptr)
704 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
705 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300706 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300707
Olli Etuaho27446bd2015-08-10 14:59:53 +0300708 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300709 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300710 if (child != sequence->back())
711 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300712 }
713
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300714 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300715 }
716
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300717 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300718 }
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700719 }
720
Olli Etuaho27446bd2015-08-10 14:59:53 +0300721 if (visit && postVisit)
722 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000723}
724
725//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300726// Traverse a ternary node. Same comments in binary node apply here.
727//
728void TIntermTraverser::traverseTernary(TIntermTernary *node)
729{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000730 ScopedNodeInTraversalPath addToPath(this, node);
731
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300732 bool visit = true;
733
734 if (preVisit)
735 visit = visitTernary(PreVisit, node);
736
737 if (visit)
738 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300739 node->getCondition()->traverse(this);
740 if (node->getTrueExpression())
741 node->getTrueExpression()->traverse(this);
742 if (node->getFalseExpression())
743 node->getFalseExpression()->traverse(this);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300744 }
745
746 if (visit && postVisit)
747 visitTernary(PostVisit, node);
748}
749
Olli Etuaho57961272016-09-14 13:57:46 +0300750// Traverse an if-else node. Same comments in binary node apply here.
751void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000752{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000753 ScopedNodeInTraversalPath addToPath(this, node);
754
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700755 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756
Olli Etuaho27446bd2015-08-10 14:59:53 +0300757 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300758 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000759
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700760 if (visit)
761 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300762 node->getCondition()->traverse(this);
763 if (node->getTrueBlock())
764 node->getTrueBlock()->traverse(this);
765 if (node->getFalseBlock())
766 node->getFalseBlock()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700767 }
768
Olli Etuaho27446bd2015-08-10 14:59:53 +0300769 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300770 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000771}
772
773//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200774// Traverse a switch node. Same comments in binary node apply here.
775//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300776void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200777{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000778 ScopedNodeInTraversalPath addToPath(this, node);
779
Olli Etuahoa3a36662015-02-17 13:46:51 +0200780 bool visit = true;
781
Olli Etuaho27446bd2015-08-10 14:59:53 +0300782 if (preVisit)
783 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200784
785 if (visit)
786 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300787 node->getInit()->traverse(this);
788 if (inVisit)
789 visit = visitSwitch(InVisit, node);
790 if (visit && node->getStatementList())
791 node->getStatementList()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200792 }
793
Olli Etuaho27446bd2015-08-10 14:59:53 +0300794 if (visit && postVisit)
795 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200796}
797
798//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300799// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200800//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300801void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200802{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000803 ScopedNodeInTraversalPath addToPath(this, node);
804
Olli Etuahoa3a36662015-02-17 13:46:51 +0200805 bool visit = true;
806
Olli Etuaho27446bd2015-08-10 14:59:53 +0300807 if (preVisit)
808 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200809
Olli Etuaho27446bd2015-08-10 14:59:53 +0300810 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100811 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300812 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100813 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200814
Olli Etuaho27446bd2015-08-10 14:59:53 +0300815 if (visit && postVisit)
816 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200817}
818
819//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820// Traverse a loop node. Same comments in binary node apply here.
821//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300822void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000824 ScopedNodeInTraversalPath addToPath(this, node);
825
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700826 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000827
Olli Etuaho27446bd2015-08-10 14:59:53 +0300828 if (preVisit)
829 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000830
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700831 if (visit)
832 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300833 if (node->getInit())
834 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000835
Olli Etuaho27446bd2015-08-10 14:59:53 +0300836 if (node->getCondition())
837 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000838
Olli Etuaho27446bd2015-08-10 14:59:53 +0300839 if (node->getBody())
840 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700841
Olli Etuaho27446bd2015-08-10 14:59:53 +0300842 if (node->getExpression())
843 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700844 }
845
Olli Etuaho27446bd2015-08-10 14:59:53 +0300846 if (visit && postVisit)
847 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000848}
849
850//
851// Traverse a branch node. Same comments in binary node apply here.
852//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300853void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000854{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000855 ScopedNodeInTraversalPath addToPath(this, node);
856
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700857 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000858
Olli Etuaho27446bd2015-08-10 14:59:53 +0300859 if (preVisit)
860 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000861
Olli Etuaho27446bd2015-08-10 14:59:53 +0300862 if (visit && node->getExpression())
863 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300864 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700865 }
866
Olli Etuaho27446bd2015-08-10 14:59:53 +0300867 if (visit && postVisit)
868 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000869}
870
Olli Etuaho27446bd2015-08-10 14:59:53 +0300871void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400872{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000873 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300874 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400875}
Jamie Madill45bcc782016-11-07 13:58:48 -0500876
877} // namespace sh