michael@0: // michael@0: // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // michael@0: // Definition of the in-memory high-level intermediate representation michael@0: // of shaders. This is a tree that parser creates. michael@0: // michael@0: // Nodes in the tree are defined as a hierarchy of classes derived from michael@0: // TIntermNode. Each is a node in a tree. There is no preset branching factor; michael@0: // each node can have it's own type of list of children. michael@0: // michael@0: michael@0: #ifndef __INTERMEDIATE_H michael@0: #define __INTERMEDIATE_H michael@0: michael@0: #include "GLSLANG/ShaderLang.h" michael@0: michael@0: #include michael@0: #include "compiler/Common.h" michael@0: #include "compiler/Types.h" michael@0: #include "compiler/ConstantUnion.h" michael@0: michael@0: // michael@0: // Operators used by the high-level (parse tree) representation. michael@0: // michael@0: enum TOperator { michael@0: EOpNull, // if in a node, should only mean a node is still being built michael@0: EOpSequence, // denotes a list of statements, or parameters, etc. michael@0: EOpFunctionCall, michael@0: EOpFunction, // For function definition michael@0: EOpParameters, // an aggregate listing the parameters to a function michael@0: michael@0: EOpDeclaration, michael@0: EOpPrototype, michael@0: michael@0: // michael@0: // Unary operators michael@0: // michael@0: michael@0: EOpNegative, michael@0: EOpLogicalNot, michael@0: EOpVectorLogicalNot, michael@0: michael@0: EOpPostIncrement, michael@0: EOpPostDecrement, michael@0: EOpPreIncrement, michael@0: EOpPreDecrement, michael@0: michael@0: EOpConvIntToBool, michael@0: EOpConvFloatToBool, michael@0: EOpConvBoolToFloat, michael@0: EOpConvIntToFloat, michael@0: EOpConvFloatToInt, michael@0: EOpConvBoolToInt, michael@0: michael@0: // michael@0: // binary operations michael@0: // michael@0: michael@0: EOpAdd, michael@0: EOpSub, michael@0: EOpMul, michael@0: EOpDiv, michael@0: EOpEqual, michael@0: EOpNotEqual, michael@0: EOpVectorEqual, michael@0: EOpVectorNotEqual, michael@0: EOpLessThan, michael@0: EOpGreaterThan, michael@0: EOpLessThanEqual, michael@0: EOpGreaterThanEqual, michael@0: EOpComma, michael@0: michael@0: EOpVectorTimesScalar, michael@0: EOpVectorTimesMatrix, michael@0: EOpMatrixTimesVector, michael@0: EOpMatrixTimesScalar, michael@0: michael@0: EOpLogicalOr, michael@0: EOpLogicalXor, michael@0: EOpLogicalAnd, michael@0: michael@0: EOpIndexDirect, michael@0: EOpIndexIndirect, michael@0: EOpIndexDirectStruct, michael@0: michael@0: EOpVectorSwizzle, michael@0: michael@0: // michael@0: // Built-in functions potentially mapped to operators michael@0: // michael@0: michael@0: EOpRadians, michael@0: EOpDegrees, michael@0: EOpSin, michael@0: EOpCos, michael@0: EOpTan, michael@0: EOpAsin, michael@0: EOpAcos, michael@0: EOpAtan, michael@0: michael@0: EOpPow, michael@0: EOpExp, michael@0: EOpLog, michael@0: EOpExp2, michael@0: EOpLog2, michael@0: EOpSqrt, michael@0: EOpInverseSqrt, michael@0: michael@0: EOpAbs, michael@0: EOpSign, michael@0: EOpFloor, michael@0: EOpCeil, michael@0: EOpFract, michael@0: EOpMod, michael@0: EOpMin, michael@0: EOpMax, michael@0: EOpClamp, michael@0: EOpMix, michael@0: EOpStep, michael@0: EOpSmoothStep, michael@0: michael@0: EOpLength, michael@0: EOpDistance, michael@0: EOpDot, michael@0: EOpCross, michael@0: EOpNormalize, michael@0: EOpFaceForward, michael@0: EOpReflect, michael@0: EOpRefract, michael@0: michael@0: EOpDFdx, // Fragment only, OES_standard_derivatives extension michael@0: EOpDFdy, // Fragment only, OES_standard_derivatives extension michael@0: EOpFwidth, // Fragment only, OES_standard_derivatives extension michael@0: michael@0: EOpMatrixTimesMatrix, michael@0: michael@0: EOpAny, michael@0: EOpAll, michael@0: michael@0: // michael@0: // Branch michael@0: // michael@0: michael@0: EOpKill, // Fragment only michael@0: EOpReturn, michael@0: EOpBreak, michael@0: EOpContinue, michael@0: michael@0: // michael@0: // Constructors michael@0: // michael@0: michael@0: EOpConstructInt, michael@0: EOpConstructBool, michael@0: EOpConstructFloat, michael@0: EOpConstructVec2, michael@0: EOpConstructVec3, michael@0: EOpConstructVec4, michael@0: EOpConstructBVec2, michael@0: EOpConstructBVec3, michael@0: EOpConstructBVec4, michael@0: EOpConstructIVec2, michael@0: EOpConstructIVec3, michael@0: EOpConstructIVec4, michael@0: EOpConstructMat2, michael@0: EOpConstructMat3, michael@0: EOpConstructMat4, michael@0: EOpConstructStruct, michael@0: michael@0: // michael@0: // moves michael@0: // michael@0: michael@0: EOpAssign, michael@0: EOpInitialize, michael@0: EOpAddAssign, michael@0: EOpSubAssign, michael@0: EOpMulAssign, michael@0: EOpVectorTimesMatrixAssign, michael@0: EOpVectorTimesScalarAssign, michael@0: EOpMatrixTimesScalarAssign, michael@0: EOpMatrixTimesMatrixAssign, michael@0: EOpDivAssign michael@0: }; michael@0: michael@0: extern const char* getOperatorString(TOperator op); michael@0: michael@0: class TIntermTraverser; michael@0: class TIntermAggregate; michael@0: class TIntermBinary; michael@0: class TIntermUnary; michael@0: class TIntermConstantUnion; michael@0: class TIntermSelection; michael@0: class TIntermTyped; michael@0: class TIntermSymbol; michael@0: class TIntermLoop; michael@0: class TInfoSink; michael@0: michael@0: // michael@0: // Base class for the tree nodes michael@0: // michael@0: class TIntermNode { michael@0: public: michael@0: POOL_ALLOCATOR_NEW_DELETE(); michael@0: TIntermNode() { michael@0: // TODO: Move this to TSourceLoc constructor michael@0: // after getting rid of TPublicType. michael@0: line.first_file = line.last_file = 0; michael@0: line.first_line = line.last_line = 0; michael@0: } michael@0: virtual ~TIntermNode() { } michael@0: michael@0: const TSourceLoc& getLine() const { return line; } michael@0: void setLine(const TSourceLoc& l) { line = l; } michael@0: michael@0: virtual void traverse(TIntermTraverser*) = 0; michael@0: virtual TIntermTyped* getAsTyped() { return 0; } michael@0: virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } michael@0: virtual TIntermAggregate* getAsAggregate() { return 0; } michael@0: virtual TIntermBinary* getAsBinaryNode() { return 0; } michael@0: virtual TIntermUnary* getAsUnaryNode() { return 0; } michael@0: virtual TIntermSelection* getAsSelectionNode() { return 0; } michael@0: virtual TIntermSymbol* getAsSymbolNode() { return 0; } michael@0: virtual TIntermLoop* getAsLoopNode() { return 0; } michael@0: michael@0: protected: michael@0: TSourceLoc line; michael@0: }; michael@0: michael@0: // michael@0: // This is just to help yacc. michael@0: // michael@0: struct TIntermNodePair { michael@0: TIntermNode* node1; michael@0: TIntermNode* node2; michael@0: }; michael@0: michael@0: // michael@0: // Intermediate class for nodes that have a type. michael@0: // michael@0: class TIntermTyped : public TIntermNode { michael@0: public: michael@0: TIntermTyped(const TType& t) : type(t) { } michael@0: virtual TIntermTyped* getAsTyped() { return this; } michael@0: michael@0: void setType(const TType& t) { type = t; } michael@0: const TType& getType() const { return type; } michael@0: TType* getTypePointer() { return &type; } michael@0: michael@0: TBasicType getBasicType() const { return type.getBasicType(); } michael@0: TQualifier getQualifier() const { return type.getQualifier(); } michael@0: TPrecision getPrecision() const { return type.getPrecision(); } michael@0: int getNominalSize() const { return type.getNominalSize(); } michael@0: michael@0: bool isMatrix() const { return type.isMatrix(); } michael@0: bool isArray() const { return type.isArray(); } michael@0: bool isVector() const { return type.isVector(); } michael@0: bool isScalar() const { return type.isScalar(); } michael@0: const char* getBasicString() const { return type.getBasicString(); } michael@0: const char* getQualifierString() const { return type.getQualifierString(); } michael@0: TString getCompleteString() const { return type.getCompleteString(); } michael@0: michael@0: int totalRegisterCount() const { return type.totalRegisterCount(); } michael@0: int elementRegisterCount() const { return type.elementRegisterCount(); } michael@0: int getArraySize() const { return type.getArraySize(); } michael@0: michael@0: protected: michael@0: TType type; michael@0: }; michael@0: michael@0: // michael@0: // Handle for, do-while, and while loops. michael@0: // michael@0: enum TLoopType { michael@0: ELoopFor, michael@0: ELoopWhile, michael@0: ELoopDoWhile michael@0: }; michael@0: michael@0: class TIntermLoop : public TIntermNode { michael@0: public: michael@0: TIntermLoop(TLoopType aType, michael@0: TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, michael@0: TIntermNode* aBody) : michael@0: type(aType), michael@0: init(aInit), michael@0: cond(aCond), michael@0: expr(aExpr), michael@0: body(aBody), michael@0: unrollFlag(false) { } michael@0: michael@0: virtual TIntermLoop* getAsLoopNode() { return this; } michael@0: virtual void traverse(TIntermTraverser*); michael@0: michael@0: TLoopType getType() const { return type; } michael@0: TIntermNode* getInit() { return init; } michael@0: TIntermTyped* getCondition() { return cond; } michael@0: TIntermTyped* getExpression() { return expr; } michael@0: TIntermNode* getBody() { return body; } michael@0: michael@0: void setUnrollFlag(bool flag) { unrollFlag = flag; } michael@0: bool getUnrollFlag() { return unrollFlag; } michael@0: michael@0: protected: michael@0: TLoopType type; michael@0: TIntermNode* init; // for-loop initialization michael@0: TIntermTyped* cond; // loop exit condition michael@0: TIntermTyped* expr; // for-loop expression michael@0: TIntermNode* body; // loop body michael@0: michael@0: bool unrollFlag; // Whether the loop should be unrolled or not. michael@0: }; michael@0: michael@0: // michael@0: // Handle break, continue, return, and kill. michael@0: // michael@0: class TIntermBranch : public TIntermNode { michael@0: public: michael@0: TIntermBranch(TOperator op, TIntermTyped* e) : michael@0: flowOp(op), michael@0: expression(e) { } michael@0: michael@0: virtual void traverse(TIntermTraverser*); michael@0: michael@0: TOperator getFlowOp() { return flowOp; } michael@0: TIntermTyped* getExpression() { return expression; } michael@0: michael@0: protected: michael@0: TOperator flowOp; michael@0: TIntermTyped* expression; // non-zero except for "return exp;" statements michael@0: }; michael@0: michael@0: // michael@0: // Nodes that correspond to symbols or constants in the source code. michael@0: // michael@0: class TIntermSymbol : public TIntermTyped { michael@0: public: michael@0: // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from michael@0: // per process globalpoolallocator, then it causes increased memory usage per compile michael@0: // it is essential to use "symbol = sym" to assign to symbol michael@0: TIntermSymbol(int i, const TString& sym, const TType& t) : michael@0: TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; } michael@0: michael@0: int getId() const { return id; } michael@0: const TString& getSymbol() const { return symbol; } michael@0: michael@0: void setId(int newId) { id = newId; } michael@0: void setSymbol(const TString& sym) { symbol = sym; } michael@0: michael@0: const TString& getOriginalSymbol() const { return originalSymbol; } michael@0: michael@0: virtual void traverse(TIntermTraverser*); michael@0: virtual TIntermSymbol* getAsSymbolNode() { return this; } michael@0: michael@0: protected: michael@0: int id; michael@0: TString symbol; michael@0: TString originalSymbol; michael@0: }; michael@0: michael@0: class TIntermConstantUnion : public TIntermTyped { michael@0: public: michael@0: TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } michael@0: michael@0: ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } michael@0: michael@0: int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } michael@0: float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; } michael@0: bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; } michael@0: michael@0: virtual TIntermConstantUnion* getAsConstantUnion() { return this; } michael@0: virtual void traverse(TIntermTraverser*); michael@0: michael@0: TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); michael@0: michael@0: protected: michael@0: ConstantUnion *unionArrayPointer; michael@0: }; michael@0: michael@0: // michael@0: // Intermediate class for node types that hold operators. michael@0: // michael@0: class TIntermOperator : public TIntermTyped { michael@0: public: michael@0: TOperator getOp() const { return op; } michael@0: void setOp(TOperator o) { op = o; } michael@0: michael@0: bool modifiesState() const; michael@0: bool isConstructor() const; michael@0: michael@0: protected: michael@0: TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} michael@0: TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} michael@0: TOperator op; michael@0: }; michael@0: michael@0: // michael@0: // Nodes for all the basic binary math operators. michael@0: // michael@0: class TIntermBinary : public TIntermOperator { michael@0: public: michael@0: TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {} michael@0: michael@0: virtual TIntermBinary* getAsBinaryNode() { return this; } michael@0: virtual void traverse(TIntermTraverser*); michael@0: michael@0: void setLeft(TIntermTyped* n) { left = n; } michael@0: void setRight(TIntermTyped* n) { right = n; } michael@0: TIntermTyped* getLeft() const { return left; } michael@0: TIntermTyped* getRight() const { return right; } michael@0: bool promote(TInfoSink&); michael@0: michael@0: void setAddIndexClamp() { addIndexClamp = true; } michael@0: bool getAddIndexClamp() { return addIndexClamp; } michael@0: michael@0: protected: michael@0: TIntermTyped* left; michael@0: TIntermTyped* right; michael@0: michael@0: // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. michael@0: bool addIndexClamp; michael@0: }; michael@0: michael@0: // michael@0: // Nodes for unary math operators. michael@0: // michael@0: class TIntermUnary : public TIntermOperator { michael@0: public: michael@0: TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {} michael@0: TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {} michael@0: michael@0: virtual void traverse(TIntermTraverser*); michael@0: virtual TIntermUnary* getAsUnaryNode() { return this; } michael@0: michael@0: void setOperand(TIntermTyped* o) { operand = o; } michael@0: TIntermTyped* getOperand() { return operand; } michael@0: bool promote(TInfoSink&); michael@0: michael@0: void setUseEmulatedFunction() { useEmulatedFunction = true; } michael@0: bool getUseEmulatedFunction() { return useEmulatedFunction; } michael@0: michael@0: protected: michael@0: TIntermTyped* operand; michael@0: michael@0: // If set to true, replace the built-in function call with an emulated one michael@0: // to work around driver bugs. michael@0: bool useEmulatedFunction; michael@0: }; michael@0: michael@0: typedef TVector TIntermSequence; michael@0: typedef TVector TQualifierList; michael@0: michael@0: // michael@0: // Nodes that operate on an arbitrary sized set of children. michael@0: // michael@0: class TIntermAggregate : public TIntermOperator { michael@0: public: michael@0: TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { } michael@0: TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { } michael@0: ~TIntermAggregate() { } michael@0: michael@0: virtual TIntermAggregate* getAsAggregate() { return this; } michael@0: virtual void traverse(TIntermTraverser*); michael@0: michael@0: TIntermSequence& getSequence() { return sequence; } michael@0: michael@0: void setName(const TString& n) { name = n; } michael@0: const TString& getName() const { return name; } michael@0: michael@0: void setUserDefined() { userDefined = true; } michael@0: bool isUserDefined() const { return userDefined; } michael@0: michael@0: void setOptimize(bool o) { optimize = o; } michael@0: bool getOptimize() { return optimize; } michael@0: void setDebug(bool d) { debug = d; } michael@0: bool getDebug() { return debug; } michael@0: michael@0: void setUseEmulatedFunction() { useEmulatedFunction = true; } michael@0: bool getUseEmulatedFunction() { return useEmulatedFunction; } michael@0: michael@0: protected: michael@0: TIntermAggregate(const TIntermAggregate&); // disallow copy constructor michael@0: TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator michael@0: TIntermSequence sequence; michael@0: TString name; michael@0: bool userDefined; // used for user defined function names michael@0: michael@0: bool optimize; michael@0: bool debug; michael@0: michael@0: // If set to true, replace the built-in function call with an emulated one michael@0: // to work around driver bugs. michael@0: bool useEmulatedFunction; michael@0: }; michael@0: michael@0: // michael@0: // For if tests. Simplified since there is no switch statement. michael@0: // michael@0: class TIntermSelection : public TIntermTyped { michael@0: public: michael@0: TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : michael@0: TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} michael@0: TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : michael@0: TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} michael@0: michael@0: virtual void traverse(TIntermTraverser*); michael@0: michael@0: bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } michael@0: TIntermNode* getCondition() const { return condition; } michael@0: TIntermNode* getTrueBlock() const { return trueBlock; } michael@0: TIntermNode* getFalseBlock() const { return falseBlock; } michael@0: TIntermSelection* getAsSelectionNode() { return this; } michael@0: michael@0: protected: michael@0: TIntermTyped* condition; michael@0: TIntermNode* trueBlock; michael@0: TIntermNode* falseBlock; michael@0: }; michael@0: michael@0: enum Visit michael@0: { michael@0: PreVisit, michael@0: InVisit, michael@0: PostVisit michael@0: }; michael@0: michael@0: // michael@0: // For traversing the tree. User should derive from this, michael@0: // put their traversal specific data in it, and then pass michael@0: // it to a Traverse method. michael@0: // michael@0: // When using this, just fill in the methods for nodes you want visited. michael@0: // Return false from a pre-visit to skip visiting that node's subtree. michael@0: // michael@0: class TIntermTraverser michael@0: { michael@0: public: michael@0: POOL_ALLOCATOR_NEW_DELETE(); michael@0: TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : michael@0: preVisit(preVisit), michael@0: inVisit(inVisit), michael@0: postVisit(postVisit), michael@0: rightToLeft(rightToLeft), michael@0: depth(0), michael@0: maxDepth(0) {} michael@0: virtual ~TIntermTraverser() {}; michael@0: michael@0: virtual void visitSymbol(TIntermSymbol*) {} michael@0: virtual void visitConstantUnion(TIntermConstantUnion*) {} michael@0: virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} michael@0: virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} michael@0: virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} michael@0: virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} michael@0: virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} michael@0: virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} michael@0: michael@0: int getMaxDepth() const {return maxDepth;} michael@0: void incrementDepth() {depth++; maxDepth = std::max(maxDepth, depth); } michael@0: void decrementDepth() {depth--;} michael@0: michael@0: // Return the original name if hash function pointer is NULL; michael@0: // otherwise return the hashed name. michael@0: static TString hash(const TString& name, ShHashFunction64 hashFunction); michael@0: michael@0: const bool preVisit; michael@0: const bool inVisit; michael@0: const bool postVisit; michael@0: const bool rightToLeft; michael@0: michael@0: protected: michael@0: int depth; michael@0: int maxDepth; michael@0: }; michael@0: michael@0: #endif // __INTERMEDIATE_H