blob: 951227067108fc7725631263b90ffae61435a5c4 [file] [log] [blame]
//
// Copyright 2020 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.
//
#ifndef COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_INTERMREBUILD_H_
#define COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_INTERMREBUILD_H_
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/NodeType.h"
namespace sh
{
// Walks the tree to rebuild nodes.
// This class is intended to be derived with overridden visitXXX functions.
//
// Each visitXXX function that does not have a Visit parameter simply has the visitor called
// exactly once, regardless of (preVisit) or (postVisit) values.
// Each visitXXX function that has a Visit parameter behaves as follows:
// * If (preVisit):
// - The node is visited before children are traversed.
// - The returned value is used to replace the visited node. The returned value may be the same
// as the original node.
// - If multiple nodes are returned, children and post visits of the returned nodes are not
// preformed, even if it is a singleton collection.
// * If (childVisit)
// - If any new children are returned, the node is automatically rebuilt with the new children
// before post visit.
// - Depending on the type of the node, null children may be discarded.
// - Ill-typed children cause rebuild errors. Ill-typed means the node to automatically rebuild
// cannot accept a child of a certain type as input to its constructor.
// - Only instances of TIntermAggregateBase can accept Multi results for any of its children.
// If supplied, the nodes are spliced children at the spot of the original child.
// * If (postVisit)
// - The node is visited after any children are traversed.
// - Only after such a rebuild (or lack thereof), the post-visit is performed.
//
// Nodes in visit functions are allowed to be modified in place, including TIntermAggregateBase
// child sequences.
//
// The default implementations of all the visitXXX functions support full pre and post traversal
// without modifying the visited nodes.
//
class TIntermRebuild : angle::NonCopyable
{
enum class Action
{
ReplaceSingle,
ReplaceMulti,
Drop,
Fail,
};
public:
struct Fail
{};
enum VisitBits : size_t
{
// No bits are set.
Empty = 0u,
// Allow visit of returned node's children.
Children = 1u << 0u,
// Allow post visit of returned node.
Post = 1u << 1u,
// If (Children) bit, only visit if the returned node is the same as the original node.
ChildrenRequiresSame = 1u << 2u,
// If (Post) bit, only visit if the returned node is the same as the original node.
PostRequiresSame = 1u << 3u,
RequireSame = ChildrenRequiresSame | PostRequiresSame,
Neither = Empty,
Both = Children | Post,
BothWhenSame = Both | RequireSame,
};
private:
struct NodeStackGuard;
template <typename T>
struct ConsList
{
T value;
ConsList<T> *tail;
};
class BaseResult
{
BaseResult(const BaseResult &) = delete;
BaseResult &operator=(const BaseResult &) = delete;
public:
BaseResult(BaseResult &&other) = default;
BaseResult(BaseResult &other); // For subclass move constructor impls
BaseResult(TIntermNode &node, VisitBits visit);
BaseResult(TIntermNode *node, VisitBits visit);
BaseResult(std::nullptr_t);
BaseResult(Fail);
BaseResult(std::vector<TIntermNode *> &&nodes);
void moveAssignImpl(BaseResult &other); // For subclass move assign impls
static BaseResult Multi(std::vector<TIntermNode *> &&nodes);
template <typename Iter>
static BaseResult Multi(Iter nodesBegin, Iter nodesEnd)
{
std::vector<TIntermNode *> nodes;
for (Iter nodesCurr = nodesBegin; nodesCurr != nodesEnd; ++nodesCurr)
{
nodes.push_back(*nodesCurr);
}
return std::move(nodes);
}
bool isFail() const;
bool isDrop() const;
TIntermNode *single() const;
const std::vector<TIntermNode *> *multi() const;
public:
Action mAction;
VisitBits mVisit;
TIntermNode *mSingle;
std::vector<TIntermNode *> mMulti;
};
public:
class PreResult : private BaseResult
{
friend class TIntermRebuild;
public:
PreResult(PreResult &&other);
PreResult(TIntermNode &node, VisitBits visit = VisitBits::BothWhenSame);
PreResult(TIntermNode *node, VisitBits visit = VisitBits::BothWhenSame);
PreResult(std::nullptr_t); // Used to drop a node.
PreResult(Fail); // Used to signal failure.
void operator=(PreResult &&other);
static PreResult Multi(std::vector<TIntermNode *> &&nodes)
{
return BaseResult::Multi(std::move(nodes));
}
template <typename Iter>
static PreResult Multi(Iter nodesBegin, Iter nodesEnd)
{
return BaseResult::Multi(nodesBegin, nodesEnd);
}
using BaseResult::isDrop;
using BaseResult::isFail;
using BaseResult::multi;
using BaseResult::single;
private:
PreResult(BaseResult &&other);
};
class PostResult : private BaseResult
{
friend class TIntermRebuild;
public:
PostResult(PostResult &&other);
PostResult(TIntermNode &node);
PostResult(TIntermNode *node);
PostResult(std::nullptr_t); // Used to drop a node
PostResult(Fail); // Used to signal failure.
void operator=(PostResult &&other);
static PostResult Multi(std::vector<TIntermNode *> &&nodes)
{
return BaseResult::Multi(std::move(nodes));
}
template <typename Iter>
static PostResult Multi(Iter nodesBegin, Iter nodesEnd)
{
return BaseResult::Multi(nodesBegin, nodesEnd);
}
using BaseResult::isDrop;
using BaseResult::isFail;
using BaseResult::multi;
using BaseResult::single;
private:
PostResult(BaseResult &&other);
};
public:
TIntermRebuild(TCompiler &compiler, bool preVisit, bool postVisit);
virtual ~TIntermRebuild();
// Rebuilds the tree starting at the provided root. If a new node would be returned for the
// root, the root node's children become that of the new node instead. Returns false if failure
// occurred.
ANGLE_NO_DISCARD bool rebuildRoot(TIntermBlock &root);
protected:
virtual PreResult visitSymbolPre(TIntermSymbol &node);
virtual PreResult visitConstantUnionPre(TIntermConstantUnion &node);
virtual PreResult visitFunctionPrototypePre(TIntermFunctionPrototype &node);
virtual PreResult visitPreprocessorDirectivePre(TIntermPreprocessorDirective &node);
virtual PreResult visitUnaryPre(TIntermUnary &node);
virtual PreResult visitBinaryPre(TIntermBinary &node);
virtual PreResult visitTernaryPre(TIntermTernary &node);
virtual PreResult visitSwizzlePre(TIntermSwizzle &node);
virtual PreResult visitIfElsePre(TIntermIfElse &node);
virtual PreResult visitSwitchPre(TIntermSwitch &node);
virtual PreResult visitCasePre(TIntermCase &node);
virtual PreResult visitLoopPre(TIntermLoop &node);
virtual PreResult visitBranchPre(TIntermBranch &node);
virtual PreResult visitDeclarationPre(TIntermDeclaration &node);
virtual PreResult visitBlockPre(TIntermBlock &node);
virtual PreResult visitAggregatePre(TIntermAggregate &node);
virtual PreResult visitFunctionDefinitionPre(TIntermFunctionDefinition &node);
virtual PreResult visitGlobalQualifierDeclarationPre(TIntermGlobalQualifierDeclaration &node);
virtual PostResult visitSymbolPost(TIntermSymbol &node);
virtual PostResult visitConstantUnionPost(TIntermConstantUnion &node);
virtual PostResult visitFunctionPrototypePost(TIntermFunctionPrototype &node);
virtual PostResult visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node);
virtual PostResult visitUnaryPost(TIntermUnary &node);
virtual PostResult visitBinaryPost(TIntermBinary &node);
virtual PostResult visitTernaryPost(TIntermTernary &node);
virtual PostResult visitSwizzlePost(TIntermSwizzle &node);
virtual PostResult visitIfElsePost(TIntermIfElse &node);
virtual PostResult visitSwitchPost(TIntermSwitch &node);
virtual PostResult visitCasePost(TIntermCase &node);
virtual PostResult visitLoopPost(TIntermLoop &node);
virtual PostResult visitBranchPost(TIntermBranch &node);
virtual PostResult visitDeclarationPost(TIntermDeclaration &node);
virtual PostResult visitBlockPost(TIntermBlock &node);
virtual PostResult visitAggregatePost(TIntermAggregate &node);
virtual PostResult visitFunctionDefinitionPost(TIntermFunctionDefinition &node);
virtual PostResult visitGlobalQualifierDeclarationPost(TIntermGlobalQualifierDeclaration &node);
// Can be used to rebuild a specific node during a traversal. Useful for fine control of
// rebuilding a node's children.
ANGLE_NO_DISCARD PostResult rebuild(TIntermNode &node);
// Rebuilds the provided node in place. If a new node would be returned, the old node's children
// become that of the new node instead. Returns false if failure occurred.
ANGLE_NO_DISCARD bool rebuildInPlace(TIntermAggregate &node);
// Rebuilds the provided node in place. If a new node would be returned, the old node's children
// become that of the new node instead. Returns false if failure occurred.
ANGLE_NO_DISCARD bool rebuildInPlace(TIntermBlock &node);
// Rebuilds the provided node in place. If a new node would be returned, the old node's children
// become that of the new node instead. Returns false if failure occurred.
ANGLE_NO_DISCARD bool rebuildInPlace(TIntermDeclaration &node);
// If currently at or below a function declaration body, this returns the function that encloses
// the currently visited node. (This returns null if at a function declaration node.)
const TFunction *getParentFunction() const;
TIntermNode *getParentNode(size_t offset = 0) const;
private:
template <typename Node>
ANGLE_NO_DISCARD bool rebuildInPlaceImpl(Node &node);
PostResult traverseAny(TIntermNode &node);
template <typename Node>
Node *traverseAnyAs(TIntermNode &node);
template <typename Node>
bool traverseAnyAs(TIntermNode &node, Node *&out);
PreResult traversePre(TIntermNode &originalNode);
TIntermNode *traverseChildren(NodeType currNodeType,
const TIntermNode &originalNode,
TIntermNode &currNode,
VisitBits visit);
PostResult traversePost(NodeType nodeType,
const TIntermNode &originalNode,
TIntermNode &currNode,
VisitBits visit);
bool traverseAggregateBaseChildren(TIntermAggregateBase &node);
TIntermNode *traverseUnaryChildren(TIntermUnary &node);
TIntermNode *traverseBinaryChildren(TIntermBinary &node);
TIntermNode *traverseTernaryChildren(TIntermTernary &node);
TIntermNode *traverseSwizzleChildren(TIntermSwizzle &node);
TIntermNode *traverseIfElseChildren(TIntermIfElse &node);
TIntermNode *traverseSwitchChildren(TIntermSwitch &node);
TIntermNode *traverseCaseChildren(TIntermCase &node);
TIntermNode *traverseLoopChildren(TIntermLoop &node);
TIntermNode *traverseBranchChildren(TIntermBranch &node);
TIntermNode *traverseDeclarationChildren(TIntermDeclaration &node);
TIntermNode *traverseBlockChildren(TIntermBlock &node);
TIntermNode *traverseAggregateChildren(TIntermAggregate &node);
TIntermNode *traverseFunctionDefinitionChildren(TIntermFunctionDefinition &node);
TIntermNode *traverseGlobalQualifierDeclarationChildren(
TIntermGlobalQualifierDeclaration &node);
protected:
TCompiler &mCompiler;
TSymbolTable &mSymbolTable;
const TFunction *mParentFunc = nullptr;
GetNodeType getNodeType;
private:
ConsList<TIntermNode *> mNodeStack{nullptr, nullptr};
bool mPreVisit;
bool mPostVisit;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_TRANSLATORMETALDIRECT_INTERMREBUILD_H_