1 //
2 // Copyright 2002 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
7 #include "compiler/translator/tree_util/IntermTraverse.h"
8
9 #include "compiler/translator/InfoSink.h"
10 #include "compiler/translator/SymbolTable.h"
11 #include "compiler/translator/tree_util/IntermNode_util.h"
12
13 namespace sh
14 {
15
16 // Traverse the intermediate representation tree, and call a node type specific visit function for
17 // each node. Traversal is done recursively through the node member function traverse(). Nodes with
18 // children can have their whole subtree skipped if preVisit is turned on and the type specific
19 // function returns false.
20 template <typename T>
traverse(T * node)21 void TIntermTraverser::traverse(T *node)
22 {
23 ScopedNodeInTraversalPath addToPath(this, node);
24 if (!addToPath.isWithinDepthLimit())
25 return;
26
27 bool visit = true;
28
29 // Visit the node before children if pre-visiting.
30 if (preVisit)
31 visit = node->visit(PreVisit, this);
32
33 if (visit)
34 {
35 size_t childIndex = 0;
36 size_t childCount = node->getChildCount();
37
38 while (childIndex < childCount && visit)
39 {
40 node->getChildNode(childIndex)->traverse(this);
41 if (inVisit && childIndex != childCount - 1)
42 {
43 visit = node->visit(InVisit, this);
44 }
45 ++childIndex;
46 }
47
48 if (visit && postVisit)
49 node->visit(PostVisit, this);
50 }
51 }
52
53 // Instantiate template for RewriteAtomicFunctionExpressions, in case this gets inlined thus not
54 // exported from the TU.
55 template void TIntermTraverser::traverse(TIntermNode *);
56
traverse(TIntermTraverser * it)57 void TIntermNode::traverse(TIntermTraverser *it)
58 {
59 it->traverse(this);
60 }
61
traverse(TIntermTraverser * it)62 void TIntermSymbol::traverse(TIntermTraverser *it)
63 {
64 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
65 it->visitSymbol(this);
66 }
67
traverse(TIntermTraverser * it)68 void TIntermConstantUnion::traverse(TIntermTraverser *it)
69 {
70 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
71 it->visitConstantUnion(this);
72 }
73
traverse(TIntermTraverser * it)74 void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
75 {
76 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this);
77 it->visitFunctionPrototype(this);
78 }
79
traverse(TIntermTraverser * it)80 void TIntermBinary::traverse(TIntermTraverser *it)
81 {
82 it->traverseBinary(this);
83 }
84
traverse(TIntermTraverser * it)85 void TIntermUnary::traverse(TIntermTraverser *it)
86 {
87 it->traverseUnary(this);
88 }
89
traverse(TIntermTraverser * it)90 void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
91 {
92 it->traverseFunctionDefinition(this);
93 }
94
traverse(TIntermTraverser * it)95 void TIntermBlock::traverse(TIntermTraverser *it)
96 {
97 it->traverseBlock(this);
98 }
99
traverse(TIntermTraverser * it)100 void TIntermAggregate::traverse(TIntermTraverser *it)
101 {
102 it->traverseAggregate(this);
103 }
104
traverse(TIntermTraverser * it)105 void TIntermLoop::traverse(TIntermTraverser *it)
106 {
107 it->traverseLoop(this);
108 }
109
traverse(TIntermTraverser * it)110 void TIntermPreprocessorDirective::traverse(TIntermTraverser *it)
111 {
112 it->visitPreprocessorDirective(this);
113 }
114
visit(Visit visit,TIntermTraverser * it)115 bool TIntermSymbol::visit(Visit visit, TIntermTraverser *it)
116 {
117 it->visitSymbol(this);
118 return false;
119 }
120
visit(Visit visit,TIntermTraverser * it)121 bool TIntermConstantUnion::visit(Visit visit, TIntermTraverser *it)
122 {
123 it->visitConstantUnion(this);
124 return false;
125 }
126
visit(Visit visit,TIntermTraverser * it)127 bool TIntermFunctionPrototype::visit(Visit visit, TIntermTraverser *it)
128 {
129 it->visitFunctionPrototype(this);
130 return false;
131 }
132
visit(Visit visit,TIntermTraverser * it)133 bool TIntermFunctionDefinition::visit(Visit visit, TIntermTraverser *it)
134 {
135 return it->visitFunctionDefinition(visit, this);
136 }
137
visit(Visit visit,TIntermTraverser * it)138 bool TIntermUnary::visit(Visit visit, TIntermTraverser *it)
139 {
140 return it->visitUnary(visit, this);
141 }
142
visit(Visit visit,TIntermTraverser * it)143 bool TIntermSwizzle::visit(Visit visit, TIntermTraverser *it)
144 {
145 return it->visitSwizzle(visit, this);
146 }
147
visit(Visit visit,TIntermTraverser * it)148 bool TIntermBinary::visit(Visit visit, TIntermTraverser *it)
149 {
150 return it->visitBinary(visit, this);
151 }
152
visit(Visit visit,TIntermTraverser * it)153 bool TIntermTernary::visit(Visit visit, TIntermTraverser *it)
154 {
155 return it->visitTernary(visit, this);
156 }
157
visit(Visit visit,TIntermTraverser * it)158 bool TIntermAggregate::visit(Visit visit, TIntermTraverser *it)
159 {
160 return it->visitAggregate(visit, this);
161 }
162
visit(Visit visit,TIntermTraverser * it)163 bool TIntermDeclaration::visit(Visit visit, TIntermTraverser *it)
164 {
165 return it->visitDeclaration(visit, this);
166 }
167
visit(Visit visit,TIntermTraverser * it)168 bool TIntermInvariantDeclaration::visit(Visit visit, TIntermTraverser *it)
169 {
170 return it->visitInvariantDeclaration(visit, this);
171 }
172
visit(Visit visit,TIntermTraverser * it)173 bool TIntermBlock::visit(Visit visit, TIntermTraverser *it)
174 {
175 return it->visitBlock(visit, this);
176 }
177
visit(Visit visit,TIntermTraverser * it)178 bool TIntermIfElse::visit(Visit visit, TIntermTraverser *it)
179 {
180 return it->visitIfElse(visit, this);
181 }
182
visit(Visit visit,TIntermTraverser * it)183 bool TIntermLoop::visit(Visit visit, TIntermTraverser *it)
184 {
185 return it->visitLoop(visit, this);
186 }
187
visit(Visit visit,TIntermTraverser * it)188 bool TIntermBranch::visit(Visit visit, TIntermTraverser *it)
189 {
190 return it->visitBranch(visit, this);
191 }
192
visit(Visit visit,TIntermTraverser * it)193 bool TIntermSwitch::visit(Visit visit, TIntermTraverser *it)
194 {
195 return it->visitSwitch(visit, this);
196 }
197
visit(Visit visit,TIntermTraverser * it)198 bool TIntermCase::visit(Visit visit, TIntermTraverser *it)
199 {
200 return it->visitCase(visit, this);
201 }
202
visit(Visit visit,TIntermTraverser * it)203 bool TIntermPreprocessorDirective::visit(Visit visit, TIntermTraverser *it)
204 {
205 it->visitPreprocessorDirective(this);
206 return false;
207 }
208
TIntermTraverser(bool preVisit,bool inVisit,bool postVisit,TSymbolTable * symbolTable)209 TIntermTraverser::TIntermTraverser(bool preVisit,
210 bool inVisit,
211 bool postVisit,
212 TSymbolTable *symbolTable)
213 : preVisit(preVisit),
214 inVisit(inVisit),
215 postVisit(postVisit),
216 mMaxDepth(0),
217 mMaxAllowedDepth(std::numeric_limits<int>::max()),
218 mInGlobalScope(true),
219 mSymbolTable(symbolTable)
220 {
221 // Only enabling inVisit is not supported.
222 ASSERT(!(inVisit && !preVisit && !postVisit));
223 }
224
~TIntermTraverser()225 TIntermTraverser::~TIntermTraverser() {}
226
setMaxAllowedDepth(int depth)227 void TIntermTraverser::setMaxAllowedDepth(int depth)
228 {
229 mMaxAllowedDepth = depth;
230 }
231
getParentBlock() const232 const TIntermBlock *TIntermTraverser::getParentBlock() const
233 {
234 if (!mParentBlockStack.empty())
235 {
236 return mParentBlockStack.back().node;
237 }
238 return nullptr;
239 }
240
pushParentBlock(TIntermBlock * node)241 void TIntermTraverser::pushParentBlock(TIntermBlock *node)
242 {
243 mParentBlockStack.push_back(ParentBlock(node, 0));
244 }
245
incrementParentBlockPos()246 void TIntermTraverser::incrementParentBlockPos()
247 {
248 ++mParentBlockStack.back().pos;
249 }
250
popParentBlock()251 void TIntermTraverser::popParentBlock()
252 {
253 ASSERT(!mParentBlockStack.empty());
254 mParentBlockStack.pop_back();
255 }
256
insertStatementsInParentBlock(const TIntermSequence & insertions)257 void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
258 {
259 TIntermSequence emptyInsertionsAfter;
260 insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
261 }
262
insertStatementsInParentBlock(const TIntermSequence & insertionsBefore,const TIntermSequence & insertionsAfter)263 void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
264 const TIntermSequence &insertionsAfter)
265 {
266 ASSERT(!mParentBlockStack.empty());
267 ParentBlock &parentBlock = mParentBlockStack.back();
268 if (mPath.back() == parentBlock.node)
269 {
270 ASSERT(mParentBlockStack.size() >= 2u);
271 // The current node is a block node, so the parent block is not the topmost one in the block
272 // stack, but the one below that.
273 parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
274 }
275 NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
276 insertionsAfter);
277 mInsertions.push_back(insert);
278 }
279
insertStatementInParentBlock(TIntermNode * statement)280 void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
281 {
282 TIntermSequence insertions;
283 insertions.push_back(statement);
284 insertStatementsInParentBlock(insertions);
285 }
286
insertStatementsInBlockAtPosition(TIntermBlock * parent,size_t position,const TIntermSequence & insertionsBefore,const TIntermSequence & insertionsAfter)287 void TIntermTraverser::insertStatementsInBlockAtPosition(TIntermBlock *parent,
288 size_t position,
289 const TIntermSequence &insertionsBefore,
290 const TIntermSequence &insertionsAfter)
291 {
292 ASSERT(parent);
293 ASSERT(position >= 0);
294 ASSERT(position < parent->getChildCount());
295
296 mInsertions.emplace_back(parent, position, insertionsBefore, insertionsAfter);
297 }
298
setInFunctionCallOutParameter(bool inOutParameter)299 void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
300 {
301 mInFunctionCallOutParameter = inOutParameter;
302 }
303
isInFunctionCallOutParameter() const304 bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
305 {
306 return mInFunctionCallOutParameter;
307 }
308
traverseBinary(TIntermBinary * node)309 void TIntermTraverser::traverseBinary(TIntermBinary *node)
310 {
311 traverse(node);
312 }
313
traverseBinary(TIntermBinary * node)314 void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
315 {
316 ScopedNodeInTraversalPath addToPath(this, node);
317 if (!addToPath.isWithinDepthLimit())
318 return;
319
320 bool visit = true;
321
322 // visit the node before children if pre-visiting.
323 if (preVisit)
324 visit = node->visit(PreVisit, this);
325
326 // Visit the children, in the right order.
327 if (visit)
328 {
329 if (node->isAssignment())
330 {
331 ASSERT(!isLValueRequiredHere());
332 setOperatorRequiresLValue(true);
333 }
334
335 node->getLeft()->traverse(this);
336
337 if (node->isAssignment())
338 setOperatorRequiresLValue(false);
339
340 if (inVisit)
341 visit = node->visit(InVisit, this);
342
343 if (visit)
344 {
345 // Some binary operations like indexing can be inside an expression which must be an
346 // l-value.
347 bool parentOperatorRequiresLValue = operatorRequiresLValue();
348 bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
349
350 // Index is not required to be an l-value even when the surrounding expression is
351 // required to be an l-value.
352 TOperator op = node->getOp();
353 if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
354 op == EOpIndexDirectStruct || op == EOpIndexIndirect)
355 {
356 setOperatorRequiresLValue(false);
357 setInFunctionCallOutParameter(false);
358 }
359
360 node->getRight()->traverse(this);
361
362 setOperatorRequiresLValue(parentOperatorRequiresLValue);
363 setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
364
365 // Visit the node after the children, if requested and the traversal
366 // hasn't been cancelled yet.
367 if (postVisit)
368 visit = node->visit(PostVisit, this);
369 }
370 }
371 }
372
traverseUnary(TIntermUnary * node)373 void TIntermTraverser::traverseUnary(TIntermUnary *node)
374 {
375 traverse(node);
376 }
377
traverseUnary(TIntermUnary * node)378 void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
379 {
380 ScopedNodeInTraversalPath addToPath(this, node);
381 if (!addToPath.isWithinDepthLimit())
382 return;
383
384 bool visit = true;
385
386 if (preVisit)
387 visit = node->visit(PreVisit, this);
388
389 if (visit)
390 {
391 ASSERT(!operatorRequiresLValue());
392 switch (node->getOp())
393 {
394 case EOpPostIncrement:
395 case EOpPostDecrement:
396 case EOpPreIncrement:
397 case EOpPreDecrement:
398 setOperatorRequiresLValue(true);
399 break;
400 default:
401 break;
402 }
403
404 node->getOperand()->traverse(this);
405
406 setOperatorRequiresLValue(false);
407
408 if (postVisit)
409 visit = node->visit(PostVisit, this);
410 }
411 }
412
413 // Traverse a function definition node. This keeps track of global scope.
traverseFunctionDefinition(TIntermFunctionDefinition * node)414 void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
415 {
416 ScopedNodeInTraversalPath addToPath(this, node);
417 if (!addToPath.isWithinDepthLimit())
418 return;
419
420 bool visit = true;
421
422 if (preVisit)
423 visit = node->visit(PreVisit, this);
424
425 if (visit)
426 {
427 node->getFunctionPrototype()->traverse(this);
428 if (inVisit)
429 visit = node->visit(InVisit, this);
430 if (visit)
431 {
432 mInGlobalScope = false;
433 node->getBody()->traverse(this);
434 mInGlobalScope = true;
435 if (postVisit)
436 visit = node->visit(PostVisit, this);
437 }
438 }
439 }
440
441 // Traverse a block node. This keeps track of the position of traversed child nodes within the block
442 // so that nodes may be inserted before or after them.
traverseBlock(TIntermBlock * node)443 void TIntermTraverser::traverseBlock(TIntermBlock *node)
444 {
445 ScopedNodeInTraversalPath addToPath(this, node);
446 if (!addToPath.isWithinDepthLimit())
447 return;
448
449 pushParentBlock(node);
450
451 bool visit = true;
452
453 TIntermSequence *sequence = node->getSequence();
454
455 if (preVisit)
456 visit = node->visit(PreVisit, this);
457
458 if (visit)
459 {
460 for (auto *child : *sequence)
461 {
462 if (visit)
463 {
464 child->traverse(this);
465 if (inVisit)
466 {
467 if (child != sequence->back())
468 visit = node->visit(InVisit, this);
469 }
470
471 incrementParentBlockPos();
472 }
473 }
474
475 if (visit && postVisit)
476 visit = node->visit(PostVisit, this);
477 }
478
479 popParentBlock();
480 }
481
traverseAggregate(TIntermAggregate * node)482 void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
483 {
484 traverse(node);
485 }
486
CompareInsertion(const NodeInsertMultipleEntry & a,const NodeInsertMultipleEntry & b)487 bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
488 const NodeInsertMultipleEntry &b)
489 {
490 if (a.parent != b.parent)
491 {
492 return a.parent < b.parent;
493 }
494 return a.position < b.position;
495 }
496
updateTree()497 void TIntermTraverser::updateTree()
498 {
499 // Sort the insertions so that insertion position is increasing and same position insertions are
500 // not reordered. The insertions are processed in reverse order so that multiple insertions to
501 // the same parent node are handled correctly.
502 std::stable_sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
503 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
504 {
505 // If two insertions are to the same position, insert them in the order they were specified.
506 // The std::stable_sort call above will automatically guarantee this.
507 const NodeInsertMultipleEntry &insertion = mInsertions[mInsertions.size() - ii - 1];
508 ASSERT(insertion.parent);
509 if (!insertion.insertionsAfter.empty())
510 {
511 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
512 insertion.insertionsAfter);
513 ASSERT(inserted);
514 }
515 if (!insertion.insertionsBefore.empty())
516 {
517 bool inserted =
518 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
519 ASSERT(inserted);
520 }
521 }
522 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
523 {
524 const NodeUpdateEntry &replacement = mReplacements[ii];
525 ASSERT(replacement.parent);
526 bool replaced =
527 replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
528 ASSERT(replaced);
529
530 if (!replacement.originalBecomesChildOfReplacement)
531 {
532 // In AST traversing, a parent is visited before its children.
533 // After we replace a node, if its immediate child is to
534 // be replaced, we need to make sure we don't update the replaced
535 // node; instead, we update the replacement node.
536 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
537 {
538 NodeUpdateEntry &replacement2 = mReplacements[jj];
539 if (replacement2.parent == replacement.original)
540 replacement2.parent = replacement.replacement;
541 }
542 }
543 }
544 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
545 {
546 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
547 ASSERT(replacement.parent);
548 bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
549 replacement.replacements);
550 ASSERT(replaced);
551 }
552
553 clearReplacementQueue();
554 }
555
clearReplacementQueue()556 void TIntermTraverser::clearReplacementQueue()
557 {
558 mReplacements.clear();
559 mMultiReplacements.clear();
560 mInsertions.clear();
561 }
562
queueReplacement(TIntermNode * replacement,OriginalNode originalStatus)563 void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
564 {
565 queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
566 }
567
queueReplacementWithParent(TIntermNode * parent,TIntermNode * original,TIntermNode * replacement,OriginalNode originalStatus)568 void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
569 TIntermNode *original,
570 TIntermNode *replacement,
571 OriginalNode originalStatus)
572 {
573 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
574 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
575 }
576
TLValueTrackingTraverser(bool preVisit,bool inVisit,bool postVisit,TSymbolTable * symbolTable)577 TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
578 bool inVisit,
579 bool postVisit,
580 TSymbolTable *symbolTable)
581 : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
582 mOperatorRequiresLValue(false),
583 mInFunctionCallOutParameter(false)
584 {
585 ASSERT(symbolTable);
586 }
587
traverseAggregate(TIntermAggregate * node)588 void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
589 {
590 ScopedNodeInTraversalPath addToPath(this, node);
591 if (!addToPath.isWithinDepthLimit())
592 return;
593
594 bool visit = true;
595
596 TIntermSequence *sequence = node->getSequence();
597
598 if (preVisit)
599 visit = node->visit(PreVisit, this);
600
601 if (visit)
602 {
603 size_t paramIndex = 0u;
604 for (auto *child : *sequence)
605 {
606 if (visit)
607 {
608 if (node->getFunction())
609 {
610 // Both built-ins and user defined functions should have the function symbol
611 // set.
612 ASSERT(paramIndex < node->getFunction()->getParamCount());
613 TQualifier qualifier =
614 node->getFunction()->getParam(paramIndex)->getType().getQualifier();
615 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
616 ++paramIndex;
617 }
618 else
619 {
620 ASSERT(node->isConstructor());
621 }
622 child->traverse(this);
623 if (inVisit)
624 {
625 if (child != sequence->back())
626 visit = node->visit(InVisit, this);
627 }
628 }
629 }
630 setInFunctionCallOutParameter(false);
631
632 if (visit && postVisit)
633 visit = node->visit(PostVisit, this);
634 }
635 }
636
traverseLoop(TIntermLoop * node)637 void TIntermTraverser::traverseLoop(TIntermLoop *node)
638 {
639 traverse(node);
640 }
641 } // namespace sh
642