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.
8 // Definition of the in-memory high-level intermediate representation
9 // of shaders. This is a tree that parser creates.
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.
16 #ifndef COMPILER_TRANSLATOR_INTERMEDIATE_H_
17 #define COMPILER_TRANSLATOR_INTERMEDIATE_H_
19 #include "GLSLANG/ShaderLang.h"
24 #include "compiler/translator/Common.h"
25 #include "compiler/translator/Types.h"
26 #include "compiler/translator/ConstantUnion.h"
29 // Operators used by the high-level (parse tree) representation.
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.
36 EOpFunction, // For function definition
37 EOpParameters, // an aggregate listing the parameters to a function
40 EOpInvariantDeclaration, // Specialized declarations for attributing invariance
86 EOpIndexDirectInterfaceBlock,
91 // Built-in functions potentially mapped to operators
133 EOpDFdx, // Fragment only, OES_standard_derivatives extension
134 EOpDFdy, // Fragment only, OES_standard_derivatives extension
135 EOpFwidth, // Fragment only, OES_standard_derivatives extension
137 EOpMatrixTimesMatrix,
146 EOpKill, // Fragment only
185 EOpVectorTimesMatrixAssign,
186 EOpVectorTimesScalarAssign,
187 EOpMatrixTimesScalarAssign,
188 EOpMatrixTimesMatrixAssign,
192 class TIntermTraverser;
193 class TIntermAggregate;
196 class TIntermConstantUnion;
197 class TIntermSelection;
205 // Base class for the tree nodes
210 POOL_ALLOCATOR_NEW_DELETE();
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;
218 virtual ~TIntermNode() { }
220 const TSourceLoc &getLine() const { return mLine; }
221 void setLine(const TSourceLoc &l) { mLine = l; }
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; }
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;
239 // For traversing a tree in no particular order, but using
241 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const = 0;
248 // This is just to help yacc.
250 struct TIntermNodePair
257 // Intermediate class for nodes that have a type.
259 class TIntermTyped : public TIntermNode
262 TIntermTyped(const TType &t) : mType(t) { }
263 virtual TIntermTyped *getAsTyped() { return this; }
265 virtual bool hasSideEffects() const = 0;
267 void setType(const TType &t) { mType = t; }
268 const TType &getType() const { return mType; }
269 TType *getTypePointer() { return &mType; }
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(); }
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(); }
289 int getArraySize() const { return mType.getArraySize(); }
296 // Handle for, do-while, and while loops.
305 class TIntermLoop : public TIntermNode
308 TIntermLoop(TLoopType type,
309 TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
316 mUnrollFlag(false) { }
318 virtual TIntermLoop *getAsLoopNode() { return this; }
319 virtual void traverse(TIntermTraverser *);
320 virtual bool replaceChildNode(
321 TIntermNode *original, TIntermNode *replacement);
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; }
329 void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
330 bool getUnrollFlag() const { return mUnrollFlag; }
332 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
336 TIntermNode *mInit; // for-loop initialization
337 TIntermTyped *mCond; // loop exit condition
338 TIntermTyped *mExpr; // for-loop expression
339 TIntermNode *mBody; // loop body
341 bool mUnrollFlag; // Whether the loop should be unrolled or not.
345 // Handle break, continue, return, and kill.
347 class TIntermBranch : public TIntermNode
350 TIntermBranch(TOperator op, TIntermTyped *e)
354 virtual void traverse(TIntermTraverser *);
355 virtual bool replaceChildNode(
356 TIntermNode *original, TIntermNode *replacement);
358 TOperator getFlowOp() { return mFlowOp; }
359 TIntermTyped* getExpression() { return mExpression; }
361 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
365 TIntermTyped *mExpression; // non-zero except for "return exp;" statements
369 // Nodes that correspond to symbols or constants in the source code.
371 class TIntermSymbol : public TIntermTyped
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),
384 virtual bool hasSideEffects() const { return false; }
386 int getId() const { return mId; }
387 const TString &getSymbol() const { return mSymbol; }
389 void setId(int newId) { mId = newId; }
391 virtual void traverse(TIntermTraverser *);
392 virtual TIntermSymbol *getAsSymbolNode() { return this; }
393 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
395 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const {}
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
408 TIntermRaw(const TType &type, const TString &rawText)
409 : TIntermTyped(type),
410 mRawText(rawText) { }
412 virtual bool hasSideEffects() const { return false; }
414 TString getRawText() const { return mRawText; }
416 virtual void traverse(TIntermTraverser *);
418 virtual TIntermRaw *getAsRawNode() { return this; }
419 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
420 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const {}
426 class TIntermConstantUnion : public TIntermTyped
429 TIntermConstantUnion(ConstantUnion *unionPointer, const TType &type)
430 : TIntermTyped(type),
431 mUnionArrayPointer(unionPointer) { }
433 virtual bool hasSideEffects() const { return false; }
435 ConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
437 int getIConst(size_t index) const
439 return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0;
441 unsigned int getUConst(size_t index) const
443 return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0;
445 float getFConst(size_t index) const
447 return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f;
449 bool getBConst(size_t index) const
451 return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
454 virtual TIntermConstantUnion *getAsConstantUnion() { return this; }
455 virtual void traverse(TIntermTraverser *);
456 virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
458 TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &);
460 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const {}
463 ConstantUnion *mUnionArrayPointer;
467 // Intermediate class for node types that hold operators.
469 class TIntermOperator : public TIntermTyped
472 TOperator getOp() const { return mOp; }
473 void setOp(TOperator op) { mOp = op; }
475 bool isAssignment() const;
476 bool isConstructor() const;
478 virtual bool hasSideEffects() const { return isAssignment(); }
481 TIntermOperator(TOperator op)
482 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
484 TIntermOperator(TOperator op, const TType &type)
485 : TIntermTyped(type),
492 // Nodes for all the basic binary math operators.
494 class TIntermBinary : public TIntermOperator
497 TIntermBinary(TOperator op)
498 : TIntermOperator(op),
499 mAddIndexClamp(false) {}
501 virtual TIntermBinary *getAsBinaryNode() { return this; }
502 virtual void traverse(TIntermTraverser *);
503 virtual bool replaceChildNode(
504 TIntermNode *original, TIntermNode *replacement);
506 virtual bool hasSideEffects() const
508 return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
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 &);
517 void setAddIndexClamp() { mAddIndexClamp = true; }
518 bool getAddIndexClamp() { return mAddIndexClamp; }
520 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
524 TIntermTyped* mRight;
526 // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
531 // Nodes for unary math operators.
533 class TIntermUnary : public TIntermOperator
536 TIntermUnary(TOperator op, const TType &type)
537 : TIntermOperator(op, type),
539 mUseEmulatedFunction(false) {}
540 TIntermUnary(TOperator op)
541 : TIntermOperator(op),
543 mUseEmulatedFunction(false) {}
545 virtual void traverse(TIntermTraverser *);
546 virtual TIntermUnary *getAsUnaryNode() { return this; }
547 virtual bool replaceChildNode(
548 TIntermNode *original, TIntermNode *replacement);
550 virtual bool hasSideEffects() const
552 return isAssignment() || mOperand->hasSideEffects();
555 void setOperand(TIntermTyped *operand) { mOperand = operand; }
556 TIntermTyped *getOperand() { return mOperand; }
557 bool promote(TInfoSink &);
559 void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
560 bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
562 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
565 TIntermTyped *mOperand;
567 // If set to true, replace the built-in function call with an emulated one
568 // to work around driver bugs.
569 bool mUseEmulatedFunction;
572 typedef TVector<TIntermNode *> TIntermSequence;
573 typedef TVector<int> TQualifierList;
576 // Nodes that operate on an arbitrary sized set of children.
578 class TIntermAggregate : public TIntermOperator
582 : TIntermOperator(EOpNull),
584 mUseEmulatedFunction(false) { }
585 TIntermAggregate(TOperator op)
586 : TIntermOperator(op),
587 mUseEmulatedFunction(false) { }
588 ~TIntermAggregate() { }
590 virtual TIntermAggregate *getAsAggregate() { return this; }
591 virtual void traverse(TIntermTraverser *);
592 virtual bool replaceChildNode(
593 TIntermNode *original, TIntermNode *replacement);
595 // Conservatively assume function calls and other aggregate operators have side-effects
596 virtual bool hasSideEffects() const { return true; }
598 TIntermSequence *getSequence() { return &mSequence; }
600 void setName(const TString &name) { mName = name; }
601 const TString &getName() const { return mName; }
603 void setUserDefined() { mUserDefined = true; }
604 bool isUserDefined() const { return mUserDefined; }
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; }
611 void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
612 bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
614 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
617 TIntermAggregate(const TIntermAggregate &); // disallow copy constructor
618 TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator
619 TIntermSequence mSequence;
621 bool mUserDefined; // used for user defined function names
626 // If set to true, replace the built-in function call with an emulated one
627 // to work around driver bugs.
628 bool mUseEmulatedFunction;
632 // For if tests. Simplified since there is no switch statement.
634 class TIntermSelection : public TIntermTyped
637 TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
638 : TIntermTyped(TType(EbtVoid, EbpUndefined)),
641 mFalseBlock(falseB) {}
642 TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB,
644 : TIntermTyped(type),
647 mFalseBlock(falseB) {}
649 virtual void traverse(TIntermTraverser *);
650 virtual bool replaceChildNode(
651 TIntermNode *original, TIntermNode *replacement);
653 // Conservatively assume selections have side-effects
654 virtual bool hasSideEffects() const { return true; }
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; }
662 virtual void enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const;
665 TIntermTyped *mCondition;
666 TIntermNode *mTrueBlock;
667 TIntermNode *mFalseBlock;
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.
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.
685 class TIntermTraverser
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),
694 postVisit(postVisit),
695 rightToLeft(rightToLeft),
698 virtual ~TIntermTraverser() {}
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; }
710 int getMaxDepth() const { return mMaxDepth; }
712 void incrementDepth(TIntermNode *current)
715 mMaxDepth = std::max(mMaxDepth, mDepth);
716 mPath.push_back(current);
719 void decrementDepth()
725 TIntermNode *getParentNode()
727 return mPath.size() == 0 ? NULL : mPath.back();
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);
736 const bool postVisit;
737 const bool rightToLeft;
743 // All the nodes from root to the current node's parent during traversing.
744 TVector<TIntermNode *> mPath;
748 // For traversing the tree, and computing max depth.
749 // Takes a maximum depth limit to prevent stack overflow.
751 class TMaxDepthTraverser : public TIntermTraverser
754 POOL_ALLOCATOR_NEW_DELETE();
755 TMaxDepthTraverser(int depthLimit)
756 : TIntermTraverser(true, true, false, false),
757 mDepthLimit(depthLimit) { }
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(); }
767 bool depthCheck() const { return mMaxDepth < mDepthLimit; }
772 #endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_