blob: ab3ad15ddc3807b5c9011b47d1af216ba8a2ab7f [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 Etuaho27446bd2015-08-10 14:59:53 +030084void TIntermAggregate::traverse(TIntermTraverser *it)
85{
86 it->traverseAggregate(this);
87}
88
89void TIntermLoop::traverse(TIntermTraverser *it)
90{
91 it->traverseLoop(this);
92}
93
94void TIntermBranch::traverse(TIntermTraverser *it)
95{
96 it->traverseBranch(this);
97}
98
Jamie Madill03d863c2016-07-27 18:15:53 -040099TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit)
100 : preVisit(preVisit),
101 inVisit(inVisit),
102 postVisit(postVisit),
103 mDepth(0),
104 mMaxDepth(0),
105 mInGlobalScope(true),
106 mTemporaryIndex(nullptr)
107{
108}
109
110TIntermTraverser::~TIntermTraverser()
111{
112}
113
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100114void TIntermTraverser::pushParentBlock(TIntermBlock *node)
Olli Etuaho56eea882015-05-18 12:41:03 +0300115{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300116 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +0300117}
118
119void TIntermTraverser::incrementParentBlockPos()
120{
Olli Etuaho64f0be92015-06-03 17:38:34 +0300121 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +0300122}
123
124void TIntermTraverser::popParentBlock()
125{
126 ASSERT(!mParentBlockStack.empty());
127 mParentBlockStack.pop_back();
128}
129
130void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
131{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300132 TIntermSequence emptyInsertionsAfter;
133 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
134}
135
136void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
137 const TIntermSequence &insertionsAfter)
138{
Olli Etuaho56eea882015-05-18 12:41:03 +0300139 ASSERT(!mParentBlockStack.empty());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300140 NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos,
141 insertionsBefore, insertionsAfter);
Olli Etuaho56eea882015-05-18 12:41:03 +0300142 mInsertions.push_back(insert);
143}
144
Jamie Madill1048e432016-07-23 18:51:28 -0400145void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
146{
147 TIntermSequence insertions;
148 insertions.push_back(statement);
149 insertStatementsInParentBlock(insertions);
150}
151
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300152TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300153{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500154 // Each traversal uses at most one temporary variable, so the index stays the same within a
155 // single traversal.
Olli Etuahod4f303e2015-05-20 17:09:06 +0300156 TInfoSinkBase symbolNameOut;
157 ASSERT(mTemporaryIndex != nullptr);
158 symbolNameOut << "s" << (*mTemporaryIndex);
159 TString symbolName = symbolNameOut.c_str();
160
161 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
162 node->setInternal(true);
Olli Etuahob990b552016-10-27 12:29:17 +0100163
164 ASSERT(qualifier == EvqTemporary || qualifier == EvqConst || qualifier == EvqGlobal);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300165 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahob990b552016-10-27 12:29:17 +0100166 // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
167 // symbol. This might need to be done in other places as well.
Olli Etuahod4f303e2015-05-20 17:09:06 +0300168 return node;
169}
170
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300171TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
172{
173 return createTempSymbol(type, EvqTemporary);
174}
175
Olli Etuaho13389b62016-10-16 11:48:18 +0100176TIntermDeclaration *TIntermTraverser::createTempDeclaration(const TType &type)
Olli Etuaho4f1af782015-05-25 11:55:07 +0300177{
Olli Etuaho13389b62016-10-16 11:48:18 +0100178 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
179 tempDeclaration->appendDeclarator(createTempSymbol(type));
Olli Etuaho4f1af782015-05-25 11:55:07 +0300180 return tempDeclaration;
181}
Olli Etuahod4f303e2015-05-20 17:09:06 +0300182
Olli Etuaho13389b62016-10-16 11:48:18 +0100183TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer,
184 TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +0300185{
186 ASSERT(initializer != nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500187 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuaho13389b62016-10-16 11:48:18 +0100188 TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500189 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
Olli Etuaho13389b62016-10-16 11:48:18 +0100190 tempDeclaration->appendDeclarator(tempInit);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300191 return tempDeclaration;
192}
193
Olli Etuaho13389b62016-10-16 11:48:18 +0100194TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300195{
196 return createTempInitDeclaration(initializer, EvqTemporary);
197}
198
Olli Etuahod4f303e2015-05-20 17:09:06 +0300199TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
200{
201 ASSERT(rightNode != nullptr);
202 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300203 TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
Olli Etuahod4f303e2015-05-20 17:09:06 +0300204 return assignment;
205}
206
207void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
208{
209 mTemporaryIndex = temporaryIndex;
210}
211
212void TIntermTraverser::nextTemporaryIndex()
213{
214 ASSERT(mTemporaryIndex != nullptr);
215 ++(*mTemporaryIndex);
216}
217
Olli Etuaho5f579b12015-08-14 17:44:43 +0300218void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequence *paramSequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300219{
220 mFunctionMap[name] = paramSequence;
221}
222
Olli Etuaho3fc93372015-08-11 14:50:59 +0300223bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
Olli Etuahoa26ad582015-08-04 13:51:47 +0300224{
Olli Etuaho59f9a642015-08-06 20:38:26 +0300225 ASSERT(callNode->getOp() == EOpFunctionCall);
Olli Etuahobd674552016-10-06 13:28:42 +0100226 return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
227 mFunctionMap.end());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300228}
229
Olli Etuaho3fc93372015-08-11 14:50:59 +0300230TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300231{
232 ASSERT(isInFunctionMap(callNode));
Olli Etuahobd674552016-10-06 13:28:42 +0100233 return mFunctionMap[callNode->getFunctionSymbolInfo()->getNameObj()];
Olli Etuahoa26ad582015-08-04 13:51:47 +0300234}
235
Olli Etuaho3fc93372015-08-11 14:50:59 +0300236void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300237{
238 mInFunctionCallOutParameter = inOutParameter;
239}
240
Olli Etuaho3fc93372015-08-11 14:50:59 +0300241bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300242{
243 return mInFunctionCallOutParameter;
244}
245
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000246//
247// Traverse the intermediate representation tree, and
248// call a node type specific function for each node.
249// Done recursively through the member function Traverse().
250// Node types can be skipped if their function to call is 0,
251// but their subtree will still be traversed.
252// Nodes with children can have their whole subtree skipped
253// if preVisit is turned on and the type specific function
254// returns false.
255//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256
257//
258// Traversal functions for terminals are straighforward....
259//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300260void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300262 visitSymbol(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000263}
264
Olli Etuaho27446bd2015-08-10 14:59:53 +0300265void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300267 visitConstantUnion(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268}
269
Olli Etuahob6fa0432016-09-28 16:28:05 +0100270void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
271{
272 bool visit = true;
273
274 if (preVisit)
275 visit = visitSwizzle(PreVisit, node);
276
277 if (visit)
278 {
279 incrementDepth(node);
280
281 node->getOperand()->traverse(this);
282
283 decrementDepth();
284 }
285
286 if (visit && postVisit)
287 visitSwizzle(PostVisit, node);
288}
289
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290//
291// Traverse a binary node.
292//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300293void TIntermTraverser::traverseBinary(TIntermBinary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000294{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700295 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700297 //
298 // visit the node before children if pre-visiting.
299 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300300 if (preVisit)
301 visit = visitBinary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000302
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700303 //
304 // Visit the children, in the right order.
305 //
306 if (visit)
307 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300308 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309
Olli Etuaho3fc93372015-08-11 14:50:59 +0300310 if (node->getLeft())
311 node->getLeft()->traverse(this);
312
313 if (inVisit)
314 visit = visitBinary(InVisit, node);
315
316 if (visit && node->getRight())
317 node->getRight()->traverse(this);
318
319 decrementDepth();
320 }
321
322 //
323 // Visit the node after the children, if requested and the traversal
324 // hasn't been cancelled yet.
325 //
326 if (visit && postVisit)
327 visitBinary(PostVisit, node);
328}
329
330void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
331{
332 bool visit = true;
333
334 //
335 // visit the node before children if pre-visiting.
336 //
337 if (preVisit)
338 visit = visitBinary(PreVisit, node);
339
340 //
341 // Visit the children, in the right order.
342 //
343 if (visit)
344 {
345 incrementDepth(node);
346
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300347 // Some binary operations like indexing can be inside an expression which must be an
348 // l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300349 bool parentOperatorRequiresLValue = operatorRequiresLValue();
350 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
351 if (node->isAssignment())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300352 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300353 ASSERT(!isLValueRequiredHere());
354 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300355 }
356
Olli Etuaho27446bd2015-08-10 14:59:53 +0300357 if (node->getLeft())
358 node->getLeft()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359
Olli Etuaho27446bd2015-08-10 14:59:53 +0300360 if (inVisit)
361 visit = visitBinary(InVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362
Olli Etuaho27446bd2015-08-10 14:59:53 +0300363 if (node->isAssignment())
364 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300365
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300366 // Index is not required to be an l-value even when the surrounding expression is required
367 // to be an l-value.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300368 TOperator op = node->getOp();
369 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
370 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300371 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300372 setOperatorRequiresLValue(false);
373 setInFunctionCallOutParameter(false);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300374 }
375
Olli Etuaho27446bd2015-08-10 14:59:53 +0300376 if (visit && node->getRight())
377 node->getRight()->traverse(this);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700378
Olli Etuaho27446bd2015-08-10 14:59:53 +0300379 setOperatorRequiresLValue(parentOperatorRequiresLValue);
380 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300381
Olli Etuaho27446bd2015-08-10 14:59:53 +0300382 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700383 }
384
385 //
386 // Visit the node after the children, if requested and the traversal
387 // hasn't been cancelled yet.
388 //
Olli Etuaho27446bd2015-08-10 14:59:53 +0300389 if (visit && postVisit)
390 visitBinary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000391}
392
393//
394// Traverse a unary node. Same comments in binary node apply here.
395//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300396void TIntermTraverser::traverseUnary(TIntermUnary *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000397{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700398 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000399
Olli Etuaho27446bd2015-08-10 14:59:53 +0300400 if (preVisit)
401 visit = visitUnary(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402
Olli Etuahoa26ad582015-08-04 13:51:47 +0300403 if (visit)
404 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300405 incrementDepth(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300406
Olli Etuaho3fc93372015-08-11 14:50:59 +0300407 node->getOperand()->traverse(this);
408
409 decrementDepth();
410 }
411
412 if (visit && postVisit)
413 visitUnary(PostVisit, node);
414}
415
416void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
417{
418 bool visit = true;
419
420 if (preVisit)
421 visit = visitUnary(PreVisit, node);
422
423 if (visit)
424 {
425 incrementDepth(node);
426
Olli Etuaho27446bd2015-08-10 14:59:53 +0300427 ASSERT(!operatorRequiresLValue());
428 switch (node->getOp())
Olli Etuahoa26ad582015-08-04 13:51:47 +0300429 {
430 case EOpPostIncrement:
431 case EOpPostDecrement:
432 case EOpPreIncrement:
433 case EOpPreDecrement:
Olli Etuaho27446bd2015-08-10 14:59:53 +0300434 setOperatorRequiresLValue(true);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300435 break;
436 default:
437 break;
438 }
439
Olli Etuaho27446bd2015-08-10 14:59:53 +0300440 node->getOperand()->traverse(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300441
Olli Etuaho27446bd2015-08-10 14:59:53 +0300442 setOperatorRequiresLValue(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300443
Olli Etuaho27446bd2015-08-10 14:59:53 +0300444 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700445 }
446
Olli Etuaho27446bd2015-08-10 14:59:53 +0300447 if (visit && postVisit)
448 visitUnary(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000449}
450
Olli Etuaho336b1472016-10-05 16:37:55 +0100451// Traverse a function definition node.
452void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
453{
454 bool visit = true;
455
456 if (preVisit)
457 visit = visitFunctionDefinition(PreVisit, node);
458
459 if (visit)
460 {
461 incrementDepth(node);
462 mInGlobalScope = false;
463
464 node->getFunctionParameters()->traverse(this);
465 if (inVisit)
466 visit = visitFunctionDefinition(InVisit, node);
467 node->getBody()->traverse(this);
468
469 mInGlobalScope = true;
470 decrementDepth();
471 }
472
473 if (visit && postVisit)
474 visitFunctionDefinition(PostVisit, node);
475}
476
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100477// Traverse a block node.
478void TIntermTraverser::traverseBlock(TIntermBlock *node)
479{
480 bool visit = true;
481
482 TIntermSequence *sequence = node->getSequence();
483
484 if (preVisit)
485 visit = visitBlock(PreVisit, node);
486
487 if (visit)
488 {
489 incrementDepth(node);
490 pushParentBlock(node);
491
492 for (auto *child : *sequence)
493 {
494 child->traverse(this);
495 if (visit && inVisit)
496 {
497 if (child != sequence->back())
498 visit = visitBlock(InVisit, node);
499 }
500
501 incrementParentBlockPos();
502 }
503
504 popParentBlock();
505 decrementDepth();
506 }
507
508 if (visit && postVisit)
509 visitBlock(PostVisit, node);
510}
511
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000512void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
513{
514 bool visit = true;
515
516 if (preVisit)
517 {
518 visit = visitInvariantDeclaration(PreVisit, node);
519 }
520
521 if (visit)
522 {
523 node->getSymbol()->traverse(this);
524 if (postVisit)
525 {
526 visitInvariantDeclaration(PostVisit, node);
527 }
528 }
529}
530
Olli Etuaho13389b62016-10-16 11:48:18 +0100531// Traverse a declaration node.
532void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
533{
534 bool visit = true;
535
536 TIntermSequence *sequence = node->getSequence();
537
538 if (preVisit)
539 visit = visitDeclaration(PreVisit, node);
540
541 if (visit)
542 {
543 incrementDepth(node);
544
545 for (auto *child : *sequence)
546 {
547 child->traverse(this);
548 if (visit && inVisit)
549 {
550 if (child != sequence->back())
551 visit = visitDeclaration(InVisit, node);
552 }
553 }
554
555 decrementDepth();
556 }
557
558 if (visit && postVisit)
559 visitDeclaration(PostVisit, node);
560}
561
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562// Traverse an aggregate node. Same comments in binary node apply here.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300563void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000564{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700565 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000566
Olli Etuaho27446bd2015-08-10 14:59:53 +0300567 TIntermSequence *sequence = node->getSequence();
Olli Etuaho3fc93372015-08-11 14:50:59 +0300568
569 if (preVisit)
570 visit = visitAggregate(PreVisit, node);
571
572 if (visit)
573 {
574 incrementDepth(node);
575
Olli Etuaho3fc93372015-08-11 14:50:59 +0300576 for (auto *child : *sequence)
577 {
578 child->traverse(this);
579 if (visit && inVisit)
580 {
581 if (child != sequence->back())
582 visit = visitAggregate(InVisit, node);
583 }
Olli Etuaho3fc93372015-08-11 14:50:59 +0300584 }
585
Olli Etuaho3fc93372015-08-11 14:50:59 +0300586 decrementDepth();
587 }
588
589 if (visit && postVisit)
590 visitAggregate(PostVisit, node);
591}
592
Olli Etuaho336b1472016-10-05 16:37:55 +0100593void TLValueTrackingTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
594{
595 TIntermAggregate *params = node->getFunctionParameters();
596 ASSERT(params != nullptr);
597 ASSERT(params->getOp() == EOpParameters);
598 addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), params->getSequence());
599
600 TIntermTraverser::traverseFunctionDefinition(node);
601}
602
Olli Etuaho3fc93372015-08-11 14:50:59 +0300603void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
604{
605 bool visit = true;
606
607 TIntermSequence *sequence = node->getSequence();
Olli Etuaho336b1472016-10-05 16:37:55 +0100608 if (node->getOp() == EOpPrototype)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300609 {
Olli Etuaho336b1472016-10-05 16:37:55 +0100610 addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300611 }
612
Olli Etuaho27446bd2015-08-10 14:59:53 +0300613 if (preVisit)
614 visit = visitAggregate(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000615
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700616 if (visit)
617 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300618 bool inFunctionMap = false;
Olli Etuaho27446bd2015-08-10 14:59:53 +0300619 if (node->getOp() == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700620 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300621 inFunctionMap = isInFunctionMap(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300622 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300623 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300624 // The function is not user-defined - it is likely built-in texture function.
625 // Assume that those do not have out parameters.
Olli Etuaho27446bd2015-08-10 14:59:53 +0300626 setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700627 }
628 }
629
Olli Etuaho27446bd2015-08-10 14:59:53 +0300630 incrementDepth(node);
Olli Etuaho56eea882015-05-18 12:41:03 +0300631
Olli Etuahoa26ad582015-08-04 13:51:47 +0300632 if (inFunctionMap)
633 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300634 TIntermSequence *params = getFunctionParameters(node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300635 TIntermSequence::iterator paramIter = params->begin();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300636 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300637 {
638 ASSERT(paramIter != params->end());
639 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
Olli Etuaho27446bd2015-08-10 14:59:53 +0300640 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300641
Olli Etuaho27446bd2015-08-10 14:59:53 +0300642 child->traverse(this);
643 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300644 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300645 if (child != sequence->back())
646 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300647 }
648
649 ++paramIter;
650 }
651
Olli Etuaho27446bd2015-08-10 14:59:53 +0300652 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300653 }
654 else
655 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300656 // Find the built-in function corresponding to this op so that we can determine the
657 // in/out qualifiers of its parameters.
658 TFunction *builtInFunc = nullptr;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500659 TString opString = GetOperatorString(node->getOp());
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300660 if (!node->isConstructor() && !opString.empty())
661 {
662 // The return type doesn't affect the mangled name of the function, which is used
663 // to look it up from the symbol table.
664 TType dummyReturnType;
665 TFunction call(&opString, &dummyReturnType, node->getOp());
666 for (auto *child : *sequence)
667 {
668 TType *paramType = child->getAsTyped()->getTypePointer();
669 TConstParameter p(paramType);
670 call.addParameter(p);
671 }
672
673 TSymbol *sym = mSymbolTable.findBuiltIn(call.getMangledName(), mShaderVersion);
674 if (sym != nullptr && sym->isFunction())
675 {
676 builtInFunc = static_cast<TFunction *>(sym);
677 ASSERT(builtInFunc->getParamCount() == sequence->size());
678 }
679 }
680
681 size_t paramIndex = 0;
682
Olli Etuaho27446bd2015-08-10 14:59:53 +0300683 for (auto *child : *sequence)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300684 {
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300685 TQualifier qualifier = EvqIn;
686 if (builtInFunc != nullptr)
687 qualifier = builtInFunc->getParam(paramIndex).type->getQualifier();
688 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300689 child->traverse(this);
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300690
Olli Etuaho27446bd2015-08-10 14:59:53 +0300691 if (visit && inVisit)
Olli Etuahoa26ad582015-08-04 13:51:47 +0300692 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300693 if (child != sequence->back())
694 visit = visitAggregate(InVisit, node);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300695 }
696
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300697 ++paramIndex;
Olli Etuahoa26ad582015-08-04 13:51:47 +0300698 }
699
Olli Etuaho217fe6e2015-08-05 13:25:08 +0300700 setInFunctionCallOutParameter(false);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300701 }
702
Olli Etuaho27446bd2015-08-10 14:59:53 +0300703 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700704 }
705
Olli Etuaho27446bd2015-08-10 14:59:53 +0300706 if (visit && postVisit)
707 visitAggregate(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000708}
709
710//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300711// Traverse a ternary node. Same comments in binary node apply here.
712//
713void TIntermTraverser::traverseTernary(TIntermTernary *node)
714{
715 bool visit = true;
716
717 if (preVisit)
718 visit = visitTernary(PreVisit, node);
719
720 if (visit)
721 {
722 incrementDepth(node);
723 node->getCondition()->traverse(this);
724 if (node->getTrueExpression())
725 node->getTrueExpression()->traverse(this);
726 if (node->getFalseExpression())
727 node->getFalseExpression()->traverse(this);
728 decrementDepth();
729 }
730
731 if (visit && postVisit)
732 visitTernary(PostVisit, node);
733}
734
Olli Etuaho57961272016-09-14 13:57:46 +0300735// Traverse an if-else node. Same comments in binary node apply here.
736void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000737{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700738 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000739
Olli Etuaho27446bd2015-08-10 14:59:53 +0300740 if (preVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300741 visit = visitIfElse(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000742
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700743 if (visit)
744 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300745 incrementDepth(node);
746 node->getCondition()->traverse(this);
747 if (node->getTrueBlock())
748 node->getTrueBlock()->traverse(this);
749 if (node->getFalseBlock())
750 node->getFalseBlock()->traverse(this);
751 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700752 }
753
Olli Etuaho27446bd2015-08-10 14:59:53 +0300754 if (visit && postVisit)
Olli Etuaho57961272016-09-14 13:57:46 +0300755 visitIfElse(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756}
757
758//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200759// Traverse a switch node. Same comments in binary node apply here.
760//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300761void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200762{
763 bool visit = true;
764
Olli Etuaho27446bd2015-08-10 14:59:53 +0300765 if (preVisit)
766 visit = visitSwitch(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200767
768 if (visit)
769 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300770 incrementDepth(node);
771 node->getInit()->traverse(this);
772 if (inVisit)
773 visit = visitSwitch(InVisit, node);
774 if (visit && node->getStatementList())
775 node->getStatementList()->traverse(this);
776 decrementDepth();
Olli Etuahoa3a36662015-02-17 13:46:51 +0200777 }
778
Olli Etuaho27446bd2015-08-10 14:59:53 +0300779 if (visit && postVisit)
780 visitSwitch(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200781}
782
783//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300784// Traverse a case node. Same comments in binary node apply here.
Olli Etuahoa3a36662015-02-17 13:46:51 +0200785//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300786void TIntermTraverser::traverseCase(TIntermCase *node)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200787{
788 bool visit = true;
789
Olli Etuaho27446bd2015-08-10 14:59:53 +0300790 if (preVisit)
791 visit = visitCase(PreVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200792
Olli Etuaho27446bd2015-08-10 14:59:53 +0300793 if (visit && node->getCondition())
Olli Etuaho65c79db2016-10-06 17:11:28 +0100794 {
795 incrementDepth(node);
Olli Etuaho27446bd2015-08-10 14:59:53 +0300796 node->getCondition()->traverse(this);
Olli Etuaho65c79db2016-10-06 17:11:28 +0100797 decrementDepth();
798 }
Olli Etuahoa3a36662015-02-17 13:46:51 +0200799
Olli Etuaho27446bd2015-08-10 14:59:53 +0300800 if (visit && postVisit)
801 visitCase(PostVisit, node);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200802}
803
804//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000805// Traverse a loop node. Same comments in binary node apply here.
806//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300807void TIntermTraverser::traverseLoop(TIntermLoop *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000808{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700809 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000810
Olli Etuaho27446bd2015-08-10 14:59:53 +0300811 if (preVisit)
812 visit = visitLoop(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000813
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700814 if (visit)
815 {
Olli Etuaho27446bd2015-08-10 14:59:53 +0300816 incrementDepth(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000817
Olli Etuaho27446bd2015-08-10 14:59:53 +0300818 if (node->getInit())
819 node->getInit()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000820
Olli Etuaho27446bd2015-08-10 14:59:53 +0300821 if (node->getCondition())
822 node->getCondition()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000823
Olli Etuaho27446bd2015-08-10 14:59:53 +0300824 if (node->getBody())
825 node->getBody()->traverse(this);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700826
Olli Etuaho27446bd2015-08-10 14:59:53 +0300827 if (node->getExpression())
828 node->getExpression()->traverse(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000829
Olli Etuaho27446bd2015-08-10 14:59:53 +0300830 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700831 }
832
Olli Etuaho27446bd2015-08-10 14:59:53 +0300833 if (visit && postVisit)
834 visitLoop(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000835}
836
837//
838// Traverse a branch node. Same comments in binary node apply here.
839//
Olli Etuaho27446bd2015-08-10 14:59:53 +0300840void TIntermTraverser::traverseBranch(TIntermBranch *node)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000841{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700842 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000843
Olli Etuaho27446bd2015-08-10 14:59:53 +0300844 if (preVisit)
845 visit = visitBranch(PreVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000846
Olli Etuaho27446bd2015-08-10 14:59:53 +0300847 if (visit && node->getExpression())
848 {
849 incrementDepth(node);
850 node->getExpression()->traverse(this);
851 decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700852 }
853
Olli Etuaho27446bd2015-08-10 14:59:53 +0300854 if (visit && postVisit)
855 visitBranch(PostVisit, node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000856}
857
Olli Etuaho27446bd2015-08-10 14:59:53 +0300858void TIntermTraverser::traverseRaw(TIntermRaw *node)
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400859{
Olli Etuaho27446bd2015-08-10 14:59:53 +0300860 visitRaw(node);
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400861}
Jamie Madill45bcc782016-11-07 13:58:48 -0500862
863} // namespace sh