blob: b58b27ce133d26eab4a6c7d9b49c897a7a95fcad [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 Etuaho5f579b12015-08-14 17:44:43 +0300231void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300232{
233 mFunctionMap[name] = paramSequence;
234}
235
Olli Etuaho3fc93372015-08-11 14:50:59 +0300236bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300237{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300238 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuahobd674552016-10-06 13:28:42 +0100239 return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
240 mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300241}
242
Olli Etuaho3fc93372015-08-11 14:50:59 +0300243TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300244{
245 ASSERT(isInFunctionMap(callNode));
Olli Etuahobd674552016-10-06 13:28:42 +0100246 return mFunctionMap[callNode->getFunctionSymbolInfo()->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300247}
248
Olli Etuaho3fc93372015-08-11 14:50:59 +0300249void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300250{
251 mInFunctionCallOutParameter = inOutParameter;
252}
253
Olli Etuaho3fc93372015-08-11 14:50:59 +0300254bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300255{
256 return mInFunctionCallOutParameter;
257}
258
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259//
260// Traverse the intermediate representation tree, and
261// call a node type specific function for each node.
262// Done recursively through the member function Traverse().
263// Node types can be skipped if their function to call is 0,
264// but their subtree will still be traversed.
265// Nodes with children can have their whole subtree skipped
266// if preVisit is turned on and the type specific function
267// returns false.
268//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269
270//
271// Traversal functions for terminals are straighforward....
272//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300273void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000275 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300276 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277}
278
Olli Etuaho27446bd2015-08-10 14:59:53 +0300279void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000281 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300282 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283}
284
Olli Etuahob6fa0432016-09-28 16:28:05 +0100285void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
286{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000287 ScopedNodeInTraversalPath addToPath(this, node);
288
Olli Etuahob6fa0432016-09-28 16:28:05 +0100289 bool visit = true;
290
291 if (preVisit)
292 visit = visitSwizzle(PreVisit, node);
293
294 if (visit)
295 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100296 node->getOperand()->traverse(this);
Olli Etuahob6fa0432016-09-28 16:28:05 +0100297 }
298
299 if (visit && postVisit)
300 visitSwizzle(PostVisit, node);
301}
302
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000303//
304// Traverse a binary node.
305//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300306void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000308 ScopedNodeInTraversalPath addToPath(this, node);
309
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700310 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700312 //
313 // visit the node before children if pre-visiting.
314 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300315 if (preVisit)
316 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000317
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700318 //
319 // Visit the children, in the right order.
320 //
321 if (visit)
322 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300323 if (node->getLeft())
324 node->getLeft()->traverse(this);
325
326 if (inVisit)
327 visit = visitBinary(InVisit, node);
328
329 if (visit && node->getRight())
330 node->getRight()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300331 }
332
333 //
334 // Visit the node after the children, if requested and the traversal
335 // hasn't been cancelled yet.
336 //
337 if (visit && postVisit)
338 visitBinary(PostVisit, node);
339}
340
341void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
342{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000343 ScopedNodeInTraversalPath addToPath(this, node);
344
Olli Etuaho3fc93372015-08-11 14:50:59 +0300345 bool visit = true;
346
347 //
348 // visit the node before children if pre-visiting.
349 //
350 if (preVisit)
351 visit = visitBinary(PreVisit, node);
352
353 //
354 // Visit the children, in the right order.
355 //
356 if (visit)
357 {
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300358 // Some binary operations like indexing can be inside an expression which must be an
359 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300360 bool parentOperatorRequiresLValue = operatorRequiresLValue();
361 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
362 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300363 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300364 ASSERT(!isLValueRequiredHere());
365 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300366 }
367
Olli Etuaho27446bd2015-08-10 14:59:53 +0300368 if (node->getLeft())
369 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370
Olli Etuaho27446bd2015-08-10 14:59:53 +0300371 if (inVisit)
372 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000373
Olli Etuaho27446bd2015-08-10 14:59:53 +0300374 if (node->isAssignment())
375 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300376
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300377 // Index is not required to be an l-value even when the surrounding expression is required
378 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300379 TOperator op = node->getOp();
380 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
381 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300382 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300383 setOperatorRequiresLValue(false);
384 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300385 }
386
Olli Etuaho27446bd2015-08-10 14:59:53 +0300387 if (visit && node->getRight())
388 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700389
Olli Etuaho27446bd2015-08-10 14:59:53 +0300390 setOperatorRequiresLValue(parentOperatorRequiresLValue);
391 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700392 }
393
394 //
395 // Visit the node after the children, if requested and the traversal
396 // hasn't been cancelled yet.
397 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300398 if (visit && postVisit)
399 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400}
401
402//
403// Traverse a unary node. Same comments in binary node apply here.
404//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300405void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000406{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000407 ScopedNodeInTraversalPath addToPath(this, node);
408
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700409 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000410
Olli Etuaho27446bd2015-08-10 14:59:53 +0300411 if (preVisit)
412 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413
Olli Etuahoa26ad582015-08-04 13:51:47 +0300414 if (visit)
415 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300416 node->getOperand()->traverse(this);
Olli Etuaho3fc93372015-08-11 14:50:59 +0300417 }
418
419 if (visit && postVisit)
420 visitUnary(PostVisit, node);
421}
422
423void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
424{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000425 ScopedNodeInTraversalPath addToPath(this, node);
426
Olli Etuaho3fc93372015-08-11 14:50:59 +0300427 bool visit = true;
428
429 if (preVisit)
430 visit = visitUnary(PreVisit, node);
431
432 if (visit)
433 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300434 ASSERT(!operatorRequiresLValue());
435 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300436 {
437 case EOpPostIncrement:
438 case EOpPostDecrement:
439 case EOpPreIncrement:
440 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300441 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300442 break;
443 default:
444 break;
445 }
446
Olli Etuaho27446bd2015-08-10 14:59:53 +0300447 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300448
Olli Etuaho27446bd2015-08-10 14:59:53 +0300449 setOperatorRequiresLValue(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700450 }
451
Olli Etuaho27446bd2015-08-10 14:59:53 +0300452 if (visit && postVisit)
453 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454}
455
Olli Etuaho336b1472016-10-05 16:37:55 +0100456// Traverse a function definition node.
457void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
458{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000459 ScopedNodeInTraversalPath addToPath(this, node);
460
Olli Etuaho336b1472016-10-05 16:37:55 +0100461 bool visit = true;
462
463 if (preVisit)
464 visit = visitFunctionDefinition(PreVisit, node);
465
466 if (visit)
467 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100468 mInGlobalScope = false;
469
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000470 node->getFunctionPrototype()->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100471 if (inVisit)
472 visit = visitFunctionDefinition(InVisit, node);
473 node->getBody()->traverse(this);
474
475 mInGlobalScope = true;
Olli Etuaho336b1472016-10-05 16:37:55 +0100476 }
477
478 if (visit && postVisit)
479 visitFunctionDefinition(PostVisit, node);
480}
481
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100482// Traverse a block node.
483void TIntermTraverser::traverseBlock(TIntermBlock *node)
484{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000485 ScopedNodeInTraversalPath addToPath(this, node);
486 pushParentBlock(node);
487
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100488 bool visit = true;
489
490 TIntermSequence *sequence = node->getSequence();
491
492 if (preVisit)
493 visit = visitBlock(PreVisit, node);
494
495 if (visit)
496 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100497 for (auto *child : *sequence)
498 {
499 child->traverse(this);
500 if (visit && inVisit)
501 {
502 if (child != sequence->back())
503 visit = visitBlock(InVisit, node);
504 }
505
506 incrementParentBlockPos();
507 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100508 }
509
510 if (visit && postVisit)
511 visitBlock(PostVisit, node);
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000512
513 popParentBlock();
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100514}
515
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000516void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
517{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000518 ScopedNodeInTraversalPath addToPath(this, node);
519
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000520 bool visit = true;
521
522 if (preVisit)
523 {
524 visit = visitInvariantDeclaration(PreVisit, node);
525 }
526
527 if (visit)
528 {
529 node->getSymbol()->traverse(this);
530 if (postVisit)
531 {
532 visitInvariantDeclaration(PostVisit, node);
533 }
534 }
535}
536
Olli Etuaho13389b62016-10-16 11:48:18 +0100537// Traverse a declaration node.
538void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
539{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000540 ScopedNodeInTraversalPath addToPath(this, node);
541
Olli Etuaho13389b62016-10-16 11:48:18 +0100542 bool visit = true;
543
544 TIntermSequence *sequence = node->getSequence();
545
546 if (preVisit)
547 visit = visitDeclaration(PreVisit, node);
548
549 if (visit)
550 {
Olli Etuaho13389b62016-10-16 11:48:18 +0100551 for (auto *child : *sequence)
552 {
553 child->traverse(this);
554 if (visit && inVisit)
555 {
556 if (child != sequence->back())
557 visit = visitDeclaration(InVisit, node);
558 }
559 }
Olli Etuaho13389b62016-10-16 11:48:18 +0100560 }
561
562 if (visit && postVisit)
563 visitDeclaration(PostVisit, node);
564}
565
Olli Etuaho16c745a2017-01-16 17:02:27 +0000566void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
567{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000568 ScopedNodeInTraversalPath addToPath(this, node);
569
Olli Etuaho16c745a2017-01-16 17:02:27 +0000570 bool visit = true;
571
572 TIntermSequence *sequence = node->getSequence();
573
574 if (preVisit)
575 visit = visitFunctionPrototype(PreVisit, node);
576
577 if (visit)
578 {
Olli Etuaho16c745a2017-01-16 17:02:27 +0000579 for (auto *child : *sequence)
580 {
581 child->traverse(this);
582 if (visit && inVisit)
583 {
584 if (child != sequence->back())
585 visit = visitFunctionPrototype(InVisit, node);
586 }
587 }
Olli Etuaho16c745a2017-01-16 17:02:27 +0000588 }
589
590 if (visit && postVisit)
591 visitFunctionPrototype(PostVisit, node);
592}
593
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000594// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300595void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000596{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000597 ScopedNodeInTraversalPath addToPath(this, node);
598
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700599 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000600
Olli Etuaho27446bd2015-08-10 14:59:53 +0300601 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300602
603 if (preVisit)
604 visit = visitAggregate(PreVisit, node);
605
606 if (visit)
607 {
Olli Etuaho3fc93372015-08-11 14:50:59 +0300608 for (auto *child : *sequence)
609 {
610 child->traverse(this);
611 if (visit && inVisit)
612 {
613 if (child != sequence->back())
614 visit = visitAggregate(InVisit, node);
615 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300616 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300617 }
618
619 if (visit && postVisit)
620 visitAggregate(PostVisit, node);
621}
622
Olli Etuaho16c745a2017-01-16 17:02:27 +0000623void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
624{
625 TIntermSequence *sequence = node->getSequence();
626 addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
627
628 TIntermTraverser::traverseFunctionPrototype(node);
629}
630
Olli Etuaho3fc93372015-08-11 14:50:59 +0300631void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
632{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000633 ScopedNodeInTraversalPath addToPath(this, node);
634
Olli Etuaho3fc93372015-08-11 14:50:59 +0300635 bool visit = true;
636
637 TIntermSequence *sequence = node->getSequence();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300638
Olli Etuaho27446bd2015-08-10 14:59:53 +0300639 if (preVisit)
640 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700642 if (visit)
643 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300644 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300645 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700646 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300647 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300648 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300649 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300650 // The function is not user-defined - it is likely built-in texture function.
651 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300652 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700653 }
654 }
655
Olli Etuahoa26ad582015-08-04 13:51:47 +0300656 if (inFunctionMap)
657 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300658 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300659 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300660 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300661 {
662 ASSERT(paramIter != params->end());
663 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300664 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300665
Olli Etuaho27446bd2015-08-10 14:59:53 +0300666 child->traverse(this);
667 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300668 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300669 if (child != sequence->back())
670 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300671 }
672
673 ++paramIter;
674 }
675
Olli Etuaho27446bd2015-08-10 14:59:53 +0300676 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300677 }
678 else
679 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300680 // Find the built-in function corresponding to this op so that we can determine the
681 // in/out qualifiers of its parameters.
682 TFunction *builtInFunc = nullptr;
Olli Etuaho01d0ad02017-01-22 14:51:23 -0800683 if (!node->isConstructor() && node->getOp() != EOpFunctionCall)
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300684 {
Olli Etuaho01d0ad02017-01-22 14:51:23 -0800685 builtInFunc = mSymbolTable.findBuiltInOp(node, mShaderVersion);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300686 }
687
688 size_t paramIndex = 0;
689
Olli Etuaho27446bd2015-08-10 14:59:53 +0300690 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300691 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300692 TQualifier qualifier = EvqIn;
693 if (builtInFunc != nullptr)
694 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
695 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300696 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300697
Olli Etuaho27446bd2015-08-10 14:59:53 +0300698 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300699 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300700 if (child != sequence->back())
701 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300702 }
703
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300704 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300705 }
706
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300707 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300708 }
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700709 }
710
Olli Etuaho27446bd2015-08-10 14:59:53 +0300711 if (visit && postVisit)
712 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000713}
714
715//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300716// Traverse a ternary node. Same comments in binary node apply here.
717//
718void TIntermTraverser::traverseTernary(TIntermTernary *node)
719{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000720 ScopedNodeInTraversalPath addToPath(this, node);
721
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300722 bool visit = true;
723
724 if (preVisit)
725 visit = visitTernary(PreVisit, node);
726
727 if (visit)
728 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300729 node->getCondition()->traverse(this);
730 if (node->getTrueExpression())
731 node->getTrueExpression()->traverse(this);
732 if (node->getFalseExpression())
733 node->getFalseExpression()->traverse(this);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300734 }
735
736 if (visit && postVisit)
737 visitTernary(PostVisit, node);
738}
739
Olli Etuaho57961272016-09-14 13:57:46 +0300740// Traverse an if-else node. Same comments in binary node apply here.
741void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000742{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000743 ScopedNodeInTraversalPath addToPath(this, node);
744
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700745 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000746
Olli Etuaho27446bd2015-08-10 14:59:53 +0300747 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300748 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000749
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700750 if (visit)
751 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300752 node->getCondition()->traverse(this);
753 if (node->getTrueBlock())
754 node->getTrueBlock()->traverse(this);
755 if (node->getFalseBlock())
756 node->getFalseBlock()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700757 }
758
Olli Etuaho27446bd2015-08-10 14:59:53 +0300759 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300760 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000761}
762
763//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200764// Traverse a switch node. Same comments in binary node apply here.
765//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300766void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200767{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000768 ScopedNodeInTraversalPath addToPath(this, node);
769
Olli Etuahoa3a36662015-02-17 13:46:51 +0200770 bool visit = true;
771
Olli Etuaho27446bd2015-08-10 14:59:53 +0300772 if (preVisit)
773 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200774
775 if (visit)
776 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300777 node->getInit()->traverse(this);
778 if (inVisit)
779 visit = visitSwitch(InVisit, node);
780 if (visit && node->getStatementList())
781 node->getStatementList()->traverse(this);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200782 }
783
Olli Etuaho27446bd2015-08-10 14:59:53 +0300784 if (visit && postVisit)
785 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200786}
787
788//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300789// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200790//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300791void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200792{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000793 ScopedNodeInTraversalPath addToPath(this, node);
794
Olli Etuahoa3a36662015-02-17 13:46:51 +0200795 bool visit = true;
796
Olli Etuaho27446bd2015-08-10 14:59:53 +0300797 if (preVisit)
798 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200799
Olli Etuaho27446bd2015-08-10 14:59:53 +0300800 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100801 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300802 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100803 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200804
Olli Etuaho27446bd2015-08-10 14:59:53 +0300805 if (visit && postVisit)
806 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200807}
808
809//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000810// Traverse a loop node. Same comments in binary node apply here.
811//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300812void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000814 ScopedNodeInTraversalPath addToPath(this, node);
815
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700816 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000817
Olli Etuaho27446bd2015-08-10 14:59:53 +0300818 if (preVisit)
819 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700821 if (visit)
822 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300823 if (node->getInit())
824 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825
Olli Etuaho27446bd2015-08-10 14:59:53 +0300826 if (node->getCondition())
827 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000828
Olli Etuaho27446bd2015-08-10 14:59:53 +0300829 if (node->getBody())
830 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700831
Olli Etuaho27446bd2015-08-10 14:59:53 +0300832 if (node->getExpression())
833 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700834 }
835
Olli Etuaho27446bd2015-08-10 14:59:53 +0300836 if (visit && postVisit)
837 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000838}
839
840//
841// Traverse a branch node. Same comments in binary node apply here.
842//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300843void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000844{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000845 ScopedNodeInTraversalPath addToPath(this, node);
846
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700847 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000848
Olli Etuaho27446bd2015-08-10 14:59:53 +0300849 if (preVisit)
850 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000851
Olli Etuaho27446bd2015-08-10 14:59:53 +0300852 if (visit && node->getExpression())
853 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300854 node->getExpression()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700855 }
856
Olli Etuaho27446bd2015-08-10 14:59:53 +0300857 if (visit && postVisit)
858 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000859}
860
Olli Etuaho27446bd2015-08-10 14:59:53 +0300861void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400862{
Olli Etuaho1d9dcc22017-01-19 11:25:32 +0000863 ScopedNodeInTraversalPath addToPath(this, node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300864 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400865}
Jamie Madill45bcc782016-11-07 13:58:48 -0500866
867} // namespace sh