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