1 // 2 // Copyright (c) 2002-2014 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 // 8 // Definition of the in-memory high-level intermediate representation 9 // of shaders. This is a tree that parser creates. 10 // 11 // Nodes in the tree are defined as a hierarchy of classes derived from 12 // TIntermNode. Each is a node in a tree. There is no preset branching factor; 13 // each node can have it's own type of list of children. 14 // 15 16 #ifndef COMPILER_TRANSLATOR_INTERMEDIATE_H_ 17 #define COMPILER_TRANSLATOR_INTERMEDIATE_H_ 18 19 #include "GLSLANG/ShaderLang.h" 20 21 #include <algorithm> 22 #include <queue> 23 24 #include "compiler/translator/Common.h" 25 #include "compiler/translator/Types.h" 26 #include "compiler/translator/ConstantUnion.h" 27 28 // 29 // Operators used by the high-level (parse tree) representation. 30 // 31 enum TOperator 32 { 33 EOpNull, // if in a node, should only mean a node is still being built 34 EOpSequence, // denotes a list of statements, or parameters, etc. 35 EOpFunctionCall, 36 EOpFunction, // For function definition 37 EOpParameters, // an aggregate listing the parameters to a function 38 39 EOpDeclaration, 40 EOpInvariantDeclaration, // Specialized declarations for attributing invariance 41 EOpPrototype, 42 43 // 44 // Unary operators 45 // 46 47 EOpNegative, 48 EOpLogicalNot, 49 EOpVectorLogicalNot, 50 51 EOpPostIncrement, 52 EOpPostDecrement, 53 EOpPreIncrement, 54 EOpPreDecrement, 55 56 // 57 // binary operations 58 // 59 60 EOpAdd, 61 EOpSub, 62 EOpMul, 63 EOpDiv, 64 EOpEqual, 65 EOpNotEqual, 66 EOpVectorEqual, 67 EOpVectorNotEqual, 68 EOpLessThan, 69 EOpGreaterThan, 70 EOpLessThanEqual, 71 EOpGreaterThanEqual, 72 EOpComma, 73 74 EOpVectorTimesScalar, 75 EOpVectorTimesMatrix, 76 EOpMatrixTimesVector, 77 EOpMatrixTimesScalar, 78 79 EOpLogicalOr, 80 EOpLogicalXor, 81 EOpLogicalAnd, 82 83 EOpIndexDirect, 84 EOpIndexIndirect, 85 EOpIndexDirectStruct, 86 EOpIndexDirectInterfaceBlock, 87 88 EOpVectorSwizzle, 89 90 // 91 // Built-in functions potentially mapped to operators 92 // 93 94 EOpRadians, 95 EOpDegrees, 96 EOpSin, 97 EOpCos, 98 EOpTan, 99 EOpAsin, 100 EOpAcos, 101 EOpAtan, 102 103 EOpPow, 104 EOpExp, 105 EOpLog, 106 EOpExp2, 107 EOpLog2, 108 EOpSqrt, 109 EOpInverseSqrt, 110 111 EOpAbs, 112 EOpSign, 113 EOpFloor, 114 EOpCeil, 115 EOpFract, 116 EOpMod, 117 EOpMin, 118 EOpMax, 119 EOpClamp, 120 EOpMix, 121 EOpStep, 122 EOpSmoothStep, 123 124 EOpLength, 125 EOpDistance, 126 EOpDot, 127 EOpCross, 128 EOpNormalize, 129 EOpFaceForward, 130 EOpReflect, 131 EOpRefract, 132 133 EOpDFdx, // Fragment only, OES_standard_derivatives extension 134 EOpDFdy, // Fragment only, OES_standard_derivatives extension 135 EOpFwidth, // Fragment only, OES_standard_derivatives extension 136 137 EOpMatrixTimesMatrix, 138 139 EOpAny, 140 EOpAll, 141 142 // 143 // Branch 144 // 145 146 EOpKill, // Fragment only 147 EOpReturn, 148 EOpBreak, 149 EOpContinue, 150 151 // 152 // Constructors 153 // 154 155 EOpConstructInt, 156 EOpConstructUInt, 157 EOpConstructBool, 158 EOpConstructFloat, 159 EOpConstructVec2, 160 EOpConstructVec3, 161 EOpConstructVec4, 162 EOpConstructBVec2, 163 EOpConstructBVec3, 164 EOpConstructBVec4, 165 EOpConstructIVec2, 166 EOpConstructIVec3, 167 EOpConstructIVec4, 168 EOpConstructUVec2, 169 EOpConstructUVec3, 170 EOpConstructUVec4, 171 EOpConstructMat2, 172 EOpConstructMat3, 173 EOpConstructMat4, 174 EOpConstructStruct, 175 176 // 177 // moves 178 // 179 180 EOpAssign, 181 EOpInitialize, 182 EOpAddAssign, 183 EOpSubAssign, 184 EOpMulAssign, 185 EOpVectorTimesMatrixAssign, 186 EOpVectorTimesScalarAssign, 187 EOpMatrixTimesScalarAssign, 188 EOpMatrixTimesMatrixAssign, 189 EOpDivAssign 190 }; 191 192 class TIntermTraverser; 193 class TIntermAggregate; 194 class TIntermBinary; 195 class TIntermUnary; 196 class TIntermConstantUnion; 197 class TIntermSelection; 198 class TIntermTyped; 199 class TIntermSymbol; 200 class TIntermLoop; 201 class TInfoSink; 202 class TIntermRaw; 203 204 // 205 // Base class for the tree nodes 206 // 207 class TIntermNode 208 { 209 public: 210 POOL_ALLOCATOR_NEW_DELETE(); 211 TIntermNode() 212 { 213 // TODO: Move this to TSourceLoc constructor 214 // after getting rid of TPublicType. 215 mLine.first_file = mLine.last_file = 0; 216 mLine.first_line = mLine.last_line = 0; 217 } 218 virtual ~TIntermNode() { } 219 220 const TSourceLoc &getLine() const { return mLine; } 221 void setLine(const TSourceLoc &l) { mLine = l; } 222 223 virtual void traverse(TIntermTraverser *) = 0; 224 virtual TIntermTyped *getAsTyped() { return 0; } 225 virtual TIntermConstantUnion *getAsConstantUnion() { return 0; } 226 virtual TIntermAggregate *getAsAggregate() { return 0; } 227 virtual TIntermBinary *getAsBinaryNode() { return 0; } 228 virtual TIntermUnary *getAsUnaryNode() { return 0; } 229 virtual TIntermSelection *getAsSelectionNode() { return 0; } 230 virtual TIntermSymbol *getAsSymbolNode() { return 0; } 231 virtual TIntermLoop *getAsLoopNode() { return 0; } 232 virtual TIntermRaw *getAsRawNode() { return 0; } 233 234 // Replace a child node. Return true if |original| is a child 235 // node and it is replaced; otherwise, return false. 236 virtual bool replaceChildNode( 237 TIntermNode *original, TIntermNode *replacement) = 0; 238 239 // For traversing a tree in no particular order, but using 240 // heap memory. 241 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const = 0; 242 243 protected: 244 TSourceLoc mLine; 245 }; 246 247 // 248 // This is just to help yacc. 249 // 250 struct TIntermNodePair 251 { 252 TIntermNode *node1; 253 TIntermNode *node2; 254 }; 255 256 // 257 // Intermediate class for nodes that have a type. 258 // 259 class TIntermTyped : public TIntermNode 260 { 261 public: 262 TIntermTyped(const TType &t) : mType(t) { } 263 virtual TIntermTyped *getAsTyped() { return this; } 264 265 virtual bool hasSideEffects() const = 0; 266 267 void setType(const TType &t) { mType = t; } 268 const TType &getType() const { return mType; } 269 TType *getTypePointer() { return &mType; } 270 271 TBasicType getBasicType() const { return mType.getBasicType(); } 272 TQualifier getQualifier() const { return mType.getQualifier(); } 273 TPrecision getPrecision() const { return mType.getPrecision(); } 274 int getCols() const { return mType.getCols(); } 275 int getRows() const { return mType.getRows(); } 276 int getNominalSize() const { return mType.getNominalSize(); } 277 int getSecondarySize() const { return mType.getSecondarySize(); } 278 279 bool isInterfaceBlock() const { return mType.isInterfaceBlock(); } 280 bool isMatrix() const { return mType.isMatrix(); } 281 bool isArray() const { return mType.isArray(); } 282 bool isVector() const { return mType.isVector(); } 283 bool isScalar() const { return mType.isScalar(); } 284 bool isScalarInt() const { return mType.isScalarInt(); } 285 const char *getBasicString() const { return mType.getBasicString(); } 286 const char *getQualifierString() const { return mType.getQualifierString(); } 287 TString getCompleteString() const { return mType.getCompleteString(); } 288 289 int getArraySize() const { return mType.getArraySize(); } 290 291 protected: 292 TType mType; 293 }; 294 295 // 296 // Handle for, do-while, and while loops. 297 // 298 enum TLoopType 299 { 300 ELoopFor, 301 ELoopWhile, 302 ELoopDoWhile 303 }; 304 305 class TIntermLoop : public TIntermNode 306 { 307 public: 308 TIntermLoop(TLoopType type, 309 TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr, 310 TIntermNode *body) 311 : mType(type), 312 mInit(init), 313 mCond(cond), 314 mExpr(expr), 315 mBody(body), 316 mUnrollFlag(false) { } 317 318 virtual TIntermLoop *getAsLoopNode() { return this; } 319 virtual void traverse(TIntermTraverser *); 320 virtual bool replaceChildNode( 321 TIntermNode *original, TIntermNode *replacement); 322 323 TLoopType getType() const { return mType; } 324 TIntermNode *getInit() { return mInit; } 325 TIntermTyped *getCondition() { return mCond; } 326 TIntermTyped *getExpression() { return mExpr; } 327 TIntermNode *getBody() { return mBody; } 328 329 void setUnrollFlag(bool flag) { mUnrollFlag = flag; } 330 bool getUnrollFlag() const { return mUnrollFlag; } 331 332 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const; 333 334 protected: 335 TLoopType mType; 336 TIntermNode *mInit; // for-loop initialization 337 TIntermTyped *mCond; // loop exit condition 338 TIntermTyped *mExpr; // for-loop expression 339 TIntermNode *mBody; // loop body 340 341 bool mUnrollFlag; // Whether the loop should be unrolled or not. 342 }; 343 344 // 345 // Handle break, continue, return, and kill. 346 // 347 class TIntermBranch : public TIntermNode 348 { 349 public: 350 TIntermBranch(TOperator op, TIntermTyped *e) 351 : mFlowOp(op), 352 mExpression(e) { } 353 354 virtual void traverse(TIntermTraverser *); 355 virtual bool replaceChildNode( 356 TIntermNode *original, TIntermNode *replacement); 357 358 TOperator getFlowOp() { return mFlowOp; } 359 TIntermTyped* getExpression() { return mExpression; } 360 361 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const; 362 363 protected: 364 TOperator mFlowOp; 365 TIntermTyped *mExpression; // non-zero except for "return exp;" statements 366 }; 367 368 // 369 // Nodes that correspond to symbols or constants in the source code. 370 // 371 class TIntermSymbol : public TIntermTyped 372 { 373 public: 374 // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. 375 // If sym comes from per process globalpoolallocator, then it causes increased memory usage 376 // per compile it is essential to use "symbol = sym" to assign to symbol 377 TIntermSymbol(int id, const TString &symbol, const TType &type) 378 : TIntermTyped(type), 379 mId(id) 380 { 381 mSymbol = symbol; 382 } 383 384 virtual bool hasSideEffects() const { return false; } 385 386 int getId() const { return mId; } 387 const TString &getSymbol() const { return mSymbol; } 388 389 void setId(int newId) { mId = newId; } 390 391 virtual void traverse(TIntermTraverser *); 392 virtual TIntermSymbol *getAsSymbolNode() { return this; } 393 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } 394 395 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const {} 396 397 protected: 398 int mId; 399 TString mSymbol; 400 }; 401 402 // A Raw node stores raw code, that the translator will insert verbatim 403 // into the output stream. Useful for transformation operations that make 404 // complex code that might not fit naturally into the GLSL model. 405 class TIntermRaw : public TIntermTyped 406 { 407 public: 408 TIntermRaw(const TType &type, const TString &rawText) 409 : TIntermTyped(type), 410 mRawText(rawText) { } 411 412 virtual bool hasSideEffects() const { return false; } 413 414 TString getRawText() const { return mRawText; } 415 416 virtual void traverse(TIntermTraverser *); 417 418 virtual TIntermRaw *getAsRawNode() { return this; } 419 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } 420 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const {} 421 422 protected: 423 TString mRawText; 424 }; 425 426 class TIntermConstantUnion : public TIntermTyped 427 { 428 public: 429 TIntermConstantUnion(ConstantUnion *unionPointer, const TType &type) 430 : TIntermTyped(type), 431 mUnionArrayPointer(unionPointer) { } 432 433 virtual bool hasSideEffects() const { return false; } 434 435 ConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; } 436 437 int getIConst(size_t index) const 438 { 439 return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0; 440 } 441 unsigned int getUConst(size_t index) const 442 { 443 return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0; 444 } 445 float getFConst(size_t index) const 446 { 447 return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f; 448 } 449 bool getBConst(size_t index) const 450 { 451 return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false; 452 } 453 454 virtual TIntermConstantUnion *getAsConstantUnion() { return this; } 455 virtual void traverse(TIntermTraverser *); 456 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } 457 458 TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &); 459 460 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const {} 461 462 protected: 463 ConstantUnion *mUnionArrayPointer; 464 }; 465 466 // 467 // Intermediate class for node types that hold operators. 468 // 469 class TIntermOperator : public TIntermTyped 470 { 471 public: 472 TOperator getOp() const { return mOp; } 473 void setOp(TOperator op) { mOp = op; } 474 475 bool isAssignment() const; 476 bool isConstructor() const; 477 478 virtual bool hasSideEffects() const { return isAssignment(); } 479 480 protected: 481 TIntermOperator(TOperator op) 482 : TIntermTyped(TType(EbtFloat, EbpUndefined)), 483 mOp(op) {} 484 TIntermOperator(TOperator op, const TType &type) 485 : TIntermTyped(type), 486 mOp(op) {} 487 488 TOperator mOp; 489 }; 490 491 // 492 // Nodes for all the basic binary math operators. 493 // 494 class TIntermBinary : public TIntermOperator 495 { 496 public: 497 TIntermBinary(TOperator op) 498 : TIntermOperator(op), 499 mAddIndexClamp(false) {} 500 501 virtual TIntermBinary *getAsBinaryNode() { return this; } 502 virtual void traverse(TIntermTraverser *); 503 virtual bool replaceChildNode( 504 TIntermNode *original, TIntermNode *replacement); 505 506 virtual bool hasSideEffects() const 507 { 508 return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects(); 509 } 510 511 void setLeft(TIntermTyped *node) { mLeft = node; } 512 void setRight(TIntermTyped *node) { mRight = node; } 513 TIntermTyped *getLeft() const { return mLeft; } 514 TIntermTyped *getRight() const { return mRight; } 515 bool promote(TInfoSink &); 516 517 void setAddIndexClamp() { mAddIndexClamp = true; } 518 bool getAddIndexClamp() { return mAddIndexClamp; } 519 520 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const; 521 522 protected: 523 TIntermTyped* mLeft; 524 TIntermTyped* mRight; 525 526 // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. 527 bool mAddIndexClamp; 528 }; 529 530 // 531 // Nodes for unary math operators. 532 // 533 class TIntermUnary : public TIntermOperator 534 { 535 public: 536 TIntermUnary(TOperator op, const TType &type) 537 : TIntermOperator(op, type), 538 mOperand(NULL), 539 mUseEmulatedFunction(false) {} 540 TIntermUnary(TOperator op) 541 : TIntermOperator(op), 542 mOperand(NULL), 543 mUseEmulatedFunction(false) {} 544 545 virtual void traverse(TIntermTraverser *); 546 virtual TIntermUnary *getAsUnaryNode() { return this; } 547 virtual bool replaceChildNode( 548 TIntermNode *original, TIntermNode *replacement); 549 550 virtual bool hasSideEffects() const 551 { 552 return isAssignment() || mOperand->hasSideEffects(); 553 } 554 555 void setOperand(TIntermTyped *operand) { mOperand = operand; } 556 TIntermTyped *getOperand() { return mOperand; } 557 bool promote(TInfoSink &); 558 559 void setUseEmulatedFunction() { mUseEmulatedFunction = true; } 560 bool getUseEmulatedFunction() { return mUseEmulatedFunction; } 561 562 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const; 563 564 protected: 565 TIntermTyped *mOperand; 566 567 // If set to true, replace the built-in function call with an emulated one 568 // to work around driver bugs. 569 bool mUseEmulatedFunction; 570 }; 571 572 typedef TVector<TIntermNode *> TIntermSequence; 573 typedef TVector<int> TQualifierList; 574 575 // 576 // Nodes that operate on an arbitrary sized set of children. 577 // 578 class TIntermAggregate : public TIntermOperator 579 { 580 public: 581 TIntermAggregate() 582 : TIntermOperator(EOpNull), 583 mUserDefined(false), 584 mUseEmulatedFunction(false) { } 585 TIntermAggregate(TOperator op) 586 : TIntermOperator(op), 587 mUseEmulatedFunction(false) { } 588 ~TIntermAggregate() { } 589 590 virtual TIntermAggregate *getAsAggregate() { return this; } 591 virtual void traverse(TIntermTraverser *); 592 virtual bool replaceChildNode( 593 TIntermNode *original, TIntermNode *replacement); 594 595 // Conservatively assume function calls and other aggregate operators have side-effects 596 virtual bool hasSideEffects() const { return true; } 597 598 TIntermSequence *getSequence() { return &mSequence; } 599 600 void setName(const TString &name) { mName = name; } 601 const TString &getName() const { return mName; } 602 603 void setUserDefined() { mUserDefined = true; } 604 bool isUserDefined() const { return mUserDefined; } 605 606 void setOptimize(bool optimize) { mOptimize = optimize; } 607 bool getOptimize() const { return mOptimize; } 608 void setDebug(bool debug) { mDebug = debug; } 609 bool getDebug() const { return mDebug; } 610 611 void setUseEmulatedFunction() { mUseEmulatedFunction = true; } 612 bool getUseEmulatedFunction() { return mUseEmulatedFunction; } 613 614 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const; 615 616 protected: 617 TIntermAggregate(const TIntermAggregate &); // disallow copy constructor 618 TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator 619 TIntermSequence mSequence; 620 TString mName; 621 bool mUserDefined; // used for user defined function names 622 623 bool mOptimize; 624 bool mDebug; 625 626 // If set to true, replace the built-in function call with an emulated one 627 // to work around driver bugs. 628 bool mUseEmulatedFunction; 629 }; 630 631 // 632 // For if tests. Simplified since there is no switch statement. 633 // 634 class TIntermSelection : public TIntermTyped 635 { 636 public: 637 TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB) 638 : TIntermTyped(TType(EbtVoid, EbpUndefined)), 639 mCondition(cond), 640 mTrueBlock(trueB), 641 mFalseBlock(falseB) {} 642 TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB, 643 const TType &type) 644 : TIntermTyped(type), 645 mCondition(cond), 646 mTrueBlock(trueB), 647 mFalseBlock(falseB) {} 648 649 virtual void traverse(TIntermTraverser *); 650 virtual bool replaceChildNode( 651 TIntermNode *original, TIntermNode *replacement); 652 653 // Conservatively assume selections have side-effects 654 virtual bool hasSideEffects() const { return true; } 655 656 bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } 657 TIntermNode *getCondition() const { return mCondition; } 658 TIntermNode *getTrueBlock() const { return mTrueBlock; } 659 TIntermNode *getFalseBlock() const { return mFalseBlock; } 660 TIntermSelection *getAsSelectionNode() { return this; } 661 662 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const; 663 664 protected: 665 TIntermTyped *mCondition; 666 TIntermNode *mTrueBlock; 667 TIntermNode *mFalseBlock; 668 }; 669 670 enum Visit 671 { 672 PreVisit, 673 InVisit, 674 PostVisit 675 }; 676 677 // 678 // For traversing the tree. User should derive from this, 679 // put their traversal specific data in it, and then pass 680 // it to a Traverse method. 681 // 682 // When using this, just fill in the methods for nodes you want visited. 683 // Return false from a pre-visit to skip visiting that node's subtree. 684 // 685 class TIntermTraverser 686 { 687 public: 688 POOL_ALLOCATOR_NEW_DELETE(); 689 // TODO(zmo): remove default values. 690 TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, 691 bool rightToLeft = false) 692 : preVisit(preVisit), 693 inVisit(inVisit), 694 postVisit(postVisit), 695 rightToLeft(rightToLeft), 696 mDepth(0), 697 mMaxDepth(0) {} 698 virtual ~TIntermTraverser() {} 699 700 virtual void visitSymbol(TIntermSymbol *) {} 701 virtual void visitRaw(TIntermRaw *) {} 702 virtual void visitConstantUnion(TIntermConstantUnion *) {} 703 virtual bool visitBinary(Visit, TIntermBinary *) { return true; } 704 virtual bool visitUnary(Visit, TIntermUnary *) { return true; } 705 virtual bool visitSelection(Visit, TIntermSelection *) { return true; } 706 virtual bool visitAggregate(Visit, TIntermAggregate *) { return true; } 707 virtual bool visitLoop(Visit, TIntermLoop *) { return true; } 708 virtual bool visitBranch(Visit, TIntermBranch *) { return true; } 709 710 int getMaxDepth() const { return mMaxDepth; } 711 712 void incrementDepth(TIntermNode *current) 713 { 714 mDepth++; 715 mMaxDepth = std::max(mMaxDepth, mDepth); 716 mPath.push_back(current); 717 } 718 719 void decrementDepth() 720 { 721 mDepth--; 722 mPath.pop_back(); 723 } 724 725 TIntermNode *getParentNode() 726 { 727 return mPath.size() == 0 ? NULL : mPath.back(); 728 } 729 730 // Return the original name if hash function pointer is NULL; 731 // otherwise return the hashed name. 732 static TString hash(const TString& name, ShHashFunction64 hashFunction); 733 734 const bool preVisit; 735 const bool inVisit; 736 const bool postVisit; 737 const bool rightToLeft; 738 739 protected: 740 int mDepth; 741 int mMaxDepth; 742 743 // All the nodes from root to the current node's parent during traversing. 744 TVector<TIntermNode *> mPath; 745 }; 746 747 // 748 // For traversing the tree, and computing max depth. 749 // Takes a maximum depth limit to prevent stack overflow. 750 // 751 class TMaxDepthTraverser : public TIntermTraverser 752 { 753 public: 754 POOL_ALLOCATOR_NEW_DELETE(); 755 TMaxDepthTraverser(int depthLimit) 756 : TIntermTraverser(true, true, false, false), 757 mDepthLimit(depthLimit) { } 758 759 virtual bool visitBinary(Visit, TIntermBinary *) { return depthCheck(); } 760 virtual bool visitUnary(Visit, TIntermUnary *) { return depthCheck(); } 761 virtual bool visitSelection(Visit, TIntermSelection *) { return depthCheck(); } 762 virtual bool visitAggregate(Visit, TIntermAggregate *) { return depthCheck(); } 763 virtual bool visitLoop(Visit, TIntermLoop *) { return depthCheck(); } 764 virtual bool visitBranch(Visit, TIntermBranch *) { return depthCheck(); } 765 766 protected: 767 bool depthCheck() const { return mMaxDepth < mDepthLimit; } 768 769 int mDepthLimit; 770 }; 771 772 #endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ 773