| // | |
| // Copyright 2002 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // | |
| // 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 COMPILER_TRANSLATOR_INTERMNODE_H_ | |
| #define COMPILER_TRANSLATOR_INTERMNODE_H_ | |
| #include "GLSLANG/ShaderLang.h" | |
| #include <algorithm> | |
| #include <queue> | |
| #include "common/angleutils.h" | |
| #include "compiler/translator/Common.h" | |
| #include "compiler/translator/ConstantUnion.h" | |
| #include "compiler/translator/ImmutableString.h" | |
| #include "compiler/translator/Operator.h" | |
| #include "compiler/translator/SymbolUniqueId.h" | |
| #include "compiler/translator/Types.h" | |
| #include "compiler/translator/tree_util/Visit.h" | |
| namespace sh | |
| { | |
| class TDiagnostics; | |
| class TIntermTraverser; | |
| class TIntermAggregate; | |
| class TIntermBlock; | |
| class TIntermGlobalQualifierDeclaration; | |
| class TIntermDeclaration; | |
| class TIntermFunctionPrototype; | |
| class TIntermFunctionDefinition; | |
| class TIntermSwizzle; | |
| class TIntermBinary; | |
| class TIntermUnary; | |
| class TIntermConstantUnion; | |
| class TIntermTernary; | |
| class TIntermIfElse; | |
| class TIntermSwitch; | |
| class TIntermCase; | |
| class TIntermTyped; | |
| class TIntermSymbol; | |
| class TIntermLoop; | |
| class TInfoSink; | |
| class TInfoSinkBase; | |
| class TIntermBranch; | |
| class TIntermPreprocessorDirective; | |
| class TSymbolTable; | |
| class TFunction; | |
| class TVariable; | |
| // | |
| // Base class for the tree nodes | |
| // | |
| class TIntermNode : angle::NonCopyable | |
| { | |
| public: | |
| POOL_ALLOCATOR_NEW_DELETE | |
| TIntermNode() | |
| { | |
| // TODO: Move this to TSourceLoc constructor | |
| // after getting rid of TPublicType. | |
| mLine.first_file = mLine.last_file = 0; | |
| mLine.first_line = mLine.last_line = 0; | |
| } | |
| virtual ~TIntermNode() {} | |
| const TSourceLoc &getLine() const { return mLine; } | |
| void setLine(const TSourceLoc &l) { mLine = l; } | |
| virtual void traverse(TIntermTraverser *it); | |
| virtual bool visit(Visit visit, TIntermTraverser *it) = 0; | |
| virtual TIntermTyped *getAsTyped() { return nullptr; } | |
| virtual TIntermConstantUnion *getAsConstantUnion() { return nullptr; } | |
| virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; } | |
| virtual TIntermAggregate *getAsAggregate() { return nullptr; } | |
| virtual TIntermBlock *getAsBlock() { return nullptr; } | |
| virtual TIntermFunctionPrototype *getAsFunctionPrototypeNode() { return nullptr; } | |
| virtual TIntermGlobalQualifierDeclaration *getAsGlobalQualifierDeclarationNode() | |
| { | |
| return nullptr; | |
| } | |
| virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; } | |
| virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; } | |
| virtual TIntermBinary *getAsBinaryNode() { return nullptr; } | |
| virtual TIntermUnary *getAsUnaryNode() { return nullptr; } | |
| virtual TIntermTernary *getAsTernaryNode() { return nullptr; } | |
| virtual TIntermIfElse *getAsIfElseNode() { return nullptr; } | |
| virtual TIntermSwitch *getAsSwitchNode() { return nullptr; } | |
| virtual TIntermCase *getAsCaseNode() { return nullptr; } | |
| virtual TIntermSymbol *getAsSymbolNode() { return nullptr; } | |
| virtual TIntermLoop *getAsLoopNode() { return nullptr; } | |
| virtual TIntermBranch *getAsBranchNode() { return nullptr; } | |
| virtual TIntermPreprocessorDirective *getAsPreprocessorDirective() { return nullptr; } | |
| virtual TIntermNode *deepCopy() const = 0; | |
| virtual size_t getChildCount() const = 0; | |
| virtual TIntermNode *getChildNode(size_t index) const = 0; | |
| // Replace a child node. Return true if |original| is a child | |
| // node and it is replaced; otherwise, return false. | |
| virtual bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) = 0; | |
| protected: | |
| TSourceLoc mLine; | |
| }; | |
| // | |
| // 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() {} | |
| virtual TIntermTyped *deepCopy() const override = 0; | |
| TIntermTyped *getAsTyped() override { return this; } | |
| virtual TIntermTyped *fold(TDiagnostics *diagnostics) { return this; } | |
| // getConstantValue() returns the constant value that this node represents, if any. It | |
| // should only be used after nodes have been replaced with their folded versions returned | |
| // from fold(). hasConstantValue() returns true if getConstantValue() will return a value. | |
| virtual bool hasConstantValue() const; | |
| virtual const TConstantUnion *getConstantValue() const; | |
| // True if executing the expression represented by this node affects state, like values of | |
| // variables. False if the executing the expression only computes its return value without | |
| // affecting state. May return true conservatively. | |
| virtual bool hasSideEffects() const = 0; | |
| virtual const TType &getType() const = 0; | |
| TBasicType getBasicType() const { return getType().getBasicType(); } | |
| TQualifier getQualifier() const { return getType().getQualifier(); } | |
| TPrecision getPrecision() const { return getType().getPrecision(); } | |
| TMemoryQualifier getMemoryQualifier() const { return getType().getMemoryQualifier(); } | |
| int getCols() const { return getType().getCols(); } | |
| int getRows() const { return getType().getRows(); } | |
| int getNominalSize() const { return getType().getNominalSize(); } | |
| int getSecondarySize() const { return getType().getSecondarySize(); } | |
| bool isInterfaceBlock() const { return getType().isInterfaceBlock(); } | |
| bool isMatrix() const { return getType().isMatrix(); } | |
| bool isArray() const { return getType().isArray(); } | |
| bool isVector() const { return getType().isVector(); } | |
| bool isScalar() const { return getType().isScalar(); } | |
| bool isScalarInt() const { return getType().isScalarInt(); } | |
| const char *getBasicString() const { return getType().getBasicString(); } | |
| unsigned int getOutermostArraySize() const { return getType().getOutermostArraySize(); } | |
| protected: | |
| TIntermTyped(const TIntermTyped &node); | |
| }; | |
| // | |
| // Handle for, do-while, and while loops. | |
| // | |
| enum TLoopType | |
| { | |
| ELoopFor, | |
| ELoopWhile, | |
| ELoopDoWhile | |
| }; | |
| class TIntermLoop : public TIntermNode | |
| { | |
| public: | |
| TIntermLoop(TLoopType type, | |
| TIntermNode *init, | |
| TIntermTyped *cond, | |
| TIntermTyped *expr, | |
| TIntermBlock *body); | |
| TIntermLoop *getAsLoopNode() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TLoopType getType() const { return mType; } | |
| TIntermNode *getInit() { return mInit; } | |
| TIntermTyped *getCondition() { return mCond; } | |
| TIntermTyped *getExpression() { return mExpr; } | |
| TIntermBlock *getBody() { return mBody; } | |
| void setInit(TIntermNode *init) { mInit = init; } | |
| void setCondition(TIntermTyped *condition) { mCond = condition; } | |
| void setExpression(TIntermTyped *expression) { mExpr = expression; } | |
| void setBody(TIntermBlock *body) { mBody = body; } | |
| virtual TIntermLoop *deepCopy() const override { return new TIntermLoop(*this); } | |
| protected: | |
| TLoopType mType; | |
| TIntermNode *mInit; // for-loop initialization | |
| TIntermTyped *mCond; // loop exit condition | |
| TIntermTyped *mExpr; // for-loop expression | |
| TIntermBlock *mBody; // loop body | |
| private: | |
| TIntermLoop(const TIntermLoop &); | |
| }; | |
| // | |
| // Handle break, continue, return, and kill. | |
| // | |
| class TIntermBranch : public TIntermNode | |
| { | |
| public: | |
| TIntermBranch(TOperator op, TIntermTyped *e) : mFlowOp(op), mExpression(e) {} | |
| TIntermBranch *getAsBranchNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TOperator getFlowOp() { return mFlowOp; } | |
| TIntermTyped *getExpression() { return mExpression; } | |
| virtual TIntermBranch *deepCopy() const override { return new TIntermBranch(*this); } | |
| protected: | |
| TOperator mFlowOp; | |
| TIntermTyped *mExpression; // zero except for "return exp;" statements | |
| private: | |
| TIntermBranch(const TIntermBranch &); | |
| }; | |
| // Nodes that correspond to variable symbols in the source code. These may be regular variables or | |
| // interface block instances. In declarations that only declare a struct type but no variables, a | |
| // TIntermSymbol node with an empty variable is used to store the type. | |
| class TIntermSymbol : public TIntermTyped | |
| { | |
| public: | |
| TIntermSymbol(const TVariable *variable); | |
| TIntermTyped *deepCopy() const override { return new TIntermSymbol(*this); } | |
| bool hasConstantValue() const override; | |
| const TConstantUnion *getConstantValue() const override; | |
| bool hasSideEffects() const override { return false; } | |
| const TType &getType() const override; | |
| const TSymbolUniqueId &uniqueId() const; | |
| ImmutableString getName() const; | |
| const TVariable &variable() const { return *mVariable; } | |
| TIntermSymbol *getAsSymbolNode() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } | |
| private: | |
| TIntermSymbol(const TIntermSymbol &) = default; // Note: not deleted, just private! | |
| const TVariable *const mVariable; // Guaranteed to be non-null | |
| }; | |
| // A typed expression that is not just representing a symbol table symbol. | |
| class TIntermExpression : public TIntermTyped | |
| { | |
| public: | |
| TIntermExpression(const TType &t); | |
| const TType &getType() const override { return mType; } | |
| protected: | |
| TType *getTypePointer() { return &mType; } | |
| void setType(const TType &t) { mType = t; } | |
| void setTypePreservePrecision(const TType &t); | |
| TIntermExpression(const TIntermExpression &node) = default; | |
| TType mType; | |
| }; | |
| // Constant folded node. | |
| // Note that nodes may be constant folded and not be constant expressions with the EvqConst | |
| // qualifier. This happens for example when the following expression is processed: | |
| // "true ? 1.0 : non_constant" | |
| // Other nodes than TIntermConstantUnion may also be constant expressions. | |
| // | |
| class TIntermConstantUnion : public TIntermExpression | |
| { | |
| public: | |
| TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type) | |
| : TIntermExpression(type), mUnionArrayPointer(unionPointer) | |
| { | |
| ASSERT(unionPointer); | |
| } | |
| TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); } | |
| bool hasConstantValue() const override; | |
| const TConstantUnion *getConstantValue() const override; | |
| bool hasSideEffects() const override { return false; } | |
| int getIConst(size_t index) const | |
| { | |
| return mUnionArrayPointer ? mUnionArrayPointer[index].getIConst() : 0; | |
| } | |
| unsigned int getUConst(size_t index) const | |
| { | |
| return mUnionArrayPointer ? mUnionArrayPointer[index].getUConst() : 0; | |
| } | |
| float getFConst(size_t index) const | |
| { | |
| return mUnionArrayPointer ? mUnionArrayPointer[index].getFConst() : 0.0f; | |
| } | |
| bool getBConst(size_t index) const | |
| { | |
| return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false; | |
| } | |
| bool isZero(size_t index) const | |
| { | |
| return mUnionArrayPointer ? mUnionArrayPointer[index].isZero() : false; | |
| } | |
| TIntermConstantUnion *getAsConstantUnion() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } | |
| TConstantUnion *foldUnaryNonComponentWise(TOperator op); | |
| TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics); | |
| static const TConstantUnion *FoldBinary(TOperator op, | |
| const TConstantUnion *leftArray, | |
| const TType &leftType, | |
| const TConstantUnion *rightArray, | |
| const TType &rightType, | |
| TDiagnostics *diagnostics, | |
| const TSourceLoc &line); | |
| static const TConstantUnion *FoldIndexing(const TType &type, | |
| const TConstantUnion *constArray, | |
| int index); | |
| static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, | |
| TDiagnostics *diagnostics); | |
| static bool IsFloatDivision(TBasicType t1, TBasicType t2); | |
| protected: | |
| // Same data may be shared between multiple constant unions, so it can't be modified. | |
| const TConstantUnion *mUnionArrayPointer; | |
| private: | |
| typedef float (*FloatTypeUnaryFunc)(float); | |
| void foldFloatTypeUnary(const TConstantUnion ¶meter, | |
| FloatTypeUnaryFunc builtinFunc, | |
| TConstantUnion *result) const; | |
| TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! | |
| }; | |
| // | |
| // Intermediate class for node types that hold operators. | |
| // | |
| class TIntermOperator : public TIntermExpression | |
| { | |
| public: | |
| TOperator getOp() const { return mOp; } | |
| bool isAssignment() const; | |
| bool isMultiplication() const; | |
| bool isConstructor() const; | |
| // Returns true for calls mapped to EOpCall*, false for built-ins that have their own specific | |
| // ops. | |
| bool isFunctionCall() const; | |
| bool hasSideEffects() const override { return isAssignment(); } | |
| protected: | |
| TIntermOperator(TOperator op) : TIntermExpression(TType(EbtFloat, EbpUndefined)), mOp(op) {} | |
| TIntermOperator(TOperator op, const TType &type) : TIntermExpression(type), mOp(op) {} | |
| TIntermOperator(const TIntermOperator &) = default; | |
| const TOperator mOp; | |
| }; | |
| // Node for vector swizzles. | |
| class TIntermSwizzle : public TIntermExpression | |
| { | |
| public: | |
| // This constructor determines the type of the node based on the operand. | |
| TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets); | |
| TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); } | |
| TIntermSwizzle *getAsSwizzleNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| bool hasSideEffects() const override { return mOperand->hasSideEffects(); } | |
| TIntermTyped *getOperand() { return mOperand; } | |
| void writeOffsetsAsXYZW(TInfoSinkBase *out) const; | |
| const TVector<int> &getSwizzleOffsets() { return mSwizzleOffsets; } | |
| bool hasDuplicateOffsets() const; | |
| void setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets); | |
| bool offsetsMatch(int offset) const; | |
| TIntermTyped *fold(TDiagnostics *diagnostics) override; | |
| protected: | |
| TIntermTyped *mOperand; | |
| TVector<int> mSwizzleOffsets; | |
| bool mHasFoldedDuplicateOffsets; | |
| private: | |
| void promote(); | |
| TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private! | |
| }; | |
| // | |
| // Nodes for all the basic binary math operators. | |
| // | |
| class TIntermBinary : public TIntermOperator | |
| { | |
| public: | |
| // This constructor determines the type of the binary node based on the operands and op. | |
| TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right); | |
| // Comma qualifier depends on the shader version, so use this to create comma nodes: | |
| static TIntermBinary *CreateComma(TIntermTyped *left, TIntermTyped *right, int shaderVersion); | |
| TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); } | |
| bool hasConstantValue() const override; | |
| const TConstantUnion *getConstantValue() const override; | |
| static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right); | |
| static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right); | |
| TIntermBinary *getAsBinaryNode() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| bool hasSideEffects() const override | |
| { | |
| return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects(); | |
| } | |
| TIntermTyped *getLeft() const { return mLeft; } | |
| TIntermTyped *getRight() const { return mRight; } | |
| TIntermTyped *fold(TDiagnostics *diagnostics) override; | |
| void setAddIndexClamp() { mAddIndexClamp = true; } | |
| bool getAddIndexClamp() const { return mAddIndexClamp; } | |
| // This method is only valid for EOpIndexDirectStruct. It returns the name of the field. | |
| const ImmutableString &getIndexStructFieldName() const; | |
| protected: | |
| TIntermTyped *mLeft; | |
| TIntermTyped *mRight; | |
| // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. | |
| bool mAddIndexClamp; | |
| private: | |
| void promote(); | |
| static TQualifier GetCommaQualifier(int shaderVersion, | |
| const TIntermTyped *left, | |
| const TIntermTyped *right); | |
| TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private! | |
| }; | |
| // | |
| // Nodes for unary math operators. | |
| // | |
| class TIntermUnary : public TIntermOperator | |
| { | |
| public: | |
| TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function); | |
| TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); } | |
| TIntermUnary *getAsUnaryNode() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); } | |
| TIntermTyped *getOperand() { return mOperand; } | |
| TIntermTyped *fold(TDiagnostics *diagnostics) override; | |
| const TFunction *getFunction() const { return mFunction; } | |
| void setUseEmulatedFunction() { mUseEmulatedFunction = true; } | |
| bool getUseEmulatedFunction() { return mUseEmulatedFunction; } | |
| protected: | |
| TIntermTyped *mOperand; | |
| // If set to true, replace the built-in function call with an emulated one | |
| // to work around driver bugs. | |
| bool mUseEmulatedFunction; | |
| const TFunction *const mFunction; | |
| private: | |
| void promote(); | |
| TIntermUnary(const TIntermUnary &node); // note: not deleted, just private! | |
| }; | |
| typedef TVector<TIntermNode *> TIntermSequence; | |
| typedef TVector<int> TQualifierList; | |
| // Interface for node classes that have an arbitrarily sized set of children. | |
| class TIntermAggregateBase | |
| { | |
| public: | |
| virtual ~TIntermAggregateBase() {} | |
| virtual TIntermSequence *getSequence() = 0; | |
| virtual const TIntermSequence *getSequence() const = 0; | |
| bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements); | |
| bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions); | |
| protected: | |
| TIntermAggregateBase() {} | |
| bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement); | |
| }; | |
| // | |
| // Nodes that operate on an arbitrary sized set of children. | |
| // | |
| class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase | |
| { | |
| public: | |
| static TIntermAggregate *CreateFunctionCall(const TFunction &func, TIntermSequence *arguments); | |
| static TIntermAggregate *CreateRawFunctionCall(const TFunction &func, | |
| TIntermSequence *arguments); | |
| // This covers all built-in function calls - whether they are associated with an op or not. | |
| static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func, | |
| TIntermSequence *arguments); | |
| static TIntermAggregate *CreateConstructor(const TType &type, TIntermSequence *arguments); | |
| ~TIntermAggregate() override {} | |
| // Note: only supported for nodes that can be a part of an expression. | |
| TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); } | |
| TIntermAggregate *shallowCopy() const; | |
| bool hasConstantValue() const override; | |
| const TConstantUnion *getConstantValue() const override; | |
| TIntermAggregate *getAsAggregate() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| bool hasSideEffects() const override; | |
| TIntermTyped *fold(TDiagnostics *diagnostics) override; | |
| TIntermSequence *getSequence() override { return &mArguments; } | |
| const TIntermSequence *getSequence() const override { return &mArguments; } | |
| void setUseEmulatedFunction() { mUseEmulatedFunction = true; } | |
| bool getUseEmulatedFunction() { return mUseEmulatedFunction; } | |
| // Returns true if changing parameter precision may affect the return value. | |
| bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; } | |
| const TFunction *getFunction() const { return mFunction; } | |
| // Get the function name to display to the user in an error message. | |
| const char *functionName() const; | |
| protected: | |
| TIntermSequence mArguments; | |
| // If set to true, replace the built-in function call with an emulated one | |
| // to work around driver bugs. Only for calls mapped to ops other than EOpCall*. | |
| bool mUseEmulatedFunction; | |
| bool mGotPrecisionFromChildren; | |
| const TFunction *const mFunction; | |
| private: | |
| TIntermAggregate(const TFunction *func, | |
| const TType &type, | |
| TOperator op, | |
| TIntermSequence *arguments); | |
| TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private! | |
| void setPrecisionAndQualifier(); | |
| bool areChildrenConstQualified(); | |
| void setPrecisionFromChildren(); | |
| void setPrecisionForBuiltInOp(); | |
| // Returns true if precision was set according to special rules for this built-in. | |
| bool setPrecisionForSpecialBuiltInOp(); | |
| // Used for built-in functions under EOpCallBuiltInFunction. The function name in the symbol | |
| // info needs to be set before calling this. | |
| void setBuiltInFunctionPrecision(); | |
| }; | |
| // A list of statements. Either the root node which contains declarations and function definitions, | |
| // or a block that can be marked with curly braces {}. | |
| class TIntermBlock : public TIntermNode, public TIntermAggregateBase | |
| { | |
| public: | |
| TIntermBlock() : TIntermNode() {} | |
| ~TIntermBlock() override {} | |
| TIntermBlock *getAsBlock() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| // Only intended for initially building the block. | |
| void appendStatement(TIntermNode *statement); | |
| void insertStatement(size_t insertPosition, TIntermNode *statement); | |
| TIntermSequence *getSequence() override { return &mStatements; } | |
| const TIntermSequence *getSequence() const override { return &mStatements; } | |
| TIntermBlock *deepCopy() const override { return new TIntermBlock(*this); } | |
| protected: | |
| TIntermSequence mStatements; | |
| private: | |
| TIntermBlock(const TIntermBlock &); | |
| }; | |
| // Function prototype. May be in the AST either as a function prototype declaration or as a part of | |
| // a function definition. The type of the node is the function return type. | |
| class TIntermFunctionPrototype : public TIntermTyped | |
| { | |
| public: | |
| TIntermFunctionPrototype(const TFunction *function); | |
| ~TIntermFunctionPrototype() override {} | |
| TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| const TType &getType() const override; | |
| TIntermTyped *deepCopy() const override | |
| { | |
| UNREACHABLE(); | |
| return nullptr; | |
| } | |
| bool hasSideEffects() const override | |
| { | |
| UNREACHABLE(); | |
| return true; | |
| } | |
| const TFunction *getFunction() const { return mFunction; } | |
| protected: | |
| const TFunction *const mFunction; | |
| }; | |
| // Node for function definitions. The prototype child node stores the function header including | |
| // parameters, and the body child node stores the function body. | |
| class TIntermFunctionDefinition : public TIntermNode | |
| { | |
| public: | |
| TIntermFunctionDefinition(TIntermFunctionPrototype *prototype, TIntermBlock *body) | |
| : TIntermNode(), mPrototype(prototype), mBody(body) | |
| { | |
| ASSERT(prototype != nullptr); | |
| ASSERT(body != nullptr); | |
| } | |
| TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; } | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TIntermFunctionPrototype *getFunctionPrototype() const { return mPrototype; } | |
| TIntermBlock *getBody() const { return mBody; } | |
| const TFunction *getFunction() const { return mPrototype->getFunction(); } | |
| TIntermNode *deepCopy() const override | |
| { | |
| UNREACHABLE(); | |
| return nullptr; | |
| } | |
| private: | |
| TIntermFunctionPrototype *mPrototype; | |
| TIntermBlock *mBody; | |
| }; | |
| // Struct, interface block or variable declaration. Can contain multiple variable declarators. | |
| class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase | |
| { | |
| public: | |
| TIntermDeclaration() : TIntermNode() {} | |
| ~TIntermDeclaration() override {} | |
| TIntermDeclaration *getAsDeclarationNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| // Only intended for initially building the declaration. | |
| // The declarator node should be either TIntermSymbol or TIntermBinary with op set to | |
| // EOpInitialize. | |
| void appendDeclarator(TIntermTyped *declarator); | |
| TIntermSequence *getSequence() override { return &mDeclarators; } | |
| const TIntermSequence *getSequence() const override { return &mDeclarators; } | |
| TIntermNode *deepCopy() const override | |
| { | |
| UNREACHABLE(); | |
| return nullptr; | |
| } | |
| protected: | |
| TIntermSequence mDeclarators; | |
| }; | |
| // Specialized declarations for attributing invariance. | |
| class TIntermGlobalQualifierDeclaration : public TIntermNode | |
| { | |
| public: | |
| TIntermGlobalQualifierDeclaration(TIntermSymbol *symbol, const TSourceLoc &line); | |
| virtual TIntermGlobalQualifierDeclaration *getAsGlobalQualifierDeclarationNode() override | |
| { | |
| return this; | |
| } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| TIntermSymbol *getSymbol() { return mSymbol; } | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TIntermGlobalQualifierDeclaration *deepCopy() const override | |
| { | |
| return new TIntermGlobalQualifierDeclaration(*this); | |
| } | |
| private: | |
| TIntermSymbol *mSymbol; | |
| TIntermGlobalQualifierDeclaration(const TIntermGlobalQualifierDeclaration &); | |
| }; | |
| // For ternary operators like a ? b : c. | |
| class TIntermTernary : public TIntermExpression | |
| { | |
| public: | |
| TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression); | |
| TIntermTernary *getAsTernaryNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TIntermTyped *getCondition() const { return mCondition; } | |
| TIntermTyped *getTrueExpression() const { return mTrueExpression; } | |
| TIntermTyped *getFalseExpression() const { return mFalseExpression; } | |
| TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); } | |
| bool hasSideEffects() const override | |
| { | |
| return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() || | |
| mFalseExpression->hasSideEffects(); | |
| } | |
| TIntermTyped *fold(TDiagnostics *diagnostics) override; | |
| private: | |
| TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private! | |
| static TQualifier DetermineQualifier(TIntermTyped *cond, | |
| TIntermTyped *trueExpression, | |
| TIntermTyped *falseExpression); | |
| TIntermTyped *mCondition; | |
| TIntermTyped *mTrueExpression; | |
| TIntermTyped *mFalseExpression; | |
| }; | |
| class TIntermIfElse : public TIntermNode | |
| { | |
| public: | |
| TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB); | |
| TIntermIfElse *getAsIfElseNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TIntermTyped *getCondition() const { return mCondition; } | |
| TIntermBlock *getTrueBlock() const { return mTrueBlock; } | |
| TIntermBlock *getFalseBlock() const { return mFalseBlock; } | |
| TIntermIfElse *deepCopy() const override { return new TIntermIfElse(*this); } | |
| protected: | |
| TIntermTyped *mCondition; | |
| TIntermBlock *mTrueBlock; | |
| TIntermBlock *mFalseBlock; | |
| private: | |
| TIntermIfElse(const TIntermIfElse &); | |
| }; | |
| // | |
| // Switch statement. | |
| // | |
| class TIntermSwitch : public TIntermNode | |
| { | |
| public: | |
| TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList); | |
| TIntermSwitch *getAsSwitchNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| TIntermTyped *getInit() { return mInit; } | |
| TIntermBlock *getStatementList() { return mStatementList; } | |
| // Must be called with a non-null statementList. | |
| void setStatementList(TIntermBlock *statementList); | |
| TIntermSwitch *deepCopy() const override { return new TIntermSwitch(*this); } | |
| protected: | |
| TIntermTyped *mInit; | |
| TIntermBlock *mStatementList; | |
| private: | |
| TIntermSwitch(const TIntermSwitch &); | |
| }; | |
| // | |
| // Case label. | |
| // | |
| class TIntermCase : public TIntermNode | |
| { | |
| public: | |
| TIntermCase(TIntermTyped *condition) : TIntermNode(), mCondition(condition) {} | |
| TIntermCase *getAsCaseNode() override { return this; } | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; | |
| bool hasCondition() const { return mCondition != nullptr; } | |
| TIntermTyped *getCondition() const { return mCondition; } | |
| TIntermCase *deepCopy() const override { return new TIntermCase(*this); } | |
| protected: | |
| TIntermTyped *mCondition; | |
| private: | |
| TIntermCase(const TIntermCase &); | |
| }; | |
| // | |
| // Preprocessor Directive. | |
| // #ifdef, #define, #if, #endif, etc. | |
| // | |
| enum class PreprocessorDirective | |
| { | |
| Define, | |
| Ifdef, | |
| If, | |
| Endif, | |
| }; | |
| class TIntermPreprocessorDirective final : public TIntermNode | |
| { | |
| public: | |
| // This could also take an ImmutableString as an argument. | |
| TIntermPreprocessorDirective(PreprocessorDirective directive, ImmutableString command); | |
| ~TIntermPreprocessorDirective() final; | |
| void traverse(TIntermTraverser *it) final; | |
| bool visit(Visit visit, TIntermTraverser *it) final; | |
| bool replaceChildNode(TIntermNode *, TIntermNode *) final { return false; } | |
| TIntermPreprocessorDirective *getAsPreprocessorDirective() final { return this; } | |
| size_t getChildCount() const final; | |
| TIntermNode *getChildNode(size_t index) const final; | |
| PreprocessorDirective getDirective() const { return mDirective; } | |
| const ImmutableString &getCommand() const { return mCommand; } | |
| TIntermPreprocessorDirective *deepCopy() const override | |
| { | |
| return new TIntermPreprocessorDirective(*this); | |
| } | |
| private: | |
| PreprocessorDirective mDirective; | |
| ImmutableString mCommand; | |
| TIntermPreprocessorDirective(const TIntermPreprocessorDirective &); | |
| }; | |
| } // namespace sh | |
| #endif // COMPILER_TRANSLATOR_INTERMNODE_H_ |