| // |
| // 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 |