blob: 4b45b10e4ec0ecfdee7c17ace00f6b537470cbcf [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.
//
#include <algorithm>
#include "compiler/translator/Compiler.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/AsNode.h"
#include "compiler/translator/tree_util/IntermRebuild.h"
#define GUARD2(cond, failVal) \
do \
{ \
if (!(cond)) \
{ \
return failVal; \
} \
} while (false)
#define GUARD(cond) GUARD2(cond, nullptr)
namespace sh
{
template <typename T, typename U>
ANGLE_INLINE bool AllBits(T haystack, U needle)
{
return (haystack & needle) == needle;
}
template <typename T, typename U>
ANGLE_INLINE bool AnyBits(T haystack, U needle)
{
return (haystack & needle) != 0;
}
////////////////////////////////////////////////////////////////////////////////
TIntermRebuild::BaseResult::BaseResult(BaseResult &other)
: mAction(other.mAction),
mVisit(other.mVisit),
mSingle(other.mSingle),
mMulti(std::move(other.mMulti))
{}
TIntermRebuild::BaseResult::BaseResult(TIntermNode &node, VisitBits visit)
: mAction(Action::ReplaceSingle), mVisit(visit), mSingle(&node)
{}
TIntermRebuild::BaseResult::BaseResult(TIntermNode *node, VisitBits visit)
: mAction(node ? Action::ReplaceSingle : Action::Drop),
mVisit(node ? visit : VisitBits::Neither),
mSingle(node)
{}
TIntermRebuild::BaseResult::BaseResult(std::nullptr_t)
: mAction(Action::Drop), mVisit(VisitBits::Neither), mSingle(nullptr)
{}
TIntermRebuild::BaseResult::BaseResult(Fail)
: mAction(Action::Fail), mVisit(VisitBits::Neither), mSingle(nullptr)
{}
TIntermRebuild::BaseResult::BaseResult(std::vector<TIntermNode *> &&nodes)
: mAction(Action::ReplaceMulti),
mVisit(VisitBits::Neither),
mSingle(nullptr),
mMulti(std::move(nodes))
{}
void TIntermRebuild::BaseResult::moveAssignImpl(BaseResult &other)
{
mAction = other.mAction;
mVisit = other.mVisit;
mSingle = other.mSingle;
mMulti = std::move(other.mMulti);
}
TIntermRebuild::BaseResult TIntermRebuild::BaseResult::Multi(std::vector<TIntermNode *> &&nodes)
{
auto it = std::remove(nodes.begin(), nodes.end(), nullptr);
nodes.erase(it, nodes.end());
return std::move(nodes);
}
bool TIntermRebuild::BaseResult::isFail() const
{
return mAction == Action::Fail;
}
bool TIntermRebuild::BaseResult::isDrop() const
{
return mAction == Action::Drop;
}
TIntermNode *TIntermRebuild::BaseResult::single() const
{
return mSingle;
}
const std::vector<TIntermNode *> *TIntermRebuild::BaseResult::multi() const
{
if (mAction == Action::ReplaceMulti)
{
return &mMulti;
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
using PreResult = TIntermRebuild::PreResult;
PreResult::PreResult(TIntermNode &node, VisitBits visit) : BaseResult(node, visit) {}
PreResult::PreResult(TIntermNode *node, VisitBits visit) : BaseResult(node, visit) {}
PreResult::PreResult(std::nullptr_t) : BaseResult(nullptr) {}
PreResult::PreResult(Fail) : BaseResult(Fail()) {}
PreResult::PreResult(BaseResult &&other) : BaseResult(other) {}
PreResult::PreResult(PreResult &&other) : BaseResult(other) {}
void PreResult::operator=(PreResult &&other)
{
moveAssignImpl(other);
}
////////////////////////////////////////////////////////////////////////////////
using PostResult = TIntermRebuild::PostResult;
PostResult::PostResult(TIntermNode &node) : BaseResult(node, VisitBits::Neither) {}
PostResult::PostResult(TIntermNode *node) : BaseResult(node, VisitBits::Neither) {}
PostResult::PostResult(std::nullptr_t) : BaseResult(nullptr) {}
PostResult::PostResult(Fail) : BaseResult(Fail()) {}
PostResult::PostResult(PostResult &&other) : BaseResult(other) {}
PostResult::PostResult(BaseResult &&other) : BaseResult(other) {}
void PostResult::operator=(PostResult &&other)
{
moveAssignImpl(other);
}
////////////////////////////////////////////////////////////////////////////////
TIntermRebuild::TIntermRebuild(TCompiler &compiler, bool preVisit, bool postVisit)
: mCompiler(compiler),
mSymbolTable(compiler.getSymbolTable()),
mPreVisit(preVisit),
mPostVisit(postVisit)
{
ASSERT(preVisit || postVisit);
}
TIntermRebuild::~TIntermRebuild()
{
ASSERT(!mNodeStack.value);
ASSERT(!mNodeStack.tail);
}
const TFunction *TIntermRebuild::getParentFunction() const
{
return mParentFunc;
}
TIntermNode *TIntermRebuild::getParentNode(size_t offset) const
{
ASSERT(mNodeStack.tail);
auto parent = *mNodeStack.tail;
while (offset > 0)
{
--offset;
ASSERT(parent.tail);
parent = *parent.tail;
}
return parent.value;
}
bool TIntermRebuild::rebuildRoot(TIntermBlock &root)
{
if (!rebuildInPlace(root))
{
return false;
}
return mCompiler.validateAST(&root);
}
bool TIntermRebuild::rebuildInPlace(TIntermAggregate &node)
{
return rebuildInPlaceImpl(node);
}
bool TIntermRebuild::rebuildInPlace(TIntermBlock &node)
{
return rebuildInPlaceImpl(node);
}
bool TIntermRebuild::rebuildInPlace(TIntermDeclaration &node)
{
return rebuildInPlaceImpl(node);
}
template <typename Node>
bool TIntermRebuild::rebuildInPlaceImpl(Node &node)
{
auto *newNode = traverseAnyAs<Node>(node);
if (!newNode)
{
return false;
}
if (newNode != &node)
{
*node.getSequence() = std::move(*newNode->getSequence());
}
return true;
}
PostResult TIntermRebuild::rebuild(TIntermNode &node)
{
return traverseAny(node);
}
////////////////////////////////////////////////////////////////////////////////
template <typename Node>
Node *TIntermRebuild::traverseAnyAs(TIntermNode &node)
{
PostResult result(traverseAny(node));
if (result.mAction == Action::Fail || !result.mSingle)
{
return nullptr;
}
return asNode<Node>(result.mSingle);
}
template <typename Node>
bool TIntermRebuild::traverseAnyAs(TIntermNode &node, Node *&out)
{
PostResult result(traverseAny(node));
if (result.mAction == Action::Fail || result.mAction == Action::ReplaceMulti)
{
return false;
}
if (!result.mSingle)
{
return true;
}
out = asNode<Node>(result.mSingle);
return out != nullptr;
}
bool TIntermRebuild::traverseAggregateBaseChildren(TIntermAggregateBase &node)
{
auto *const children = node.getSequence();
ASSERT(children);
TIntermSequence newChildren;
for (TIntermNode *child : *children)
{
ASSERT(child);
PostResult result(traverseAny(*child));
switch (result.mAction)
{
case Action::ReplaceSingle:
newChildren.push_back(result.mSingle);
break;
case Action::ReplaceMulti:
for (TIntermNode *newNode : result.mMulti)
{
if (newNode)
{
newChildren.push_back(newNode);
}
}
break;
case Action::Drop:
break;
case Action::Fail:
return false;
default:
ASSERT(false);
return false;
}
}
*children = std::move(newChildren);
return true;
}
////////////////////////////////////////////////////////////////////////////////
struct TIntermRebuild::NodeStackGuard
{
ConsList<TIntermNode *> oldNodeStack;
ConsList<TIntermNode *> &nodeStack;
NodeStackGuard(ConsList<TIntermNode *> &nodeStack)
: oldNodeStack(nodeStack), nodeStack(nodeStack)
{}
~NodeStackGuard() { nodeStack = oldNodeStack; }
};
PostResult TIntermRebuild::traverseAny(TIntermNode &originalNode)
{
PreResult preResult = traversePre(originalNode);
if (!preResult.mSingle)
{
ASSERT(preResult.mVisit == VisitBits::Neither);
return std::move(preResult);
}
TIntermNode *currNode = preResult.mSingle;
const VisitBits visit = preResult.mVisit;
const NodeType currNodeType = getNodeType(*currNode);
currNode = traverseChildren(currNodeType, originalNode, *currNode, visit);
if (!currNode)
{
return Fail();
}
return traversePost(currNodeType, originalNode, *currNode, visit);
}
PreResult TIntermRebuild::traversePre(TIntermNode &originalNode)
{
if (!mPreVisit)
{
return {originalNode, VisitBits::Both};
}
NodeStackGuard guard(mNodeStack);
mNodeStack = {&originalNode, &guard.oldNodeStack};
const NodeType originalNodeType = getNodeType(originalNode);
switch (originalNodeType)
{
case NodeType::Unknown:
ASSERT(false);
return Fail();
case NodeType::Symbol:
return visitSymbolPre(*originalNode.getAsSymbolNode());
case NodeType::ConstantUnion:
return visitConstantUnionPre(*originalNode.getAsConstantUnion());
case NodeType::FunctionPrototype:
return visitFunctionPrototypePre(*originalNode.getAsFunctionPrototypeNode());
case NodeType::PreprocessorDirective:
return visitPreprocessorDirectivePre(*originalNode.getAsPreprocessorDirective());
case NodeType::Unary:
return visitUnaryPre(*originalNode.getAsUnaryNode());
case NodeType::Binary:
return visitBinaryPre(*originalNode.getAsBinaryNode());
case NodeType::Ternary:
return visitTernaryPre(*originalNode.getAsTernaryNode());
case NodeType::Swizzle:
return visitSwizzlePre(*originalNode.getAsSwizzleNode());
case NodeType::IfElse:
return visitIfElsePre(*originalNode.getAsIfElseNode());
case NodeType::Switch:
return visitSwitchPre(*originalNode.getAsSwitchNode());
case NodeType::Case:
return visitCasePre(*originalNode.getAsCaseNode());
case NodeType::FunctionDefinition:
return visitFunctionDefinitionPre(*originalNode.getAsFunctionDefinition());
case NodeType::Aggregate:
return visitAggregatePre(*originalNode.getAsAggregate());
case NodeType::Block:
return visitBlockPre(*originalNode.getAsBlock());
case NodeType::GlobalQualifierDeclaration:
return visitGlobalQualifierDeclarationPre(
*originalNode.getAsGlobalQualifierDeclarationNode());
case NodeType::Declaration:
return visitDeclarationPre(*originalNode.getAsDeclarationNode());
case NodeType::Loop:
return visitLoopPre(*originalNode.getAsLoopNode());
case NodeType::Branch:
return visitBranchPre(*originalNode.getAsBranchNode());
default:
ASSERT(false);
return Fail();
}
}
TIntermNode *TIntermRebuild::traverseChildren(NodeType currNodeType,
const TIntermNode &originalNode,
TIntermNode &currNode,
VisitBits visit)
{
if (!AnyBits(visit, VisitBits::Children))
{
return &currNode;
}
if (AnyBits(visit, VisitBits::ChildrenRequiresSame) && &originalNode != &currNode)
{
return &currNode;
}
NodeStackGuard guard(mNodeStack);
mNodeStack = {&currNode, &guard.oldNodeStack};
switch (currNodeType)
{
case NodeType::Unknown:
ASSERT(false);
return nullptr;
case NodeType::Symbol:
return &currNode;
case NodeType::ConstantUnion:
return &currNode;
case NodeType::FunctionPrototype:
return &currNode;
case NodeType::PreprocessorDirective:
return &currNode;
case NodeType::Unary:
return traverseUnaryChildren(*currNode.getAsUnaryNode());
case NodeType::Binary:
return traverseBinaryChildren(*currNode.getAsBinaryNode());
case NodeType::Ternary:
return traverseTernaryChildren(*currNode.getAsTernaryNode());
case NodeType::Swizzle:
return traverseSwizzleChildren(*currNode.getAsSwizzleNode());
case NodeType::IfElse:
return traverseIfElseChildren(*currNode.getAsIfElseNode());
case NodeType::Switch:
return traverseSwitchChildren(*currNode.getAsSwitchNode());
case NodeType::Case:
return traverseCaseChildren(*currNode.getAsCaseNode());
case NodeType::FunctionDefinition:
return traverseFunctionDefinitionChildren(*currNode.getAsFunctionDefinition());
case NodeType::Aggregate:
return traverseAggregateChildren(*currNode.getAsAggregate());
case NodeType::Block:
return traverseBlockChildren(*currNode.getAsBlock());
case NodeType::GlobalQualifierDeclaration:
return traverseGlobalQualifierDeclarationChildren(
*currNode.getAsGlobalQualifierDeclarationNode());
case NodeType::Declaration:
return traverseDeclarationChildren(*currNode.getAsDeclarationNode());
case NodeType::Loop:
return traverseLoopChildren(*currNode.getAsLoopNode());
case NodeType::Branch:
return traverseBranchChildren(*currNode.getAsBranchNode());
default:
ASSERT(false);
return nullptr;
}
}
PostResult TIntermRebuild::traversePost(NodeType currNodeType,
const TIntermNode &originalNode,
TIntermNode &currNode,
VisitBits visit)
{
if (!mPostVisit)
{
return currNode;
}
if (!AnyBits(visit, VisitBits::Post))
{
return currNode;
}
if (AnyBits(visit, VisitBits::PostRequiresSame) && &originalNode != &currNode)
{
return currNode;
}
NodeStackGuard guard(mNodeStack);
mNodeStack = {&currNode, &guard.oldNodeStack};
switch (currNodeType)
{
case NodeType::Unknown:
ASSERT(false);
return Fail();
case NodeType::Symbol:
return visitSymbolPost(*currNode.getAsSymbolNode());
case NodeType::ConstantUnion:
return visitConstantUnionPost(*currNode.getAsConstantUnion());
case NodeType::FunctionPrototype:
return visitFunctionPrototypePost(*currNode.getAsFunctionPrototypeNode());
case NodeType::PreprocessorDirective:
return visitPreprocessorDirectivePost(*currNode.getAsPreprocessorDirective());
case NodeType::Unary:
return visitUnaryPost(*currNode.getAsUnaryNode());
case NodeType::Binary:
return visitBinaryPost(*currNode.getAsBinaryNode());
case NodeType::Ternary:
return visitTernaryPost(*currNode.getAsTernaryNode());
case NodeType::Swizzle:
return visitSwizzlePost(*currNode.getAsSwizzleNode());
case NodeType::IfElse:
return visitIfElsePost(*currNode.getAsIfElseNode());
case NodeType::Switch:
return visitSwitchPost(*currNode.getAsSwitchNode());
case NodeType::Case:
return visitCasePost(*currNode.getAsCaseNode());
case NodeType::FunctionDefinition:
return visitFunctionDefinitionPost(*currNode.getAsFunctionDefinition());
case NodeType::Aggregate:
return visitAggregatePost(*currNode.getAsAggregate());
case NodeType::Block:
return visitBlockPost(*currNode.getAsBlock());
case NodeType::GlobalQualifierDeclaration:
return visitGlobalQualifierDeclarationPost(
*currNode.getAsGlobalQualifierDeclarationNode());
case NodeType::Declaration:
return visitDeclarationPost(*currNode.getAsDeclarationNode());
case NodeType::Loop:
return visitLoopPost(*currNode.getAsLoopNode());
case NodeType::Branch:
return visitBranchPost(*currNode.getAsBranchNode());
default:
ASSERT(false);
return Fail();
}
}
////////////////////////////////////////////////////////////////////////////////
TIntermNode *TIntermRebuild::traverseAggregateChildren(TIntermAggregate &node)
{
if (traverseAggregateBaseChildren(node))
{
return &node;
}
return nullptr;
}
TIntermNode *TIntermRebuild::traverseBlockChildren(TIntermBlock &node)
{
if (traverseAggregateBaseChildren(node))
{
return &node;
}
return nullptr;
}
TIntermNode *TIntermRebuild::traverseDeclarationChildren(TIntermDeclaration &node)
{
if (traverseAggregateBaseChildren(node))
{
return &node;
}
return nullptr;
}
TIntermNode *TIntermRebuild::traverseSwizzleChildren(TIntermSwizzle &node)
{
auto *const operand = node.getOperand();
ASSERT(operand);
auto *newOperand = traverseAnyAs<TIntermTyped>(*operand);
GUARD(newOperand);
if (newOperand != operand)
{
return new TIntermSwizzle(newOperand, node.getSwizzleOffsets());
}
return &node;
}
TIntermNode *TIntermRebuild::traverseBinaryChildren(TIntermBinary &node)
{
auto *const left = node.getLeft();
ASSERT(left);
auto *const right = node.getRight();
ASSERT(right);
auto *const newLeft = traverseAnyAs<TIntermTyped>(*left);
GUARD(newLeft);
auto *const newRight = traverseAnyAs<TIntermTyped>(*right);
GUARD(newRight);
if (newLeft != left || newRight != right)
{
TOperator op = node.getOp();
switch (op)
{
case TOperator::EOpIndexDirectStruct:
{
if (newLeft->getType().getInterfaceBlock())
{
op = TOperator::EOpIndexDirectInterfaceBlock;
}
}
break;
case TOperator::EOpIndexDirectInterfaceBlock:
{
if (newLeft->getType().getStruct())
{
op = TOperator::EOpIndexDirectStruct;
}
}
break;
case TOperator::EOpComma:
return TIntermBinary::CreateComma(newLeft, newRight, mCompiler.getShaderVersion());
default:
break;
}
return new TIntermBinary(op, newLeft, newRight);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseUnaryChildren(TIntermUnary &node)
{
auto *const operand = node.getOperand();
ASSERT(operand);
auto *const newOperand = traverseAnyAs<TIntermTyped>(*operand);
GUARD(newOperand);
if (newOperand != operand)
{
return new TIntermUnary(node.getOp(), newOperand, node.getFunction());
}
return &node;
}
TIntermNode *TIntermRebuild::traverseTernaryChildren(TIntermTernary &node)
{
auto *const cond = node.getCondition();
ASSERT(cond);
auto *const true_ = node.getTrueExpression();
ASSERT(true_);
auto *const false_ = node.getFalseExpression();
ASSERT(false_);
auto *const newCond = traverseAnyAs<TIntermTyped>(*cond);
GUARD(newCond);
auto *const newTrue = traverseAnyAs<TIntermTyped>(*true_);
GUARD(newTrue);
auto *const newFalse = traverseAnyAs<TIntermTyped>(*false_);
GUARD(newFalse);
if (newCond != cond || newTrue != true_ || newFalse != false_)
{
return new TIntermTernary(newCond, newTrue, newFalse);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseIfElseChildren(TIntermIfElse &node)
{
auto *const cond = node.getCondition();
ASSERT(cond);
auto *const true_ = node.getTrueBlock();
auto *const false_ = node.getFalseBlock();
auto *const newCond = traverseAnyAs<TIntermTyped>(*cond);
GUARD(newCond);
TIntermBlock *newTrue = nullptr;
if (true_)
{
GUARD(traverseAnyAs(*true_, newTrue));
}
TIntermBlock *newFalse = nullptr;
if (false_)
{
GUARD(traverseAnyAs(*false_, newFalse));
}
if (newCond != cond || newTrue != true_ || newFalse != false_)
{
return new TIntermIfElse(newCond, newTrue, newFalse);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseSwitchChildren(TIntermSwitch &node)
{
auto *const init = node.getInit();
ASSERT(init);
auto *const stmts = node.getStatementList();
ASSERT(stmts);
auto *const newInit = traverseAnyAs<TIntermTyped>(*init);
GUARD(newInit);
auto *const newStmts = traverseAnyAs<TIntermBlock>(*stmts);
GUARD(newStmts);
if (newInit != init || newStmts != stmts)
{
return new TIntermSwitch(newInit, newStmts);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseCaseChildren(TIntermCase &node)
{
auto *const cond = node.getCondition();
TIntermTyped *newCond = nullptr;
if (cond)
{
GUARD(traverseAnyAs(*cond, newCond));
}
if (newCond != cond)
{
return new TIntermCase(newCond);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseFunctionDefinitionChildren(TIntermFunctionDefinition &node)
{
GUARD(!mParentFunc); // Function definitions cannot be nested.
mParentFunc = node.getFunction();
struct OnExit
{
const TFunction *&parentFunc;
OnExit(const TFunction *&parentFunc) : parentFunc(parentFunc) {}
~OnExit() { parentFunc = nullptr; }
} onExit(mParentFunc);
auto *const proto = node.getFunctionPrototype();
ASSERT(proto);
auto *const body = node.getBody();
ASSERT(body);
auto *const newProto = traverseAnyAs<TIntermFunctionPrototype>(*proto);
GUARD(newProto);
auto *const newBody = traverseAnyAs<TIntermBlock>(*body);
GUARD(newBody);
if (newProto != proto || newBody != body)
{
return new TIntermFunctionDefinition(newProto, newBody);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseGlobalQualifierDeclarationChildren(
TIntermGlobalQualifierDeclaration &node)
{
auto *const symbol = node.getSymbol();
ASSERT(symbol);
auto *const newSymbol = traverseAnyAs<TIntermSymbol>(*symbol);
GUARD(newSymbol);
if (newSymbol != symbol)
{
return new TIntermGlobalQualifierDeclaration(newSymbol, node.isPrecise(), node.getLine());
}
return &node;
}
TIntermNode *TIntermRebuild::traverseLoopChildren(TIntermLoop &node)
{
const TLoopType loopType = node.getType();
auto *const init = node.getInit();
auto *const cond = node.getCondition();
auto *const expr = node.getExpression();
auto *const body = node.getBody();
ASSERT(body);
#if defined(ANGLE_ENABLE_ASSERTS)
switch (loopType)
{
case TLoopType::ELoopFor:
break;
case TLoopType::ELoopWhile:
case TLoopType::ELoopDoWhile:
ASSERT(cond);
ASSERT(!init && !expr);
break;
default:
ASSERT(false);
break;
}
#endif
auto *const newBody = traverseAnyAs<TIntermBlock>(*body);
GUARD(newBody);
TIntermNode *newInit = nullptr;
if (init)
{
GUARD(traverseAnyAs(*init, newInit));
}
TIntermTyped *newCond = nullptr;
if (cond)
{
GUARD(traverseAnyAs(*cond, newCond));
}
TIntermTyped *newExpr = nullptr;
if (expr)
{
GUARD(traverseAnyAs(*expr, newExpr));
}
if (newInit != init || newCond != cond || newExpr != expr || newBody != body)
{
switch (loopType)
{
case TLoopType::ELoopFor:
GUARD(newBody);
break;
case TLoopType::ELoopWhile:
case TLoopType::ELoopDoWhile:
GUARD(newCond && newBody);
GUARD(!newInit && !newExpr);
break;
default:
ASSERT(false);
break;
}
return new TIntermLoop(loopType, newInit, newCond, newExpr, newBody);
}
return &node;
}
TIntermNode *TIntermRebuild::traverseBranchChildren(TIntermBranch &node)
{
auto *const expr = node.getExpression();
TIntermTyped *newExpr = nullptr;
if (expr)
{
GUARD(traverseAnyAs<TIntermTyped>(*expr, newExpr));
}
if (newExpr != expr)
{
return new TIntermBranch(node.getFlowOp(), newExpr);
}
return &node;
}
////////////////////////////////////////////////////////////////////////////////
PreResult TIntermRebuild::visitSymbolPre(TIntermSymbol &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitConstantUnionPre(TIntermConstantUnion &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitFunctionPrototypePre(TIntermFunctionPrototype &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitPreprocessorDirectivePre(TIntermPreprocessorDirective &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitUnaryPre(TIntermUnary &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitBinaryPre(TIntermBinary &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitTernaryPre(TIntermTernary &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitSwizzlePre(TIntermSwizzle &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitIfElsePre(TIntermIfElse &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitSwitchPre(TIntermSwitch &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitCasePre(TIntermCase &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitLoopPre(TIntermLoop &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitBranchPre(TIntermBranch &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitDeclarationPre(TIntermDeclaration &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitBlockPre(TIntermBlock &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitAggregatePre(TIntermAggregate &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitFunctionDefinitionPre(TIntermFunctionDefinition &node)
{
return {node, VisitBits::Both};
}
PreResult TIntermRebuild::visitGlobalQualifierDeclarationPre(
TIntermGlobalQualifierDeclaration &node)
{
return {node, VisitBits::Both};
}
////////////////////////////////////////////////////////////////////////////////
PostResult TIntermRebuild::visitSymbolPost(TIntermSymbol &node)
{
return node;
}
PostResult TIntermRebuild::visitConstantUnionPost(TIntermConstantUnion &node)
{
return node;
}
PostResult TIntermRebuild::visitFunctionPrototypePost(TIntermFunctionPrototype &node)
{
return node;
}
PostResult TIntermRebuild::visitPreprocessorDirectivePost(TIntermPreprocessorDirective &node)
{
return node;
}
PostResult TIntermRebuild::visitUnaryPost(TIntermUnary &node)
{
return node;
}
PostResult TIntermRebuild::visitBinaryPost(TIntermBinary &node)
{
return node;
}
PostResult TIntermRebuild::visitTernaryPost(TIntermTernary &node)
{
return node;
}
PostResult TIntermRebuild::visitSwizzlePost(TIntermSwizzle &node)
{
return node;
}
PostResult TIntermRebuild::visitIfElsePost(TIntermIfElse &node)
{
return node;
}
PostResult TIntermRebuild::visitSwitchPost(TIntermSwitch &node)
{
return node;
}
PostResult TIntermRebuild::visitCasePost(TIntermCase &node)
{
return node;
}
PostResult TIntermRebuild::visitLoopPost(TIntermLoop &node)
{
return node;
}
PostResult TIntermRebuild::visitBranchPost(TIntermBranch &node)
{
return node;
}
PostResult TIntermRebuild::visitDeclarationPost(TIntermDeclaration &node)
{
return node;
}
PostResult TIntermRebuild::visitBlockPost(TIntermBlock &node)
{
return node;
}
PostResult TIntermRebuild::visitAggregatePost(TIntermAggregate &node)
{
return node;
}
PostResult TIntermRebuild::visitFunctionDefinitionPost(TIntermFunctionDefinition &node)
{
return node;
}
PostResult TIntermRebuild::visitGlobalQualifierDeclarationPost(
TIntermGlobalQualifierDeclaration &node)
{
return node;
}
} // namespace sh