diff options
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/IntermNode.h')
-rw-r--r-- | gfx/angle/checkout/src/compiler/translator/IntermNode.h | 1046 |
1 files changed, 1046 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/IntermNode.h b/gfx/angle/checkout/src/compiler/translator/IntermNode.h new file mode 100644 index 0000000000..81b5fcce43 --- /dev/null +++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.h @@ -0,0 +1,1046 @@ +// +// 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_autogen.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 bool isConstantNullValue() 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; + + // Derive the precision of the node based on its children's. + virtual TPrecision derivePrecision() const; + // Set precision of the current node and propagate it to any child node that doesn't have + // precision. This should be the case only for TIntermConstantUnion nodes as every other node + // would already need to have its precision specified or derived. + virtual void propagatePrecision(TPrecision precision); + + TBasicType getBasicType() const { return getType().getBasicType(); } + TQualifier getQualifier() const { return getType().getQualifier(); } + TPrecision getPrecision() const { return getType().getPrecision(); } + TMemoryQualifier getMemoryQualifier() const { return getType().getMemoryQualifier(); } + uint8_t getCols() const { return getType().getCols(); } + uint8_t getRows() const { return getType().getRows(); } + uint8_t getNominalSize() const { return getType().getNominalSize(); } + uint8_t 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(); } + + // After every transformation is done and just before outputting the tree (i.e. when the tree + // nodes are no longer going to change), the tree is traversed to gather some information to be + // stored in the intermediate nodes: + // + // - Precise-ness, which is set for arithmetic nodes that are involved in the calculation of a + // value assigned to a |precise| variable. + void setIsPrecise() { mIsPrecise = true; } + bool isPrecise() const { return mIsPrecise; } + + protected: + TIntermTyped(const TIntermTyped &node); + + bool mIsPrecise; +}; + +// +// 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! + void propagatePrecision(TPrecision precision) override; + + 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; } + + 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; + bool isConstantNullValue() 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, + const TFunction *function, + 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; + void propagatePrecision(TPrecision precision) override; + + 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 all built-ins. + 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(); + TPrecision derivePrecision() const override; + void propagatePrecision(TPrecision precision) override; + + 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; + + // This method is only valid for EOpIndexDirectStruct. It returns the name of the field. + const ImmutableString &getIndexStructFieldName() const; + + protected: + TIntermTyped *mLeft; + TIntermTyped *mRight; + + private: + void promote(); + TPrecision derivePrecision() const override; + void propagatePrecision(TPrecision precision) override; + + 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(); + TPrecision derivePrecision() const override; + void propagatePrecision(TPrecision precision) override; + + 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. + static TIntermAggregate *CreateBuiltInFunctionCall(const TFunction &func, + TIntermSequence *arguments); + static TIntermAggregate *CreateConstructor(const TType &type, TIntermSequence *arguments); + static TIntermAggregate *CreateConstructor( + const TType &type, + const std::initializer_list<TIntermNode *> &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; + bool isConstantNullValue() 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; } + + 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; + + 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(); + TPrecision derivePrecision() const override; + void propagatePrecision(TPrecision precision) override; + + bool areChildrenConstQualified(); +}; + +// 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(), mIsTreeRoot(false) {} + TIntermBlock(std::initializer_list<TIntermNode *> stmts); + ~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; + void replaceAllChildren(const TIntermSequence &newStatements); + + // 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); } + + void setIsTreeRoot() { mIsTreeRoot = true; } + bool isTreeRoot() const { return mIsTreeRoot; } + + protected: + TIntermSequence mStatements; + + // Used to distinguish the tree root from the other blocks. When validating the AST, some + // validations are not applicable if not run on the entire tree and are thus skipped. + bool mIsTreeRoot; + + 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(const TVariable *var, TIntermTyped *initExpr); + TIntermDeclaration(std::initializer_list<const TVariable *> declarators); + TIntermDeclaration(std::initializer_list<TIntermTyped *> declarators); + ~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; } + + TIntermDeclaration *deepCopy() const override + { + // Note: This is only useful as support for deepCopy of TIntermBlock and TIntermLoop, but is + // not sufficient as it will be redeclaring the same TVariable. If a function body is + // duplicated for example, it means that both functions reference the same TVariable pointer + // which works, but is technically not correct. In particular, maps with TVariable * as key + // can get confused. + // + // After deepCopy() is issued, ReplaceVariables must be used to replace every declared + // variable with a duplicate. This is NOT automatically done when deepCopy-ing TIntermBlock + // and TIntermLoop nodes. + return new TIntermDeclaration(*this); + } + + protected: + TIntermDeclaration(const TIntermDeclaration &node); + + TIntermSequence mDeclarators; +}; + +// Specialized declarations for attributing invariance. +class TIntermGlobalQualifierDeclaration : public TIntermNode +{ + public: + TIntermGlobalQualifierDeclaration(TIntermSymbol *symbol, + bool isPrecise, + const TSourceLoc &line); + + virtual TIntermGlobalQualifierDeclaration *getAsGlobalQualifierDeclarationNode() override + { + return this; + } + bool visit(Visit visit, TIntermTraverser *it) final; + + TIntermSymbol *getSymbol() { return mSymbol; } + bool isInvariant() const { return !mIsPrecise; } + bool isPrecise() const { return mIsPrecise; } + + 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; + // Either |precise| or |invariant|, determined based on this flag. + bool mIsPrecise; + + 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); + TPrecision derivePrecision() const override; + void propagatePrecision(TPrecision precision) override; + + 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_ |