• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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