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