blob: 568897b3bce9612d25bad81e985b631551bf906d [file] [log] [blame]
//
// 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; }
// Returns non-null body.
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 = EnsureBody(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, non-null.
private:
TIntermLoop(const TIntermLoop &);
static TIntermBlock *EnsureBody(TIntermBlock *body);
};
//
// 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 &parameter,
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 &);
};
inline TIntermBlock *TIntermLoop::EnsureBody(TIntermBlock *body)
{
if (ANGLE_LIKELY(body))
{
return body;
}
UNREACHABLE();
return new TIntermBlock();
}
} // namespace sh
#endif // COMPILER_TRANSLATOR_INTERMNODE_H_