| // |
| // Copyright (c) 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/RewriteElseBlocks.h" |
| |
| #include "compiler/translator/Intermediate.h" |
| #include "compiler/translator/NodeSearch.h" |
| #include "compiler/translator/SymbolTable.h" |
| |
| namespace sh |
| { |
| |
| namespace |
| { |
| |
| class ElseBlockRewriter : public TIntermTraverser |
| { |
| public: |
| ElseBlockRewriter(); |
| |
| protected: |
| bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override; |
| bool visitBlock(Visit visit, TIntermBlock *block) override; |
| |
| private: |
| const TType *mFunctionType; |
| |
| TIntermNode *rewriteIfElse(TIntermIfElse *ifElse); |
| }; |
| |
| ElseBlockRewriter::ElseBlockRewriter() : TIntermTraverser(true, false, true), 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); |
| |
| nextTemporaryIndex(); |
| |
| TIntermDeclaration *storeCondition = createTempInitDeclaration(ifElse->getCondition()); |
| |
| 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) |
| { |
| TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() |
| : mFunctionType->getBasicString(); |
| TString rawText = "return (" + typeString + ")0"; |
| TIntermRaw *returnNode = new TIntermRaw(*mFunctionType, rawText); |
| negatedElse = new TIntermBlock(); |
| negatedElse->getSequence()->push_back(returnNode); |
| } |
| |
| TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType); |
| TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot, conditionSymbolElse); |
| TIntermIfElse *falseIfElse = |
| new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse); |
| falseBlock = TIntermediate::EnsureBlock(falseIfElse); |
| } |
| |
| TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType); |
| TIntermIfElse *newIfElse = |
| new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock); |
| |
| TIntermBlock *block = new TIntermBlock(); |
| block->getSequence()->push_back(storeCondition); |
| block->getSequence()->push_back(newIfElse); |
| |
| return block; |
| } |
| } |
| |
| void RewriteElseBlocks(TIntermNode *node, unsigned int *temporaryIndex) |
| { |
| ElseBlockRewriter rewriter; |
| rewriter.useTemporaryIndex(temporaryIndex); |
| node->traverse(&rewriter); |
| } |
| } |