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