Edit

kc3-lang/angle/src/compiler/translator/IntermNode.h

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2019-12-03 11:31:18
    Hash : 795a3559
    Message : Vulkan: EXT_gpu_shader5 support: precise The precise keyword is used in tessellation shaders but introduced in this extension. EXT_gpu_shader5 introduces a handful of features to shaders. This change only implements the `precise` keyword. Bug: angleproject:3569 Change-Id: I2252b79098eb8ba2d2faa040d7eaed7548b7051e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1939851 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/IntermNode.h
  • //
    // 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 &parameter,
                                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,
                                          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);
    
        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_