IntermTraverse.cpp (21320B)
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> 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 62 void TIntermNode::traverse(TIntermTraverser *it) 63 { 64 it->traverse(this); 65 } 66 67 void TIntermSymbol::traverse(TIntermTraverser *it) 68 { 69 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); 70 it->visitSymbol(this); 71 } 72 73 void TIntermConstantUnion::traverse(TIntermTraverser *it) 74 { 75 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); 76 it->visitConstantUnion(this); 77 } 78 79 void TIntermFunctionPrototype::traverse(TIntermTraverser *it) 80 { 81 TIntermTraverser::ScopedNodeInTraversalPath addToPath(it, this); 82 it->visitFunctionPrototype(this); 83 } 84 85 void TIntermBinary::traverse(TIntermTraverser *it) 86 { 87 it->traverseBinary(this); 88 } 89 90 void TIntermUnary::traverse(TIntermTraverser *it) 91 { 92 it->traverseUnary(this); 93 } 94 95 void TIntermFunctionDefinition::traverse(TIntermTraverser *it) 96 { 97 it->traverseFunctionDefinition(this); 98 } 99 100 void TIntermBlock::traverse(TIntermTraverser *it) 101 { 102 it->traverseBlock(this); 103 } 104 105 void TIntermAggregate::traverse(TIntermTraverser *it) 106 { 107 it->traverseAggregate(this); 108 } 109 110 void TIntermLoop::traverse(TIntermTraverser *it) 111 { 112 it->traverseLoop(this); 113 } 114 115 void TIntermPreprocessorDirective::traverse(TIntermTraverser *it) 116 { 117 it->visitPreprocessorDirective(this); 118 } 119 120 bool TIntermSymbol::visit(Visit visit, TIntermTraverser *it) 121 { 122 it->visitSymbol(this); 123 return false; 124 } 125 126 bool TIntermConstantUnion::visit(Visit visit, TIntermTraverser *it) 127 { 128 it->visitConstantUnion(this); 129 return false; 130 } 131 132 bool TIntermFunctionPrototype::visit(Visit visit, TIntermTraverser *it) 133 { 134 it->visitFunctionPrototype(this); 135 return false; 136 } 137 138 bool TIntermFunctionDefinition::visit(Visit visit, TIntermTraverser *it) 139 { 140 return it->visitFunctionDefinition(visit, this); 141 } 142 143 bool TIntermUnary::visit(Visit visit, TIntermTraverser *it) 144 { 145 return it->visitUnary(visit, this); 146 } 147 148 bool TIntermSwizzle::visit(Visit visit, TIntermTraverser *it) 149 { 150 return it->visitSwizzle(visit, this); 151 } 152 153 bool TIntermBinary::visit(Visit visit, TIntermTraverser *it) 154 { 155 return it->visitBinary(visit, this); 156 } 157 158 bool TIntermTernary::visit(Visit visit, TIntermTraverser *it) 159 { 160 return it->visitTernary(visit, this); 161 } 162 163 bool TIntermAggregate::visit(Visit visit, TIntermTraverser *it) 164 { 165 return it->visitAggregate(visit, this); 166 } 167 168 bool TIntermDeclaration::visit(Visit visit, TIntermTraverser *it) 169 { 170 return it->visitDeclaration(visit, this); 171 } 172 173 bool TIntermGlobalQualifierDeclaration::visit(Visit visit, TIntermTraverser *it) 174 { 175 return it->visitGlobalQualifierDeclaration(visit, this); 176 } 177 178 bool TIntermBlock::visit(Visit visit, TIntermTraverser *it) 179 { 180 return it->visitBlock(visit, this); 181 } 182 183 bool TIntermIfElse::visit(Visit visit, TIntermTraverser *it) 184 { 185 return it->visitIfElse(visit, this); 186 } 187 188 bool TIntermLoop::visit(Visit visit, TIntermTraverser *it) 189 { 190 return it->visitLoop(visit, this); 191 } 192 193 bool TIntermBranch::visit(Visit visit, TIntermTraverser *it) 194 { 195 return it->visitBranch(visit, this); 196 } 197 198 bool TIntermSwitch::visit(Visit visit, TIntermTraverser *it) 199 { 200 return it->visitSwitch(visit, this); 201 } 202 203 bool TIntermCase::visit(Visit visit, TIntermTraverser *it) 204 { 205 return it->visitCase(visit, this); 206 } 207 208 bool TIntermPreprocessorDirective::visit(Visit visit, TIntermTraverser *it) 209 { 210 it->visitPreprocessorDirective(this); 211 return false; 212 } 213 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 231 TIntermTraverser::~TIntermTraverser() {} 232 233 void TIntermTraverser::setMaxAllowedDepth(int depth) 234 { 235 mMaxAllowedDepth = depth; 236 } 237 238 const TIntermBlock *TIntermTraverser::getParentBlock() const 239 { 240 if (!mParentBlockStack.empty()) 241 { 242 return mParentBlockStack.back().node; 243 } 244 return nullptr; 245 } 246 247 void TIntermTraverser::pushParentBlock(TIntermBlock *node) 248 { 249 mParentBlockStack.push_back(ParentBlock(node, 0)); 250 } 251 252 void TIntermTraverser::incrementParentBlockPos() 253 { 254 ++mParentBlockStack.back().pos; 255 } 256 257 void TIntermTraverser::popParentBlock() 258 { 259 ASSERT(!mParentBlockStack.empty()); 260 mParentBlockStack.pop_back(); 261 } 262 263 void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions) 264 { 265 TIntermSequence emptyInsertionsAfter; 266 insertStatementsInParentBlock(insertions, emptyInsertionsAfter); 267 } 268 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 286 void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement) 287 { 288 TIntermSequence insertions; 289 insertions.push_back(statement); 290 insertStatementsInParentBlock(insertions); 291 } 292 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 305 void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter) 306 { 307 mInFunctionCallOutParameter = inOutParameter; 308 } 309 310 bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const 311 { 312 return mInFunctionCallOutParameter; 313 } 314 315 void TIntermTraverser::traverseBinary(TIntermBinary *node) 316 { 317 traverse(node); 318 } 319 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 379 void TIntermTraverser::traverseUnary(TIntermUnary *node) 380 { 381 traverse(node); 382 } 383 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. 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. 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 497 void TIntermTraverser::traverseAggregate(TIntermAggregate *node) 498 { 499 traverse(node); 500 } 501 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 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 589 void TIntermTraverser::clearReplacementQueue() 590 { 591 mReplacements.clear(); 592 mMultiReplacements.clear(); 593 mInsertions.clear(); 594 } 595 596 void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus) 597 { 598 queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus); 599 } 600 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 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 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 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 704 void TIntermTraverser::traverseLoop(TIntermLoop *node) 705 { 706 traverse(node); 707 } 708 } // namespace sh