blob: a19b5463dff8d6092d45fc7d880debf82c5e4e27 [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"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009
Olli Etuaho56eea882015-05-18 12:41:03 +030010void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
11{
Olli Etuaho64f0be92015-06-03 17:38:34 +030012 mParentBlockStack.push_back(ParentBlock(node, 0));
Olli Etuaho56eea882015-05-18 12:41:03 +030013}
14
15void TIntermTraverser::incrementParentBlockPos()
16{
Olli Etuaho64f0be92015-06-03 17:38:34 +030017 ++mParentBlockStack.back().pos;
Olli Etuaho56eea882015-05-18 12:41:03 +030018}
19
20void TIntermTraverser::popParentBlock()
21{
22 ASSERT(!mParentBlockStack.empty());
23 mParentBlockStack.pop_back();
24}
25
26void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
27{
28 ASSERT(!mParentBlockStack.empty());
29 NodeInsertMultipleEntry insert(mParentBlockStack.back().node, mParentBlockStack.back().pos, insertions);
30 mInsertions.push_back(insert);
31}
32
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030033TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +030034{
35 // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal.
36 TInfoSinkBase symbolNameOut;
37 ASSERT(mTemporaryIndex != nullptr);
38 symbolNameOut << "s" << (*mTemporaryIndex);
39 TString symbolName = symbolNameOut.c_str();
40
41 TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
42 node->setInternal(true);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030043 node->getTypePointer()->setQualifier(qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +030044 return node;
45}
46
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030047TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
48{
49 return createTempSymbol(type, EvqTemporary);
50}
51
Olli Etuaho4f1af782015-05-25 11:55:07 +030052TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
53{
54 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
55 tempDeclaration->getSequence()->push_back(createTempSymbol(type));
56 return tempDeclaration;
57}
Olli Etuahod4f303e2015-05-20 17:09:06 +030058
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030059TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
Olli Etuahod4f303e2015-05-20 17:09:06 +030060{
61 ASSERT(initializer != nullptr);
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030062 TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
Olli Etuahod4f303e2015-05-20 17:09:06 +030063 TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
64 TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
65 tempInit->setLeft(tempSymbol);
66 tempInit->setRight(initializer);
67 tempInit->setType(tempSymbol->getType());
68 tempDeclaration->getSequence()->push_back(tempInit);
69 return tempDeclaration;
70}
71
Olli Etuahoa4aa4e32015-06-04 15:54:30 +030072TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
73{
74 return createTempInitDeclaration(initializer, EvqTemporary);
75}
76
Olli Etuahod4f303e2015-05-20 17:09:06 +030077TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
78{
79 ASSERT(rightNode != nullptr);
80 TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
81 TIntermBinary *assignment = new TIntermBinary(EOpAssign);
82 assignment->setLeft(tempSymbol);
83 assignment->setRight(rightNode);
84 assignment->setType(tempSymbol->getType());
85 return assignment;
86}
87
88void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
89{
90 mTemporaryIndex = temporaryIndex;
91}
92
93void TIntermTraverser::nextTemporaryIndex()
94{
95 ASSERT(mTemporaryIndex != nullptr);
96 ++(*mTemporaryIndex);
97}
98
Olli Etuahoa26ad582015-08-04 13:51:47 +030099void TIntermTraverser::addToFunctionMap(const TString &name, TIntermSequence *paramSequence)
100{
101 mFunctionMap[name] = paramSequence;
102}
103
104bool TIntermTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
105{
106 ASSERT(callNode->getOp() == EOpFunctionCall || callNode->getOp() == EOpInternalFunctionCall);
107 return (mFunctionMap.find(callNode->getName()) != mFunctionMap.end());
108}
109
110TIntermSequence *TIntermTraverser::getFunctionParameters(const TIntermAggregate *callNode)
111{
112 ASSERT(isInFunctionMap(callNode));
113 return mFunctionMap[callNode->getName()];
114}
115
116void TIntermTraverser::setInFunctionCallOutParameter(bool inOutParameter)
117{
118 mInFunctionCallOutParameter = inOutParameter;
119}
120
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121//
122// Traverse the intermediate representation tree, and
123// call a node type specific function for each node.
124// Done recursively through the member function Traverse().
125// Node types can be skipped if their function to call is 0,
126// but their subtree will still be traversed.
127// Nodes with children can have their whole subtree skipped
128// if preVisit is turned on and the type specific function
129// returns false.
130//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131
132//
133// Traversal functions for terminals are straighforward....
134//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700135void TIntermSymbol::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700137 it->visitSymbol(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138}
139
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700140void TIntermConstantUnion::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700142 it->visitConstantUnion(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143}
144
145//
146// Traverse a binary node.
147//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700148void TIntermBinary::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700150 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700152 //
153 // visit the node before children if pre-visiting.
154 //
155 if (it->preVisit)
156 visit = it->visitBinary(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700158 //
159 // Visit the children, in the right order.
160 //
161 if (visit)
162 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700163 it->incrementDepth(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164
Olli Etuahoa26ad582015-08-04 13:51:47 +0300165 if (isAssignment())
166 {
167 // Some binary operations like indexing can be inside an l-value.
168 // TODO(oetuaho@nvidia.com): Now the code doesn't unset operatorRequiresLValue for the
169 // index, fix this.
170 it->setOperatorRequiresLValue(true);
171 }
172
Olli Etuaho64f0be92015-06-03 17:38:34 +0300173 if (mLeft)
174 mLeft->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175
Olli Etuaho64f0be92015-06-03 17:38:34 +0300176 if (it->inVisit)
177 visit = it->visitBinary(InVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178
Olli Etuahoa26ad582015-08-04 13:51:47 +0300179 if (isAssignment())
180 it->setOperatorRequiresLValue(false);
181
Olli Etuaho64f0be92015-06-03 17:38:34 +0300182 if (visit && mRight)
183 mRight->traverse(it);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700184
185 it->decrementDepth();
186 }
187
188 //
189 // Visit the node after the children, if requested and the traversal
190 // hasn't been cancelled yet.
191 //
192 if (visit && it->postVisit)
193 it->visitBinary(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194}
195
196//
197// Traverse a unary node. Same comments in binary node apply here.
198//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700199void TIntermUnary::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700201 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700203 if (it->preVisit)
204 visit = it->visitUnary(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205
Olli Etuahoa26ad582015-08-04 13:51:47 +0300206 if (visit)
207 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700208 it->incrementDepth(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300209
210 switch (getOp())
211 {
212 case EOpPostIncrement:
213 case EOpPostDecrement:
214 case EOpPreIncrement:
215 case EOpPreDecrement:
216 it->setOperatorRequiresLValue(true);
217 break;
218 default:
219 break;
220 }
221
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700222 mOperand->traverse(it);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300223
224 it->setOperatorRequiresLValue(false);
225
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700226 it->decrementDepth();
227 }
228
229 if (visit && it->postVisit)
230 it->visitUnary(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000231}
232
233//
234// Traverse an aggregate node. Same comments in binary node apply here.
235//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700236void TIntermAggregate::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000237{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700238 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239
Olli Etuahoa26ad582015-08-04 13:51:47 +0300240 switch (mOp)
241 {
242 case EOpFunction:
243 {
244 TIntermAggregate *params = mSequence.front()->getAsAggregate();
245 ASSERT(params != nullptr);
246 ASSERT(params->getOp() == EOpParameters);
247 it->addToFunctionMap(mName, params->getSequence());
248 break;
249 }
250 case EOpPrototype:
251 it->addToFunctionMap(mName, &mSequence);
252 break;
253 default:
254 break;
255 }
256
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700257 if (it->preVisit)
258 visit = it->visitAggregate(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700260 if (visit)
261 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300262 bool inFunctionMap = false;
263 if (mOp == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700264 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300265 inFunctionMap = it->isInFunctionMap(this);
266 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300267 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300268 // The function is not user-defined - it is likely built-in texture function.
269 // Assume that those do not have out parameters.
270 it->setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700271 }
272 }
273
Olli Etuahoa26ad582015-08-04 13:51:47 +0300274 it->incrementDepth(this);
Olli Etuaho56eea882015-05-18 12:41:03 +0300275
Olli Etuahoa26ad582015-08-04 13:51:47 +0300276 if (inFunctionMap)
277 {
278 TIntermSequence *params = it->getFunctionParameters(this);
279 TIntermSequence::iterator paramIter = params->begin();
280 for (auto *child : mSequence)
281 {
282 ASSERT(paramIter != params->end());
283 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
284 it->setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
285
286 child->traverse(it);
287 if (visit && it->inVisit)
288 {
289 if (child != mSequence.back())
290 visit = it->visitAggregate(InVisit, this);
291 }
292
293 ++paramIter;
294 }
295
296 it->setInFunctionCallOutParameter(false);
297 }
298 else
299 {
300 if (mOp == EOpSequence)
301 it->pushParentBlock(this);
302
303 for (auto *child : mSequence)
304 {
305 child->traverse(it);
306 if (visit && it->inVisit)
307 {
308 if (child != mSequence.back())
309 visit = it->visitAggregate(InVisit, this);
310 }
311
312 if (mOp == EOpSequence)
313 it->incrementParentBlockPos();
314 }
315
316 if (mOp == EOpSequence)
317 it->popParentBlock();
318 }
319
320 it->decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700321 }
322
323 if (visit && it->postVisit)
324 it->visitAggregate(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325}
326
327//
328// Traverse a selection node. Same comments in binary node apply here.
329//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700330void TIntermSelection::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700332 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700334 if (it->preVisit)
335 visit = it->visitSelection(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700337 if (visit)
338 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700339 it->incrementDepth(this);
Olli Etuaho64f0be92015-06-03 17:38:34 +0300340 mCondition->traverse(it);
341 if (mTrueBlock)
342 mTrueBlock->traverse(it);
343 if (mFalseBlock)
344 mFalseBlock->traverse(it);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700345 it->decrementDepth();
346 }
347
348 if (visit && it->postVisit)
349 it->visitSelection(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000350}
351
352//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200353// Traverse a switch node. Same comments in binary node apply here.
354//
355void TIntermSwitch::traverse(TIntermTraverser *it)
356{
357 bool visit = true;
358
359 if (it->preVisit)
360 visit = it->visitSwitch(PreVisit, this);
361
362 if (visit)
363 {
364 it->incrementDepth(this);
Olli Etuaho64f0be92015-06-03 17:38:34 +0300365 mInit->traverse(it);
366 if (it->inVisit)
367 visit = it->visitSwitch(InVisit, this);
368 if (visit && mStatementList)
369 mStatementList->traverse(it);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200370 it->decrementDepth();
371 }
372
373 if (visit && it->postVisit)
374 it->visitSwitch(PostVisit, this);
375}
376
377//
378// Traverse a switch node. Same comments in binary node apply here.
379//
380void TIntermCase::traverse(TIntermTraverser *it)
381{
382 bool visit = true;
383
384 if (it->preVisit)
385 visit = it->visitCase(PreVisit, this);
386
387 if (visit && mCondition)
388 mCondition->traverse(it);
389
390 if (visit && it->postVisit)
391 it->visitCase(PostVisit, this);
392}
393
394//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000395// Traverse a loop node. Same comments in binary node apply here.
396//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700397void TIntermLoop::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000398{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700399 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700401 if (it->preVisit)
402 visit = it->visitLoop(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700404 if (visit)
405 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700406 it->incrementDepth(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000407
Olli Etuaho64f0be92015-06-03 17:38:34 +0300408 if (mInit)
409 mInit->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000410
Olli Etuaho64f0be92015-06-03 17:38:34 +0300411 if (mCond)
412 mCond->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413
Olli Etuaho64f0be92015-06-03 17:38:34 +0300414 if (mBody)
415 mBody->traverse(it);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700416
Olli Etuaho64f0be92015-06-03 17:38:34 +0300417 if (mExpr)
418 mExpr->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000419
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700420 it->decrementDepth();
421 }
422
423 if (visit && it->postVisit)
424 it->visitLoop(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425}
426
427//
428// Traverse a branch node. Same comments in binary node apply here.
429//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700430void TIntermBranch::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000431{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700432 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700434 if (it->preVisit)
435 visit = it->visitBranch(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700437 if (visit && mExpression) {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700438 it->incrementDepth(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700439 mExpression->traverse(it);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700440 it->decrementDepth();
441 }
442
443 if (visit && it->postVisit)
444 it->visitBranch(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445}
446
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400447void TIntermRaw::traverse(TIntermTraverser *it)
448{
449 it->visitRaw(this);
450}