| // |
| // Copyright 2014 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. |
| // |
| // RewriteElseBlocks.cpp: Implementation for tree transform to change |
| // all if-else blocks to if-if blocks. |
| // |
| |
| #include "compiler/translator/tree_ops/RewriteElseBlocks.h" |
| |
| #include "compiler/translator/Compiler.h" |
| #include "compiler/translator/IntermNode.h" |
| #include "compiler/translator/SymbolTable.h" |
| #include "compiler/translator/tree_util/IntermNode_util.h" |
| #include "compiler/translator/tree_util/NodeSearch.h" |
| |
| namespace sh |
| { |
| |
| namespace |
| { |
| |
| class ElseBlockRewriter : public TIntermTraverser |
| { |
| public: |
| ElseBlockRewriter(TSymbolTable *symbolTable); |
| |
| protected: |
| bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override; |
| bool visitBlock(Visit visit, TIntermBlock *block) override; |
| |
| private: |
| TIntermNode *rewriteIfElse(TIntermIfElse *ifElse); |
| |
| const TType *mFunctionType; |
| }; |
| |
| ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable) |
| : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr) |
| {} |
| |
| bool ElseBlockRewriter::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) |
| { |
| // Store the current function context (see comment below) |
| mFunctionType = ((visit == PreVisit) ? &node->getFunctionPrototype()->getType() : nullptr); |
| return true; |
| } |
| |
| bool ElseBlockRewriter::visitBlock(Visit visit, TIntermBlock *node) |
| { |
| if (visit == PostVisit) |
| { |
| for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); |
| statementIndex++) |
| { |
| TIntermNode *statement = (*node->getSequence())[statementIndex]; |
| TIntermIfElse *ifElse = statement->getAsIfElseNode(); |
| if (ifElse && ifElse->getFalseBlock() != nullptr) |
| { |
| (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse); |
| } |
| } |
| } |
| return true; |
| } |
| |
| TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse) |
| { |
| ASSERT(ifElse != nullptr); |
| |
| TIntermDeclaration *storeCondition = nullptr; |
| TVariable *conditionVariable = |
| DeclareTempVariable(mSymbolTable, ifElse->getCondition(), EvqTemporary, &storeCondition); |
| |
| TIntermBlock *falseBlock = nullptr; |
| |
| TType boolType(EbtBool, EbpUndefined, EvqTemporary); |
| |
| if (ifElse->getFalseBlock()) |
| { |
| TIntermBlock *negatedElse = nullptr; |
| // crbug.com/346463 |
| // D3D generates error messages claiming a function has no return value, when rewriting |
| // an if-else clause that returns something non-void in a function. By appending dummy |
| // returns (that are unreachable) we can silence this compile error. |
| if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) |
| { |
| TIntermNode *returnNode = new TIntermBranch(EOpReturn, CreateZeroNode(*mFunctionType)); |
| negatedElse = new TIntermBlock(); |
| negatedElse->appendStatement(returnNode); |
| } |
| |
| TIntermSymbol *conditionSymbolElse = CreateTempSymbolNode(conditionVariable); |
| TIntermUnary *negatedCondition = |
| new TIntermUnary(EOpLogicalNot, conditionSymbolElse, nullptr); |
| TIntermIfElse *falseIfElse = |
| new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse); |
| falseBlock = EnsureBlock(falseIfElse); |
| } |
| |
| TIntermSymbol *conditionSymbolSel = CreateTempSymbolNode(conditionVariable); |
| TIntermIfElse *newIfElse = |
| new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock); |
| |
| TIntermBlock *block = new TIntermBlock(); |
| block->getSequence()->push_back(storeCondition); |
| block->getSequence()->push_back(newIfElse); |
| |
| return block; |
| } |
| |
| } // anonymous namespace |
| |
| bool RewriteElseBlocks(TCompiler *compiler, TIntermNode *node, TSymbolTable *symbolTable) |
| { |
| ElseBlockRewriter rewriter(symbolTable); |
| node->traverse(&rewriter); |
| |
| return compiler->validateAST(node); |
| } |
| |
| } // namespace sh |