|  | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | // | 
|  | // Definition of the in-memory high-level intermediate representation | 
|  | // of shaders.  This is a tree that parser creates. | 
|  | // | 
|  | // Nodes in the tree are defined as a hierarchy of classes derived from | 
|  | // TIntermNode. Each is a node in a tree.  There is no preset branching factor; | 
|  | // each node can have it's own type of list of children. | 
|  | // | 
|  |  | 
|  | #ifndef __INTERMEDIATE_H | 
|  | #define __INTERMEDIATE_H | 
|  |  | 
|  | #include "Common.h" | 
|  | #include "Types.h" | 
|  | #include "ConstantUnion.h" | 
|  |  | 
|  | // | 
|  | // Operators used by the high-level (parse tree) representation. | 
|  | // | 
|  | enum TOperator { | 
|  | EOpNull,            // if in a node, should only mean a node is still being built | 
|  | EOpSequence,        // denotes a list of statements, or parameters, etc. | 
|  | EOpFunctionCall, | 
|  | EOpFunction,        // For function definition | 
|  | EOpParameters,      // an aggregate listing the parameters to a function | 
|  |  | 
|  | EOpDeclaration, | 
|  | EOpInvariantDeclaration, // Specialized declarations for attributing invariance | 
|  | EOpPrototype, | 
|  |  | 
|  | // | 
|  | // Unary operators | 
|  | // | 
|  |  | 
|  | EOpNegative, | 
|  | EOpLogicalNot, | 
|  | EOpVectorLogicalNot, | 
|  | EOpBitwiseNot, | 
|  |  | 
|  | EOpPostIncrement, | 
|  | EOpPostDecrement, | 
|  | EOpPreIncrement, | 
|  | EOpPreDecrement, | 
|  |  | 
|  | // | 
|  | // binary operations | 
|  | // | 
|  |  | 
|  | EOpAdd, | 
|  | EOpSub, | 
|  | EOpMul, | 
|  | EOpDiv, | 
|  | EOpEqual, | 
|  | EOpNotEqual, | 
|  | EOpVectorEqual, | 
|  | EOpVectorNotEqual, | 
|  | EOpLessThan, | 
|  | EOpGreaterThan, | 
|  | EOpLessThanEqual, | 
|  | EOpGreaterThanEqual, | 
|  | EOpComma, | 
|  |  | 
|  | EOpOuterProduct, | 
|  | EOpTranspose, | 
|  | EOpDeterminant, | 
|  | EOpInverse, | 
|  |  | 
|  | EOpVectorTimesScalar, | 
|  | EOpVectorTimesMatrix, | 
|  | EOpMatrixTimesVector, | 
|  | EOpMatrixTimesScalar, | 
|  |  | 
|  | EOpLogicalOr, | 
|  | EOpLogicalXor, | 
|  | EOpLogicalAnd, | 
|  |  | 
|  | EOpIMod, | 
|  | EOpBitShiftLeft, | 
|  | EOpBitShiftRight, | 
|  | EOpBitwiseAnd, | 
|  | EOpBitwiseXor, | 
|  | EOpBitwiseOr, | 
|  |  | 
|  | EOpIndexDirect, | 
|  | EOpIndexIndirect, | 
|  | EOpIndexDirectStruct, | 
|  | EOpIndexDirectInterfaceBlock, | 
|  |  | 
|  | EOpVectorSwizzle, | 
|  |  | 
|  | // | 
|  | // Built-in functions potentially mapped to operators | 
|  | // | 
|  |  | 
|  | EOpRadians, | 
|  | EOpDegrees, | 
|  | EOpSin, | 
|  | EOpCos, | 
|  | EOpTan, | 
|  | EOpAsin, | 
|  | EOpAcos, | 
|  | EOpAtan, | 
|  | EOpSinh, | 
|  | EOpCosh, | 
|  | EOpTanh, | 
|  | EOpAsinh, | 
|  | EOpAcosh, | 
|  | EOpAtanh, | 
|  |  | 
|  | EOpPow, | 
|  | EOpExp, | 
|  | EOpLog, | 
|  | EOpExp2, | 
|  | EOpLog2, | 
|  | EOpSqrt, | 
|  | EOpInverseSqrt, | 
|  |  | 
|  | EOpAbs, | 
|  | EOpSign, | 
|  | EOpFloor, | 
|  | EOpTrunc, | 
|  | EOpRound, | 
|  | EOpRoundEven, | 
|  | EOpCeil, | 
|  | EOpFract, | 
|  | EOpMod, | 
|  | EOpModf, | 
|  | EOpMin, | 
|  | EOpMax, | 
|  | EOpClamp, | 
|  | EOpMix, | 
|  | EOpStep, | 
|  | EOpSmoothStep, | 
|  | EOpIsNan, | 
|  | EOpIsInf, | 
|  | EOpFloatBitsToInt, | 
|  | EOpFloatBitsToUint, | 
|  | EOpIntBitsToFloat, | 
|  | EOpUintBitsToFloat, | 
|  | EOpPackSnorm2x16, | 
|  | EOpPackUnorm2x16, | 
|  | EOpPackHalf2x16, | 
|  | EOpUnpackSnorm2x16, | 
|  | EOpUnpackUnorm2x16, | 
|  | EOpUnpackHalf2x16, | 
|  |  | 
|  | EOpLength, | 
|  | EOpDistance, | 
|  | EOpDot, | 
|  | EOpCross, | 
|  | EOpNormalize, | 
|  | EOpFaceForward, | 
|  | EOpReflect, | 
|  | EOpRefract, | 
|  |  | 
|  | EOpDFdx,            // Fragment only, OES_standard_derivatives extension | 
|  | EOpDFdy,            // Fragment only, OES_standard_derivatives extension | 
|  | EOpFwidth,          // Fragment only, OES_standard_derivatives extension | 
|  |  | 
|  | EOpMatrixTimesMatrix, | 
|  |  | 
|  | EOpAny, | 
|  | EOpAll, | 
|  |  | 
|  | // | 
|  | // Branch | 
|  | // | 
|  |  | 
|  | EOpKill,            // Fragment only | 
|  | EOpReturn, | 
|  | EOpBreak, | 
|  | EOpContinue, | 
|  |  | 
|  | // | 
|  | // Constructors | 
|  | // | 
|  |  | 
|  | EOpConstructInt, | 
|  | EOpConstructUInt, | 
|  | EOpConstructBool, | 
|  | EOpConstructFloat, | 
|  | EOpConstructVec2, | 
|  | EOpConstructVec3, | 
|  | EOpConstructVec4, | 
|  | EOpConstructBVec2, | 
|  | EOpConstructBVec3, | 
|  | EOpConstructBVec4, | 
|  | EOpConstructIVec2, | 
|  | EOpConstructIVec3, | 
|  | EOpConstructIVec4, | 
|  | EOpConstructUVec2, | 
|  | EOpConstructUVec3, | 
|  | EOpConstructUVec4, | 
|  | EOpConstructMat2, | 
|  | EOpConstructMat2x3, | 
|  | EOpConstructMat2x4, | 
|  | EOpConstructMat3x2, | 
|  | EOpConstructMat3, | 
|  | EOpConstructMat3x4, | 
|  | EOpConstructMat4x2, | 
|  | EOpConstructMat4x3, | 
|  | EOpConstructMat4, | 
|  | EOpConstructStruct, | 
|  |  | 
|  | // | 
|  | // moves | 
|  | // | 
|  |  | 
|  | EOpAssign, | 
|  | EOpInitialize, | 
|  | EOpAddAssign, | 
|  | EOpSubAssign, | 
|  | EOpMulAssign, | 
|  | EOpVectorTimesMatrixAssign, | 
|  | EOpVectorTimesScalarAssign, | 
|  | EOpMatrixTimesScalarAssign, | 
|  | EOpMatrixTimesMatrixAssign, | 
|  | EOpDivAssign, | 
|  | EOpIModAssign, | 
|  | EOpBitShiftLeftAssign, | 
|  | EOpBitShiftRightAssign, | 
|  | EOpBitwiseAndAssign, | 
|  | EOpBitwiseXorAssign, | 
|  | EOpBitwiseOrAssign | 
|  | }; | 
|  |  | 
|  | extern TOperator TypeToConstructorOperator(const TType &type); | 
|  | extern const char* getOperatorString(TOperator op); | 
|  |  | 
|  | class TIntermTraverser; | 
|  | class TIntermAggregate; | 
|  | class TIntermBinary; | 
|  | class TIntermUnary; | 
|  | class TIntermConstantUnion; | 
|  | class TIntermSelection; | 
|  | class TIntermTyped; | 
|  | class TIntermSymbol; | 
|  | class TIntermLoop; | 
|  | class TIntermBranch; | 
|  | class TInfoSink; | 
|  | class TIntermSwitch; | 
|  | class TIntermCase; | 
|  |  | 
|  | // | 
|  | // Base class for the tree nodes | 
|  | // | 
|  | class TIntermNode { | 
|  | public: | 
|  | POOL_ALLOCATOR_NEW_DELETE(); | 
|  |  | 
|  | TIntermNode() | 
|  | { | 
|  | // TODO: Move this to TSourceLoc constructor | 
|  | // after getting rid of TPublicType. | 
|  | line.first_file = line.last_file = 0; | 
|  | line.first_line = line.last_line = 0; | 
|  | } | 
|  |  | 
|  | const TSourceLoc& getLine() const { return line; } | 
|  | void setLine(const TSourceLoc& l) { line = l; } | 
|  |  | 
|  | virtual void traverse(TIntermTraverser*) = 0; | 
|  | virtual TIntermTyped* getAsTyped() { return 0; } | 
|  | virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } | 
|  | virtual TIntermAggregate* getAsAggregate() { return 0; } | 
|  | virtual TIntermBinary* getAsBinaryNode() { return 0; } | 
|  | virtual TIntermUnary* getAsUnaryNode() { return 0; } | 
|  | virtual TIntermSelection* getAsSelectionNode() { return 0; } | 
|  | virtual TIntermSymbol* getAsSymbolNode() { return 0; } | 
|  | virtual TIntermLoop* getAsLoopNode() { return 0; } | 
|  | virtual TIntermBranch* getAsBranchNode() { return 0; } | 
|  | virtual TIntermSwitch *getAsSwitchNode() { return 0; } | 
|  | virtual TIntermCase *getAsCaseNode() { return 0; } | 
|  | virtual ~TIntermNode() { } | 
|  |  | 
|  | protected: | 
|  | TSourceLoc line; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // This is just to help yacc. | 
|  | // | 
|  | struct TIntermNodePair { | 
|  | TIntermNode* node1; | 
|  | TIntermNode* node2; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Intermediate class for nodes that have a type. | 
|  | // | 
|  | class TIntermTyped : public TIntermNode { | 
|  | public: | 
|  | TIntermTyped(const TType& t) : type(t)  { } | 
|  | virtual TIntermTyped* getAsTyped() { return this; } | 
|  |  | 
|  | virtual void setType(const TType& t) { type = t; } | 
|  | const TType& getType() const { return type; } | 
|  | TType* getTypePointer() { return &type; } | 
|  |  | 
|  | TBasicType getBasicType() const { return type.getBasicType(); } | 
|  | TQualifier getQualifier() const { return type.getQualifier(); } | 
|  | TPrecision getPrecision() const { return type.getPrecision(); } | 
|  | int getNominalSize() const { return type.getNominalSize(); } | 
|  | int getSecondarySize() const { return type.getSecondarySize(); } | 
|  |  | 
|  | bool isInterfaceBlock() const { return type.isInterfaceBlock(); } | 
|  | bool isMatrix() const { return type.isMatrix(); } | 
|  | bool isArray()  const { return type.isArray(); } | 
|  | bool isVector() const { return type.isVector(); } | 
|  | bool isScalar() const { return type.isScalar(); } | 
|  | bool isScalarInt() const { return type.isScalarInt(); } | 
|  | bool isRegister() const { return type.isRegister(); }   // Fits in a 4-element register | 
|  | bool isStruct() const { return type.isStruct(); } | 
|  | const char* getBasicString() const { return type.getBasicString(); } | 
|  | const char* getQualifierString() const { return type.getQualifierString(); } | 
|  | TString getCompleteString() const { return type.getCompleteString(); } | 
|  |  | 
|  | int totalRegisterCount() const { return type.totalRegisterCount(); } | 
|  | int blockRegisterCount(bool samplersOnly) const { return samplersOnly ? type.totalSamplerRegisterCount() : type.blockRegisterCount(); } | 
|  | int elementRegisterCount() const { return type.elementRegisterCount(); } | 
|  | int registerSize() const { return type.registerSize(); } | 
|  | int getArraySize() const { return type.getArraySize(); } | 
|  |  | 
|  | static TIntermTyped *CreateIndexNode(int index); | 
|  | protected: | 
|  | TType type; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Handle for, do-while, and while loops. | 
|  | // | 
|  | enum TLoopType { | 
|  | ELoopFor, | 
|  | ELoopWhile, | 
|  | ELoopDoWhile | 
|  | }; | 
|  |  | 
|  | class TIntermLoop : public TIntermNode { | 
|  | public: | 
|  | TIntermLoop(TLoopType aType, | 
|  | TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, | 
|  | TIntermNode* aBody) : | 
|  | type(aType), | 
|  | init(aInit), | 
|  | cond(aCond), | 
|  | expr(aExpr), | 
|  | body(aBody), | 
|  | unrollFlag(false) { } | 
|  |  | 
|  | virtual TIntermLoop* getAsLoopNode() { return this; } | 
|  | virtual void traverse(TIntermTraverser*); | 
|  |  | 
|  | TLoopType getType() const { return type; } | 
|  | TIntermNode* getInit() { return init; } | 
|  | TIntermTyped* getCondition() { return cond; } | 
|  | TIntermTyped* getExpression() { return expr; } | 
|  | TIntermNode* getBody() { return body; } | 
|  |  | 
|  | void setUnrollFlag(bool flag) { unrollFlag = flag; } | 
|  | bool getUnrollFlag() { return unrollFlag; } | 
|  |  | 
|  | protected: | 
|  | TLoopType type; | 
|  | TIntermNode* init;  // for-loop initialization | 
|  | TIntermTyped* cond; // loop exit condition | 
|  | TIntermTyped* expr; // for-loop expression | 
|  | TIntermNode* body;  // loop body | 
|  |  | 
|  | bool unrollFlag; // Whether the loop should be unrolled or not. | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Handle break, continue, return, and kill. | 
|  | // | 
|  | class TIntermBranch : public TIntermNode { | 
|  | public: | 
|  | TIntermBranch(TOperator op, TIntermTyped* e) : | 
|  | flowOp(op), | 
|  | expression(e) { } | 
|  |  | 
|  | virtual TIntermBranch* getAsBranchNode() { return this; } | 
|  | virtual void traverse(TIntermTraverser*); | 
|  |  | 
|  | TOperator getFlowOp() { return flowOp; } | 
|  | TIntermTyped* getExpression() { return expression; } | 
|  |  | 
|  | protected: | 
|  | TOperator flowOp; | 
|  | TIntermTyped* expression;  // non-zero except for "return exp;" statements | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Nodes that correspond to symbols or constants in the source code. | 
|  | // | 
|  | class TIntermSymbol : public TIntermTyped { | 
|  | public: | 
|  | // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from | 
|  | // per process globalpoolallocator, then it causes increased memory usage per compile | 
|  | // it is essential to use "symbol = sym" to assign to symbol | 
|  | TIntermSymbol(int i, const TString& sym, const TType& t) : | 
|  | TIntermTyped(t), id(i)  { symbol = sym; } | 
|  |  | 
|  | int getId() const { return id; } | 
|  | const TString& getSymbol() const { return symbol; } | 
|  |  | 
|  | void setId(int newId) { id = newId; } | 
|  |  | 
|  | virtual void traverse(TIntermTraverser*); | 
|  | virtual TIntermSymbol* getAsSymbolNode() { return this; } | 
|  |  | 
|  | protected: | 
|  | int id; | 
|  | TString symbol; | 
|  | }; | 
|  |  | 
|  | class TIntermConstantUnion : public TIntermTyped { | 
|  | public: | 
|  | TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) | 
|  | { | 
|  | getTypePointer()->setQualifier(EvqConstExpr); | 
|  | } | 
|  |  | 
|  | ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } | 
|  |  | 
|  | int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } | 
|  | int getUConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getUConst() : 0; } | 
|  | float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; } | 
|  | bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; } | 
|  |  | 
|  | // Previous union pointer freed on pool deallocation. | 
|  | void replaceConstantUnion(ConstantUnion *safeConstantUnion) { unionArrayPointer = safeConstantUnion; } | 
|  |  | 
|  | virtual TIntermConstantUnion* getAsConstantUnion()  { return this; } | 
|  | virtual void traverse(TIntermTraverser*); | 
|  |  | 
|  | TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); | 
|  |  | 
|  | protected: | 
|  | ConstantUnion *unionArrayPointer; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Intermediate class for node types that hold operators. | 
|  | // | 
|  | class TIntermOperator : public TIntermTyped { | 
|  | public: | 
|  | TOperator getOp() const { return op; } | 
|  | void setOp(TOperator o) { op = o; } | 
|  |  | 
|  | bool modifiesState() const; | 
|  | bool isConstructor() const; | 
|  |  | 
|  | protected: | 
|  | TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} | 
|  | TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} | 
|  | TOperator op; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Nodes for all the basic binary math operators. | 
|  | // | 
|  | class TIntermBinary : public TIntermOperator { | 
|  | public: | 
|  | TIntermBinary(TOperator o) : TIntermOperator(o) {} | 
|  |  | 
|  | TIntermBinary* getAsBinaryNode() override { return this; } | 
|  | void traverse(TIntermTraverser*) override; | 
|  |  | 
|  | void setType(const TType &t) override | 
|  | { | 
|  | type = t; | 
|  |  | 
|  | if(left->getQualifier() == EvqConstExpr && right->getQualifier() == EvqConstExpr) | 
|  | { | 
|  | type.setQualifier(EvqConstExpr); | 
|  | } | 
|  | } | 
|  |  | 
|  | void setLeft(TIntermTyped* n) { left = n; } | 
|  | void setRight(TIntermTyped* n) { right = n; } | 
|  | TIntermTyped* getLeft() const { return left; } | 
|  | TIntermTyped* getRight() const { return right; } | 
|  | bool promote(TInfoSink&); | 
|  |  | 
|  | protected: | 
|  | TIntermTyped* left; | 
|  | TIntermTyped* right; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Nodes for unary math operators. | 
|  | // | 
|  | class TIntermUnary : public TIntermOperator { | 
|  | public: | 
|  | TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {} | 
|  | TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {} | 
|  |  | 
|  | void setType(const TType &t) override | 
|  | { | 
|  | type = t; | 
|  |  | 
|  | if(operand->getQualifier() == EvqConstExpr) | 
|  | { | 
|  | type.setQualifier(EvqConstExpr); | 
|  | } | 
|  | } | 
|  |  | 
|  | void traverse(TIntermTraverser*) override; | 
|  | TIntermUnary* getAsUnaryNode() override { return this; } | 
|  |  | 
|  | void setOperand(TIntermTyped* o) { operand = o; } | 
|  | TIntermTyped* getOperand() { return operand; } | 
|  | bool promote(TInfoSink&, const TType *funcReturnType); | 
|  |  | 
|  | protected: | 
|  | TIntermTyped* operand; | 
|  | }; | 
|  |  | 
|  | typedef TVector<TIntermNode*> TIntermSequence; | 
|  | typedef TVector<int> TQualifierList; | 
|  |  | 
|  | // | 
|  | // Nodes that operate on an arbitrary sized set of children. | 
|  | // | 
|  | class TIntermAggregate : public TIntermOperator { | 
|  | public: | 
|  | TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false) { endLine = { 0, 0, 0, 0 }; } | 
|  | TIntermAggregate(TOperator o) : TIntermOperator(o), userDefined(false) { endLine = { 0, 0, 0, 0 }; } | 
|  | ~TIntermAggregate() { } | 
|  |  | 
|  | TIntermAggregate* getAsAggregate() override { return this; } | 
|  | void traverse(TIntermTraverser*) override; | 
|  |  | 
|  | TIntermSequence& getSequence() { return sequence; } | 
|  |  | 
|  | void setType(const TType &t) override | 
|  | { | 
|  | type = t; | 
|  |  | 
|  | if(op != EOpFunctionCall) | 
|  | { | 
|  | for(TIntermNode *node : sequence) | 
|  | { | 
|  | if(!node->getAsTyped() || node->getAsTyped()->getQualifier() != EvqConstExpr) | 
|  | { | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | type.setQualifier(EvqConstExpr); | 
|  | } | 
|  | } | 
|  |  | 
|  | void setName(const TString& n) { name = n; } | 
|  | const TString& getName() const { return name; } | 
|  |  | 
|  | void setUserDefined() { userDefined = true; } | 
|  | bool isUserDefined() const { return userDefined; } | 
|  |  | 
|  | void setOptimize(bool o) { optimize = o; } | 
|  | bool getOptimize() { return optimize; } | 
|  | void setDebug(bool d) { debug = d; } | 
|  | bool getDebug() { return debug; } | 
|  |  | 
|  | void setEndLine(const TSourceLoc& line) { endLine = line; } | 
|  | const TSourceLoc& getEndLine() const { return endLine; } | 
|  |  | 
|  | bool isConstantFoldable() | 
|  | { | 
|  | for(TIntermNode *node : sequence) | 
|  | { | 
|  | if(!node->getAsConstantUnion() || !node->getAsConstantUnion()->getUnionArrayPointer()) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | TIntermAggregate(const TIntermAggregate&); // disallow copy constructor | 
|  | TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator | 
|  | TIntermSequence sequence; | 
|  | TString name; | 
|  | bool userDefined; // used for user defined function names | 
|  |  | 
|  | bool optimize; | 
|  | bool debug; | 
|  | TSourceLoc endLine; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // For if tests.  Simplified since there is no switch statement. | 
|  | // | 
|  | class TIntermSelection : public TIntermTyped { | 
|  | public: | 
|  | TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : | 
|  | TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} | 
|  | TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : | 
|  | TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) | 
|  | { | 
|  | this->type.setQualifier(EvqTemporary); | 
|  | } | 
|  |  | 
|  | virtual void traverse(TIntermTraverser*); | 
|  |  | 
|  | bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } | 
|  | TIntermTyped* getCondition() const { return condition; } | 
|  | TIntermNode* getTrueBlock() const { return trueBlock; } | 
|  | TIntermNode* getFalseBlock() const { return falseBlock; } | 
|  | TIntermSelection* getAsSelectionNode() { return this; } | 
|  |  | 
|  | protected: | 
|  | TIntermTyped* condition; | 
|  | TIntermNode* trueBlock; | 
|  | TIntermNode* falseBlock; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Switch statement. | 
|  | // | 
|  | class TIntermSwitch : public TIntermNode | 
|  | { | 
|  | public: | 
|  | TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList) | 
|  | : TIntermNode(), mInit(init), mStatementList(statementList) | 
|  | {} | 
|  |  | 
|  | void traverse(TIntermTraverser *it); | 
|  |  | 
|  | TIntermSwitch *getAsSwitchNode() { return this; } | 
|  |  | 
|  | TIntermTyped *getInit() { return mInit; } | 
|  | TIntermAggregate *getStatementList() { return mStatementList; } | 
|  | void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; } | 
|  |  | 
|  | protected: | 
|  | TIntermTyped *mInit; | 
|  | TIntermAggregate *mStatementList; | 
|  | }; | 
|  |  | 
|  | // | 
|  | // Case label. | 
|  | // | 
|  | class TIntermCase : public TIntermNode | 
|  | { | 
|  | public: | 
|  | TIntermCase(TIntermTyped *condition) | 
|  | : TIntermNode(), mCondition(condition) | 
|  | {} | 
|  |  | 
|  | void traverse(TIntermTraverser *it); | 
|  |  | 
|  | TIntermCase *getAsCaseNode() { return this; } | 
|  |  | 
|  | bool hasCondition() const { return mCondition != nullptr; } | 
|  | TIntermTyped *getCondition() const { return mCondition; } | 
|  |  | 
|  | protected: | 
|  | TIntermTyped *mCondition; | 
|  | }; | 
|  |  | 
|  | enum Visit | 
|  | { | 
|  | PreVisit, | 
|  | InVisit, | 
|  | PostVisit | 
|  | }; | 
|  |  | 
|  | // | 
|  | // For traversing the tree.  User should derive from this, | 
|  | // put their traversal specific data in it, and then pass | 
|  | // it to a Traverse method. | 
|  | // | 
|  | // When using this, just fill in the methods for nodes you want visited. | 
|  | // Return false from a pre-visit to skip visiting that node's subtree. | 
|  | // | 
|  | class TIntermTraverser | 
|  | { | 
|  | public: | 
|  | POOL_ALLOCATOR_NEW_DELETE(); | 
|  | TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : | 
|  | preVisit(preVisit), | 
|  | inVisit(inVisit), | 
|  | postVisit(postVisit), | 
|  | rightToLeft(rightToLeft), | 
|  | mDepth(0) {} | 
|  | virtual ~TIntermTraverser() {}; | 
|  |  | 
|  | virtual void visitSymbol(TIntermSymbol*) {} | 
|  | virtual void visitConstantUnion(TIntermConstantUnion*) {} | 
|  | virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} | 
|  | virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} | 
|  | virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} | 
|  | virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} | 
|  | virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} | 
|  | virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} | 
|  | virtual bool visitSwitch(Visit, TIntermSwitch*) { return true; } | 
|  | virtual bool visitCase(Visit, TIntermCase*) { return true; } | 
|  |  | 
|  | void incrementDepth(TIntermNode *current) | 
|  | { | 
|  | mDepth++; | 
|  | mPath.push_back(current); | 
|  | } | 
|  |  | 
|  | void decrementDepth() | 
|  | { | 
|  | mDepth--; | 
|  | mPath.pop_back(); | 
|  | } | 
|  |  | 
|  | TIntermNode *getParentNode() | 
|  | { | 
|  | return mPath.size() == 0 ? nullptr : mPath.back(); | 
|  | } | 
|  |  | 
|  | const bool preVisit; | 
|  | const bool inVisit; | 
|  | const bool postVisit; | 
|  | const bool rightToLeft; | 
|  |  | 
|  | protected: | 
|  | int mDepth; | 
|  |  | 
|  | // All the nodes from root to the current node's parent during traversing. | 
|  | TVector<TIntermNode *> mPath; | 
|  |  | 
|  | private: | 
|  | struct ParentBlock | 
|  | { | 
|  | ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn) | 
|  | : node(nodeIn), pos(posIn) | 
|  | {} | 
|  |  | 
|  | TIntermAggregate *node; | 
|  | TIntermSequence::size_type pos; | 
|  | }; | 
|  | // All the code blocks from the root to the current node's parent during traversal. | 
|  | std::vector<ParentBlock> mParentBlockStack; | 
|  | }; | 
|  |  | 
|  | #endif // __INTERMEDIATE_H |