blob: a64d144c18ab505cbacc3f0cd71b2f2d2e024c8f [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
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300121bool TIntermTraverser::isInFunctionCallOutParameter() const
122{
123 return mInFunctionCallOutParameter;
124}
125
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000126//
127// Traverse the intermediate representation tree, and
128// call a node type specific function for each node.
129// Done recursively through the member function Traverse().
130// Node types can be skipped if their function to call is 0,
131// but their subtree will still be traversed.
132// Nodes with children can have their whole subtree skipped
133// if preVisit is turned on and the type specific function
134// returns false.
135//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136
137//
138// Traversal functions for terminals are straighforward....
139//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700140void TIntermSymbol::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700142 it->visitSymbol(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143}
144
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700145void TIntermConstantUnion::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700147 it->visitConstantUnion(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148}
149
150//
151// Traverse a binary node.
152//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700153void TIntermBinary::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700155 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700157 //
158 // visit the node before children if pre-visiting.
159 //
160 if (it->preVisit)
161 visit = it->visitBinary(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700163 //
164 // Visit the children, in the right order.
165 //
166 if (visit)
167 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700168 it->incrementDepth(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300170 // Some binary operations like indexing can be inside an expression which must be an
171 // l-value.
172 bool parentOperatorRequiresLValue = it->operatorRequiresLValue();
173 bool parentInFunctionCallOutParameter = it->isInFunctionCallOutParameter();
Olli Etuahoa26ad582015-08-04 13:51:47 +0300174 if (isAssignment())
175 {
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300176 ASSERT(!it->isLValueRequiredHere());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300177 it->setOperatorRequiresLValue(true);
178 }
179
Olli Etuaho64f0be92015-06-03 17:38:34 +0300180 if (mLeft)
181 mLeft->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182
Olli Etuaho64f0be92015-06-03 17:38:34 +0300183 if (it->inVisit)
184 visit = it->visitBinary(InVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185
Olli Etuahoa26ad582015-08-04 13:51:47 +0300186 if (isAssignment())
187 it->setOperatorRequiresLValue(false);
188
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300189 // Index is not required to be an l-value even when the surrounding expression is required
190 // to be an l-value.
191 if (mOp == EOpIndexDirect || mOp == EOpIndexDirectInterfaceBlock ||
192 mOp == EOpIndexDirectStruct || mOp == EOpIndexIndirect)
193 {
194 it->setOperatorRequiresLValue(false);
195 it->setInFunctionCallOutParameter(false);
196 }
197
Olli Etuaho64f0be92015-06-03 17:38:34 +0300198 if (visit && mRight)
199 mRight->traverse(it);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700200
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300201 it->setOperatorRequiresLValue(parentOperatorRequiresLValue);
202 it->setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
203
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700204 it->decrementDepth();
205 }
206
207 //
208 // Visit the node after the children, if requested and the traversal
209 // hasn't been cancelled yet.
210 //
211 if (visit && it->postVisit)
212 it->visitBinary(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213}
214
215//
216// Traverse a unary node. Same comments in binary node apply here.
217//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700218void TIntermUnary::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700220 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000221
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700222 if (it->preVisit)
223 visit = it->visitUnary(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224
Olli Etuahoa26ad582015-08-04 13:51:47 +0300225 if (visit)
226 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700227 it->incrementDepth(this);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300228
Olli Etuaho8afe1e12015-08-05 18:00:01 +0300229 ASSERT(!it->operatorRequiresLValue());
Olli Etuahoa26ad582015-08-04 13:51:47 +0300230 switch (getOp())
231 {
232 case EOpPostIncrement:
233 case EOpPostDecrement:
234 case EOpPreIncrement:
235 case EOpPreDecrement:
236 it->setOperatorRequiresLValue(true);
237 break;
238 default:
239 break;
240 }
241
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700242 mOperand->traverse(it);
Olli Etuahoa26ad582015-08-04 13:51:47 +0300243
244 it->setOperatorRequiresLValue(false);
245
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700246 it->decrementDepth();
247 }
248
249 if (visit && it->postVisit)
250 it->visitUnary(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000251}
252
253//
254// Traverse an aggregate node. Same comments in binary node apply here.
255//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700256void TIntermAggregate::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700258 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259
Olli Etuahoa26ad582015-08-04 13:51:47 +0300260 switch (mOp)
261 {
262 case EOpFunction:
263 {
264 TIntermAggregate *params = mSequence.front()->getAsAggregate();
265 ASSERT(params != nullptr);
266 ASSERT(params->getOp() == EOpParameters);
267 it->addToFunctionMap(mName, params->getSequence());
268 break;
269 }
270 case EOpPrototype:
271 it->addToFunctionMap(mName, &mSequence);
272 break;
273 default:
274 break;
275 }
276
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700277 if (it->preVisit)
278 visit = it->visitAggregate(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700280 if (visit)
281 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300282 bool inFunctionMap = false;
283 if (mOp == EOpFunctionCall)
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700284 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300285 inFunctionMap = it->isInFunctionMap(this);
286 if (!inFunctionMap)
Olli Etuaho64f0be92015-06-03 17:38:34 +0300287 {
Olli Etuahoa26ad582015-08-04 13:51:47 +0300288 // The function is not user-defined - it is likely built-in texture function.
289 // Assume that those do not have out parameters.
290 it->setInFunctionCallOutParameter(false);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700291 }
292 }
293
Olli Etuahoa26ad582015-08-04 13:51:47 +0300294 it->incrementDepth(this);
Olli Etuaho56eea882015-05-18 12:41:03 +0300295
Olli Etuahoa26ad582015-08-04 13:51:47 +0300296 if (inFunctionMap)
297 {
298 TIntermSequence *params = it->getFunctionParameters(this);
299 TIntermSequence::iterator paramIter = params->begin();
300 for (auto *child : mSequence)
301 {
302 ASSERT(paramIter != params->end());
303 TQualifier qualifier = (*paramIter)->getAsTyped()->getQualifier();
304 it->setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
305
306 child->traverse(it);
307 if (visit && it->inVisit)
308 {
309 if (child != mSequence.back())
310 visit = it->visitAggregate(InVisit, this);
311 }
312
313 ++paramIter;
314 }
315
316 it->setInFunctionCallOutParameter(false);
317 }
318 else
319 {
320 if (mOp == EOpSequence)
321 it->pushParentBlock(this);
322
323 for (auto *child : mSequence)
324 {
325 child->traverse(it);
326 if (visit && it->inVisit)
327 {
328 if (child != mSequence.back())
329 visit = it->visitAggregate(InVisit, this);
330 }
331
332 if (mOp == EOpSequence)
333 it->incrementParentBlockPos();
334 }
335
336 if (mOp == EOpSequence)
337 it->popParentBlock();
338 }
339
340 it->decrementDepth();
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700341 }
342
343 if (visit && it->postVisit)
344 it->visitAggregate(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345}
346
347//
348// Traverse a selection node. Same comments in binary node apply here.
349//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700350void TIntermSelection::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700352 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700354 if (it->preVisit)
355 visit = it->visitSelection(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000356
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700357 if (visit)
358 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700359 it->incrementDepth(this);
Olli Etuaho64f0be92015-06-03 17:38:34 +0300360 mCondition->traverse(it);
361 if (mTrueBlock)
362 mTrueBlock->traverse(it);
363 if (mFalseBlock)
364 mFalseBlock->traverse(it);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700365 it->decrementDepth();
366 }
367
368 if (visit && it->postVisit)
369 it->visitSelection(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000370}
371
372//
Olli Etuahoa3a36662015-02-17 13:46:51 +0200373// Traverse a switch node. Same comments in binary node apply here.
374//
375void TIntermSwitch::traverse(TIntermTraverser *it)
376{
377 bool visit = true;
378
379 if (it->preVisit)
380 visit = it->visitSwitch(PreVisit, this);
381
382 if (visit)
383 {
384 it->incrementDepth(this);
Olli Etuaho64f0be92015-06-03 17:38:34 +0300385 mInit->traverse(it);
386 if (it->inVisit)
387 visit = it->visitSwitch(InVisit, this);
388 if (visit && mStatementList)
389 mStatementList->traverse(it);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200390 it->decrementDepth();
391 }
392
393 if (visit && it->postVisit)
394 it->visitSwitch(PostVisit, this);
395}
396
397//
398// Traverse a switch node. Same comments in binary node apply here.
399//
400void TIntermCase::traverse(TIntermTraverser *it)
401{
402 bool visit = true;
403
404 if (it->preVisit)
405 visit = it->visitCase(PreVisit, this);
406
407 if (visit && mCondition)
408 mCondition->traverse(it);
409
410 if (visit && it->postVisit)
411 it->visitCase(PostVisit, this);
412}
413
414//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415// Traverse a loop node. Same comments in binary node apply here.
416//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700417void TIntermLoop::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700419 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700421 if (it->preVisit)
422 visit = it->visitLoop(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000423
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700424 if (visit)
425 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700426 it->incrementDepth(this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427
Olli Etuaho64f0be92015-06-03 17:38:34 +0300428 if (mInit)
429 mInit->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000430
Olli Etuaho64f0be92015-06-03 17:38:34 +0300431 if (mCond)
432 mCond->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000433
Olli Etuaho64f0be92015-06-03 17:38:34 +0300434 if (mBody)
435 mBody->traverse(it);
Zhenyao Mo6cb95f32013-10-03 17:01:52 -0700436
Olli Etuaho64f0be92015-06-03 17:38:34 +0300437 if (mExpr)
438 mExpr->traverse(it);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700440 it->decrementDepth();
441 }
442
443 if (visit && it->postVisit)
444 it->visitLoop(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000445}
446
447//
448// Traverse a branch node. Same comments in binary node apply here.
449//
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700450void TIntermBranch::traverse(TIntermTraverser *it)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451{
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700452 bool visit = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700454 if (it->preVisit)
455 visit = it->visitBranch(PreVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000456
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700457 if (visit && mExpression) {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700458 it->incrementDepth(this);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700459 mExpression->traverse(it);
Zhenyao Moe88dcaf2013-10-03 16:55:19 -0700460 it->decrementDepth();
461 }
462
463 if (visit && it->postVisit)
464 it->visitBranch(PostVisit, this);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000465}
466
Jamie Madill4cfb1e82014-07-07 12:49:23 -0400467void TIntermRaw::traverse(TIntermTraverser *it)
468{
469 it->visitRaw(this);
470}