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