| // |
| // 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/NodeSearch.h" |
| #include "compiler/translator/SymbolTable.h" |
| |
| namespace sh |
| { |
| |
| TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type) |
| { |
| TType variableType(type, EbpHigh, EvqInternal); |
| return new TIntermSymbol(-1, name, variableType); |
| } |
| |
| TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType) |
| { |
| TIntermBinary *binary = new TIntermBinary(op); |
| binary->setLeft(left); |
| binary->setRight(right); |
| binary->setType(resultType); |
| return binary; |
| } |
| |
| TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) |
| { |
| TIntermUnary *unary = new TIntermUnary(op, operand->getType()); |
| unary->setOperand(operand); |
| return unary; |
| } |
| |
| ElseBlockRewriter::ElseBlockRewriter() |
| : TIntermTraverser(true, false, true, false), |
| mTemporaryIndex(0), |
| mFunctionType(NULL) |
| {} |
| |
| bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) |
| { |
| switch (node->getOp()) |
| { |
| case EOpSequence: |
| if (visit == PostVisit) |
| { |
| for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++) |
| { |
| TIntermNode *statement = node->getSequence()[statementIndex]; |
| TIntermSelection *selection = statement->getAsSelectionNode(); |
| if (selection && selection->getFalseBlock() != NULL) |
| { |
| // Check for if / else if |
| TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode(); |
| if (elseIfBranch) |
| { |
| selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch)); |
| delete elseIfBranch; |
| } |
| |
| node->getSequence()[statementIndex] = rewriteSelection(selection); |
| delete selection; |
| } |
| } |
| } |
| break; |
| |
| case EOpFunction: |
| // Store the current function context (see comment below) |
| mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL); |
| break; |
| |
| default: break; |
| } |
| |
| return true; |
| } |
| |
| TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) |
| { |
| ASSERT(selection->getFalseBlock() != NULL); |
| |
| TString temporaryName = "cond_" + str(mTemporaryIndex++); |
| TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); |
| TType resultType(EbtBool, EbpUndefined); |
| TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool); |
| TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool); |
| TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool); |
| TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA, |
| typedCondition, resultType); |
| TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB); |
| TIntermNode *negatedElse = NULL; |
| |
| // 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"; |
| negatedElse = new TIntermRaw(*mFunctionType, rawText); |
| } |
| |
| TIntermSelection *falseBlock = new TIntermSelection(negatedCondition, |
| selection->getFalseBlock(), negatedElse); |
| TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC, |
| selection->getTrueBlock(), falseBlock); |
| |
| TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration); |
| declaration->getSequence().push_back(storeCondition); |
| |
| TIntermAggregate *block = new TIntermAggregate(EOpSequence); |
| block->getSequence().push_back(declaration); |
| block->getSequence().push_back(newIfElse); |
| |
| return block; |
| } |
| |
| void RewriteElseBlocks(TIntermNode *node) |
| { |
| ElseBlockRewriter rewriter; |
| node->traverse(&rewriter); |
| } |
| |
| } |