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