1 //
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 
7 #include "compiler/translator/IntermTraverse.h"
8 
9 #include "compiler/translator/InfoSink.h"
10 #include "compiler/translator/IntermNode_util.h"
11 #include "compiler/translator/SymbolTable.h"
12 
13 namespace sh
14 {
15 
traverse(TIntermTraverser * it)16 void TIntermSymbol::traverse(TIntermTraverser *it)
17 {
18     it->traverseSymbol(this);
19 }
20 
traverse(TIntermTraverser * it)21 void TIntermRaw::traverse(TIntermTraverser *it)
22 {
23     it->traverseRaw(this);
24 }
25 
traverse(TIntermTraverser * it)26 void TIntermConstantUnion::traverse(TIntermTraverser *it)
27 {
28     it->traverseConstantUnion(this);
29 }
30 
traverse(TIntermTraverser * it)31 void TIntermSwizzle::traverse(TIntermTraverser *it)
32 {
33     it->traverseSwizzle(this);
34 }
35 
traverse(TIntermTraverser * it)36 void TIntermBinary::traverse(TIntermTraverser *it)
37 {
38     it->traverseBinary(this);
39 }
40 
traverse(TIntermTraverser * it)41 void TIntermUnary::traverse(TIntermTraverser *it)
42 {
43     it->traverseUnary(this);
44 }
45 
traverse(TIntermTraverser * it)46 void TIntermTernary::traverse(TIntermTraverser *it)
47 {
48     it->traverseTernary(this);
49 }
50 
traverse(TIntermTraverser * it)51 void TIntermIfElse::traverse(TIntermTraverser *it)
52 {
53     it->traverseIfElse(this);
54 }
55 
traverse(TIntermTraverser * it)56 void TIntermSwitch::traverse(TIntermTraverser *it)
57 {
58     it->traverseSwitch(this);
59 }
60 
traverse(TIntermTraverser * it)61 void TIntermCase::traverse(TIntermTraverser *it)
62 {
63     it->traverseCase(this);
64 }
65 
traverse(TIntermTraverser * it)66 void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
67 {
68     it->traverseFunctionDefinition(this);
69 }
70 
traverse(TIntermTraverser * it)71 void TIntermBlock::traverse(TIntermTraverser *it)
72 {
73     it->traverseBlock(this);
74 }
75 
traverse(TIntermTraverser * it)76 void TIntermInvariantDeclaration::traverse(TIntermTraverser *it)
77 {
78     it->traverseInvariantDeclaration(this);
79 }
80 
traverse(TIntermTraverser * it)81 void TIntermDeclaration::traverse(TIntermTraverser *it)
82 {
83     it->traverseDeclaration(this);
84 }
85 
traverse(TIntermTraverser * it)86 void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
87 {
88     it->traverseFunctionPrototype(this);
89 }
90 
traverse(TIntermTraverser * it)91 void TIntermAggregate::traverse(TIntermTraverser *it)
92 {
93     it->traverseAggregate(this);
94 }
95 
traverse(TIntermTraverser * it)96 void TIntermLoop::traverse(TIntermTraverser *it)
97 {
98     it->traverseLoop(this);
99 }
100 
traverse(TIntermTraverser * it)101 void TIntermBranch::traverse(TIntermTraverser *it)
102 {
103     it->traverseBranch(this);
104 }
105 
TIntermTraverser(bool preVisit,bool inVisit,bool postVisit,TSymbolTable * symbolTable)106 TIntermTraverser::TIntermTraverser(bool preVisit,
107                                    bool inVisit,
108                                    bool postVisit,
109                                    TSymbolTable *symbolTable)
110     : preVisit(preVisit),
111       inVisit(inVisit),
112       postVisit(postVisit),
113       mDepth(-1),
114       mMaxDepth(0),
115       mInGlobalScope(true),
116       mSymbolTable(symbolTable)
117 {
118 }
119 
~TIntermTraverser()120 TIntermTraverser::~TIntermTraverser()
121 {
122 }
123 
getParentBlock() const124 const TIntermBlock *TIntermTraverser::getParentBlock() const
125 {
126     if (!mParentBlockStack.empty())
127     {
128         return mParentBlockStack.back().node;
129     }
130     return nullptr;
131 }
132 
pushParentBlock(TIntermBlock * node)133 void TIntermTraverser::pushParentBlock(TIntermBlock *node)
134 {
135     mParentBlockStack.push_back(ParentBlock(node, 0));
136 }
137 
incrementParentBlockPos()138 void TIntermTraverser::incrementParentBlockPos()
139 {
140     ++mParentBlockStack.back().pos;
141 }
142 
popParentBlock()143 void TIntermTraverser::popParentBlock()
144 {
145     ASSERT(!mParentBlockStack.empty());
146     mParentBlockStack.pop_back();
147 }
148 
insertStatementsInParentBlock(const TIntermSequence & insertions)149 void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
150 {
151     TIntermSequence emptyInsertionsAfter;
152     insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
153 }
154 
insertStatementsInParentBlock(const TIntermSequence & insertionsBefore,const TIntermSequence & insertionsAfter)155 void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
156                                                      const TIntermSequence &insertionsAfter)
157 {
158     ASSERT(!mParentBlockStack.empty());
159     ParentBlock &parentBlock = mParentBlockStack.back();
160     if (mPath.back() == parentBlock.node)
161     {
162         ASSERT(mParentBlockStack.size() >= 2u);
163         // The current node is a block node, so the parent block is not the topmost one in the block
164         // stack, but the one below that.
165         parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
166     }
167     NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
168                                    insertionsAfter);
169     mInsertions.push_back(insert);
170 }
171 
insertStatementInParentBlock(TIntermNode * statement)172 void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
173 {
174     TIntermSequence insertions;
175     insertions.push_back(statement);
176     insertStatementsInParentBlock(insertions);
177 }
178 
setInFunctionCallOutParameter(bool inOutParameter)179 void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
180 {
181     mInFunctionCallOutParameter = inOutParameter;
182 }
183 
isInFunctionCallOutParameter() const184 bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
185 {
186     return mInFunctionCallOutParameter;
187 }
188 
189 //
190 // Traverse the intermediate representation tree, and
191 // call a node type specific function for each node.
192 // Done recursively through the member function Traverse().
193 // Node types can be skipped if their function to call is 0,
194 // but their subtree will still be traversed.
195 // Nodes with children can have their whole subtree skipped
196 // if preVisit is turned on and the type specific function
197 // returns false.
198 //
199 
200 //
201 // Traversal functions for terminals are straighforward....
202 //
traverseSymbol(TIntermSymbol * node)203 void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
204 {
205     ScopedNodeInTraversalPath addToPath(this, node);
206     visitSymbol(node);
207 }
208 
traverseConstantUnion(TIntermConstantUnion * node)209 void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
210 {
211     ScopedNodeInTraversalPath addToPath(this, node);
212     visitConstantUnion(node);
213 }
214 
traverseSwizzle(TIntermSwizzle * node)215 void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
216 {
217     ScopedNodeInTraversalPath addToPath(this, node);
218 
219     bool visit = true;
220 
221     if (preVisit)
222         visit = visitSwizzle(PreVisit, node);
223 
224     if (visit)
225     {
226         node->getOperand()->traverse(this);
227     }
228 
229     if (visit && postVisit)
230         visitSwizzle(PostVisit, node);
231 }
232 
233 //
234 // Traverse a binary node.
235 //
traverseBinary(TIntermBinary * node)236 void TIntermTraverser::traverseBinary(TIntermBinary *node)
237 {
238     ScopedNodeInTraversalPath addToPath(this, node);
239 
240     bool visit = true;
241 
242     //
243     // visit the node before children if pre-visiting.
244     //
245     if (preVisit)
246         visit = visitBinary(PreVisit, node);
247 
248     //
249     // Visit the children, in the right order.
250     //
251     if (visit)
252     {
253         if (node->getLeft())
254             node->getLeft()->traverse(this);
255 
256         if (inVisit)
257             visit = visitBinary(InVisit, node);
258 
259         if (visit && node->getRight())
260             node->getRight()->traverse(this);
261     }
262 
263     //
264     // Visit the node after the children, if requested and the traversal
265     // hasn't been cancelled yet.
266     //
267     if (visit && postVisit)
268         visitBinary(PostVisit, node);
269 }
270 
traverseBinary(TIntermBinary * node)271 void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
272 {
273     ScopedNodeInTraversalPath addToPath(this, node);
274 
275     bool visit = true;
276 
277     //
278     // visit the node before children if pre-visiting.
279     //
280     if (preVisit)
281         visit = visitBinary(PreVisit, node);
282 
283     //
284     // Visit the children, in the right order.
285     //
286     if (visit)
287     {
288         // Some binary operations like indexing can be inside an expression which must be an
289         // l-value.
290         bool parentOperatorRequiresLValue     = operatorRequiresLValue();
291         bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
292         if (node->isAssignment())
293         {
294             ASSERT(!isLValueRequiredHere());
295             setOperatorRequiresLValue(true);
296         }
297 
298         if (node->getLeft())
299             node->getLeft()->traverse(this);
300 
301         if (inVisit)
302             visit = visitBinary(InVisit, node);
303 
304         if (node->isAssignment())
305             setOperatorRequiresLValue(false);
306 
307         // Index is not required to be an l-value even when the surrounding expression is required
308         // to be an l-value.
309         TOperator op = node->getOp();
310         if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
311             op == EOpIndexDirectStruct || op == EOpIndexIndirect)
312         {
313             setOperatorRequiresLValue(false);
314             setInFunctionCallOutParameter(false);
315         }
316 
317         if (visit && node->getRight())
318             node->getRight()->traverse(this);
319 
320         setOperatorRequiresLValue(parentOperatorRequiresLValue);
321         setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
322     }
323 
324     //
325     // Visit the node after the children, if requested and the traversal
326     // hasn't been cancelled yet.
327     //
328     if (visit && postVisit)
329         visitBinary(PostVisit, node);
330 }
331 
332 //
333 // Traverse a unary node.  Same comments in binary node apply here.
334 //
traverseUnary(TIntermUnary * node)335 void TIntermTraverser::traverseUnary(TIntermUnary *node)
336 {
337     ScopedNodeInTraversalPath addToPath(this, node);
338 
339     bool visit = true;
340 
341     if (preVisit)
342         visit = visitUnary(PreVisit, node);
343 
344     if (visit)
345     {
346         node->getOperand()->traverse(this);
347     }
348 
349     if (visit && postVisit)
350         visitUnary(PostVisit, node);
351 }
352 
traverseUnary(TIntermUnary * node)353 void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
354 {
355     ScopedNodeInTraversalPath addToPath(this, node);
356 
357     bool visit = true;
358 
359     if (preVisit)
360         visit = visitUnary(PreVisit, node);
361 
362     if (visit)
363     {
364         ASSERT(!operatorRequiresLValue());
365         switch (node->getOp())
366         {
367             case EOpPostIncrement:
368             case EOpPostDecrement:
369             case EOpPreIncrement:
370             case EOpPreDecrement:
371                 setOperatorRequiresLValue(true);
372                 break;
373             default:
374                 break;
375         }
376 
377         node->getOperand()->traverse(this);
378 
379         setOperatorRequiresLValue(false);
380     }
381 
382     if (visit && postVisit)
383         visitUnary(PostVisit, node);
384 }
385 
386 // Traverse a function definition node.
traverseFunctionDefinition(TIntermFunctionDefinition * node)387 void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
388 {
389     ScopedNodeInTraversalPath addToPath(this, node);
390 
391     bool visit = true;
392 
393     if (preVisit)
394         visit = visitFunctionDefinition(PreVisit, node);
395 
396     if (visit)
397     {
398         mInGlobalScope = false;
399 
400         node->getFunctionPrototype()->traverse(this);
401         if (inVisit)
402             visit = visitFunctionDefinition(InVisit, node);
403         node->getBody()->traverse(this);
404 
405         mInGlobalScope = true;
406     }
407 
408     if (visit && postVisit)
409         visitFunctionDefinition(PostVisit, node);
410 }
411 
412 // Traverse a block node.
traverseBlock(TIntermBlock * node)413 void TIntermTraverser::traverseBlock(TIntermBlock *node)
414 {
415     ScopedNodeInTraversalPath addToPath(this, node);
416     pushParentBlock(node);
417 
418     bool visit = true;
419 
420     TIntermSequence *sequence = node->getSequence();
421 
422     if (preVisit)
423         visit = visitBlock(PreVisit, node);
424 
425     if (visit)
426     {
427         for (auto *child : *sequence)
428         {
429             child->traverse(this);
430             if (visit && inVisit)
431             {
432                 if (child != sequence->back())
433                     visit = visitBlock(InVisit, node);
434             }
435 
436             incrementParentBlockPos();
437         }
438     }
439 
440     if (visit && postVisit)
441         visitBlock(PostVisit, node);
442 
443     popParentBlock();
444 }
445 
traverseInvariantDeclaration(TIntermInvariantDeclaration * node)446 void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
447 {
448     ScopedNodeInTraversalPath addToPath(this, node);
449 
450     bool visit = true;
451 
452     if (preVisit)
453     {
454         visit = visitInvariantDeclaration(PreVisit, node);
455     }
456 
457     if (visit)
458     {
459         node->getSymbol()->traverse(this);
460         if (postVisit)
461         {
462             visitInvariantDeclaration(PostVisit, node);
463         }
464     }
465 }
466 
467 // Traverse a declaration node.
traverseDeclaration(TIntermDeclaration * node)468 void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
469 {
470     ScopedNodeInTraversalPath addToPath(this, node);
471 
472     bool visit = true;
473 
474     TIntermSequence *sequence = node->getSequence();
475 
476     if (preVisit)
477         visit = visitDeclaration(PreVisit, node);
478 
479     if (visit)
480     {
481         for (auto *child : *sequence)
482         {
483             child->traverse(this);
484             if (visit && inVisit)
485             {
486                 if (child != sequence->back())
487                     visit = visitDeclaration(InVisit, node);
488             }
489         }
490     }
491 
492     if (visit && postVisit)
493         visitDeclaration(PostVisit, node);
494 }
495 
traverseFunctionPrototype(TIntermFunctionPrototype * node)496 void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
497 {
498     ScopedNodeInTraversalPath addToPath(this, node);
499 
500     bool visit = true;
501 
502     TIntermSequence *sequence = node->getSequence();
503 
504     if (preVisit)
505         visit = visitFunctionPrototype(PreVisit, node);
506 
507     if (visit)
508     {
509         for (auto *child : *sequence)
510         {
511             child->traverse(this);
512             if (visit && inVisit)
513             {
514                 if (child != sequence->back())
515                     visit = visitFunctionPrototype(InVisit, node);
516             }
517         }
518     }
519 
520     if (visit && postVisit)
521         visitFunctionPrototype(PostVisit, node);
522 }
523 
524 // Traverse an aggregate node.  Same comments in binary node apply here.
traverseAggregate(TIntermAggregate * node)525 void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
526 {
527     ScopedNodeInTraversalPath addToPath(this, node);
528 
529     bool visit = true;
530 
531     TIntermSequence *sequence = node->getSequence();
532 
533     if (preVisit)
534         visit = visitAggregate(PreVisit, node);
535 
536     if (visit)
537     {
538         for (auto *child : *sequence)
539         {
540             child->traverse(this);
541             if (visit && inVisit)
542             {
543                 if (child != sequence->back())
544                     visit = visitAggregate(InVisit, node);
545             }
546         }
547     }
548 
549     if (visit && postVisit)
550         visitAggregate(PostVisit, node);
551 }
552 
CompareInsertion(const NodeInsertMultipleEntry & a,const NodeInsertMultipleEntry & b)553 bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
554                                         const NodeInsertMultipleEntry &b)
555 {
556     if (a.parent != b.parent)
557     {
558         return a.parent > b.parent;
559     }
560     return a.position > b.position;
561 }
562 
updateTree()563 void TIntermTraverser::updateTree()
564 {
565     // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
566     // the same parent node are handled correctly.
567     std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
568     for (size_t ii = 0; ii < mInsertions.size(); ++ii)
569     {
570         // We can't know here what the intended ordering of two insertions to the same position is,
571         // so it is not supported.
572         ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
573                mInsertions[ii].parent != mInsertions[ii - 1].parent);
574         const NodeInsertMultipleEntry &insertion = mInsertions[ii];
575         ASSERT(insertion.parent);
576         if (!insertion.insertionsAfter.empty())
577         {
578             bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
579                                                                insertion.insertionsAfter);
580             ASSERT(inserted);
581         }
582         if (!insertion.insertionsBefore.empty())
583         {
584             bool inserted =
585                 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
586             ASSERT(inserted);
587         }
588     }
589     for (size_t ii = 0; ii < mReplacements.size(); ++ii)
590     {
591         const NodeUpdateEntry &replacement = mReplacements[ii];
592         ASSERT(replacement.parent);
593         bool replaced =
594             replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
595         ASSERT(replaced);
596 
597         if (!replacement.originalBecomesChildOfReplacement)
598         {
599             // In AST traversing, a parent is visited before its children.
600             // After we replace a node, if its immediate child is to
601             // be replaced, we need to make sure we don't update the replaced
602             // node; instead, we update the replacement node.
603             for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
604             {
605                 NodeUpdateEntry &replacement2 = mReplacements[jj];
606                 if (replacement2.parent == replacement.original)
607                     replacement2.parent = replacement.replacement;
608             }
609         }
610     }
611     for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
612     {
613         const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
614         ASSERT(replacement.parent);
615         bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
616                                                                          replacement.replacements);
617         ASSERT(replaced);
618     }
619 
620     clearReplacementQueue();
621 }
622 
clearReplacementQueue()623 void TIntermTraverser::clearReplacementQueue()
624 {
625     mReplacements.clear();
626     mMultiReplacements.clear();
627     mInsertions.clear();
628 }
629 
queueReplacement(TIntermNode * replacement,OriginalNode originalStatus)630 void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
631 {
632     queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
633 }
634 
queueReplacementWithParent(TIntermNode * parent,TIntermNode * original,TIntermNode * replacement,OriginalNode originalStatus)635 void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
636                                                   TIntermNode *original,
637                                                   TIntermNode *replacement,
638                                                   OriginalNode originalStatus)
639 {
640     bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
641     mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
642 }
643 
TLValueTrackingTraverser(bool preVisit,bool inVisit,bool postVisit,TSymbolTable * symbolTable)644 TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
645                                                    bool inVisit,
646                                                    bool postVisit,
647                                                    TSymbolTable *symbolTable)
648     : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
649       mOperatorRequiresLValue(false),
650       mInFunctionCallOutParameter(false)
651 {
652     ASSERT(symbolTable);
653 }
654 
traverseAggregate(TIntermAggregate * node)655 void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
656 {
657     ScopedNodeInTraversalPath addToPath(this, node);
658 
659     bool visit = true;
660 
661     TIntermSequence *sequence = node->getSequence();
662 
663     if (preVisit)
664         visit = visitAggregate(PreVisit, node);
665 
666     if (visit)
667     {
668         size_t paramIndex = 0u;
669         for (auto *child : *sequence)
670         {
671             if (node->getFunction())
672             {
673                 // Both built-ins and user defined functions should have the function symbol set.
674                 ASSERT(paramIndex < node->getFunction()->getParamCount());
675                 TQualifier qualifier =
676                     node->getFunction()->getParam(paramIndex).type->getQualifier();
677                 setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
678                 ++paramIndex;
679             }
680             else
681             {
682                 ASSERT(node->isConstructor());
683             }
684 
685             child->traverse(this);
686             if (visit && inVisit)
687             {
688                 if (child != sequence->back())
689                     visit = visitAggregate(InVisit, node);
690             }
691         }
692         setInFunctionCallOutParameter(false);
693     }
694 
695     if (visit && postVisit)
696         visitAggregate(PostVisit, node);
697 }
698 
699 //
700 // Traverse a ternary node.  Same comments in binary node apply here.
701 //
traverseTernary(TIntermTernary * node)702 void TIntermTraverser::traverseTernary(TIntermTernary *node)
703 {
704     ScopedNodeInTraversalPath addToPath(this, node);
705 
706     bool visit = true;
707 
708     if (preVisit)
709         visit = visitTernary(PreVisit, node);
710 
711     if (visit)
712     {
713         node->getCondition()->traverse(this);
714         if (node->getTrueExpression())
715             node->getTrueExpression()->traverse(this);
716         if (node->getFalseExpression())
717             node->getFalseExpression()->traverse(this);
718     }
719 
720     if (visit && postVisit)
721         visitTernary(PostVisit, node);
722 }
723 
724 // Traverse an if-else node.  Same comments in binary node apply here.
traverseIfElse(TIntermIfElse * node)725 void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
726 {
727     ScopedNodeInTraversalPath addToPath(this, node);
728 
729     bool visit = true;
730 
731     if (preVisit)
732         visit = visitIfElse(PreVisit, node);
733 
734     if (visit)
735     {
736         node->getCondition()->traverse(this);
737         if (node->getTrueBlock())
738             node->getTrueBlock()->traverse(this);
739         if (node->getFalseBlock())
740             node->getFalseBlock()->traverse(this);
741     }
742 
743     if (visit && postVisit)
744         visitIfElse(PostVisit, node);
745 }
746 
747 //
748 // Traverse a switch node.  Same comments in binary node apply here.
749 //
traverseSwitch(TIntermSwitch * node)750 void TIntermTraverser::traverseSwitch(TIntermSwitch *node)
751 {
752     ScopedNodeInTraversalPath addToPath(this, node);
753 
754     bool visit = true;
755 
756     if (preVisit)
757         visit = visitSwitch(PreVisit, node);
758 
759     if (visit)
760     {
761         node->getInit()->traverse(this);
762         if (inVisit)
763             visit = visitSwitch(InVisit, node);
764         if (visit && node->getStatementList())
765             node->getStatementList()->traverse(this);
766     }
767 
768     if (visit && postVisit)
769         visitSwitch(PostVisit, node);
770 }
771 
772 //
773 // Traverse a case node.  Same comments in binary node apply here.
774 //
traverseCase(TIntermCase * node)775 void TIntermTraverser::traverseCase(TIntermCase *node)
776 {
777     ScopedNodeInTraversalPath addToPath(this, node);
778 
779     bool visit = true;
780 
781     if (preVisit)
782         visit = visitCase(PreVisit, node);
783 
784     if (visit && node->getCondition())
785     {
786         node->getCondition()->traverse(this);
787     }
788 
789     if (visit && postVisit)
790         visitCase(PostVisit, node);
791 }
792 
793 //
794 // Traverse a loop node.  Same comments in binary node apply here.
795 //
traverseLoop(TIntermLoop * node)796 void TIntermTraverser::traverseLoop(TIntermLoop *node)
797 {
798     ScopedNodeInTraversalPath addToPath(this, node);
799 
800     bool visit = true;
801 
802     if (preVisit)
803         visit = visitLoop(PreVisit, node);
804 
805     if (visit)
806     {
807         if (node->getInit())
808             node->getInit()->traverse(this);
809 
810         if (node->getCondition())
811             node->getCondition()->traverse(this);
812 
813         if (node->getBody())
814             node->getBody()->traverse(this);
815 
816         if (node->getExpression())
817             node->getExpression()->traverse(this);
818     }
819 
820     if (visit && postVisit)
821         visitLoop(PostVisit, node);
822 }
823 
824 //
825 // Traverse a branch node.  Same comments in binary node apply here.
826 //
traverseBranch(TIntermBranch * node)827 void TIntermTraverser::traverseBranch(TIntermBranch *node)
828 {
829     ScopedNodeInTraversalPath addToPath(this, node);
830 
831     bool visit = true;
832 
833     if (preVisit)
834         visit = visitBranch(PreVisit, node);
835 
836     if (visit && node->getExpression())
837     {
838         node->getExpression()->traverse(this);
839     }
840 
841     if (visit && postVisit)
842         visitBranch(PostVisit, node);
843 }
844 
traverseRaw(TIntermRaw * node)845 void TIntermTraverser::traverseRaw(TIntermRaw *node)
846 {
847     ScopedNodeInTraversalPath addToPath(this, node);
848     visitRaw(node);
849 }
850 
851 }  // namespace sh
852