1 // 2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // RewriteElseBlocks.cpp: Implementation for tree transform to change 7 // all if-else blocks to if-if blocks. 8 // 9 10 #include "compiler/translator/RewriteElseBlocks.h" 11 #include "compiler/translator/NodeSearch.h" 12 #include "compiler/translator/SymbolTable.h" 13 14 namespace sh 15 { 16 17 namespace 18 { 19 20 class ElseBlockRewriter : public TIntermTraverser 21 { 22 public: 23 ElseBlockRewriter(); 24 25 protected: 26 bool visitAggregate(Visit visit, TIntermAggregate *aggregate); 27 28 private: 29 int mTemporaryIndex; 30 const TType *mFunctionType; 31 32 TIntermNode *rewriteSelection(TIntermSelection *selection); 33 }; 34 35 TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type) 36 { 37 TType variableType(type, EbpHigh, EvqInternal); 38 return new TIntermSymbol(-1, name, variableType); 39 } 40 41 TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType) 42 { 43 TIntermBinary *binary = new TIntermBinary(op); 44 binary->setLeft(left); 45 binary->setRight(right); 46 binary->setType(resultType); 47 return binary; 48 } 49 50 TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) 51 { 52 TIntermUnary *unary = new TIntermUnary(op, operand->getType()); 53 unary->setOperand(operand); 54 return unary; 55 } 56 57 ElseBlockRewriter::ElseBlockRewriter() 58 : TIntermTraverser(true, false, true, false), 59 mTemporaryIndex(0), 60 mFunctionType(NULL) 61 {} 62 63 bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) 64 { 65 switch (node->getOp()) 66 { 67 case EOpSequence: 68 if (visit == PostVisit) 69 { 70 for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++) 71 { 72 TIntermNode *statement = (*node->getSequence())[statementIndex]; 73 TIntermSelection *selection = statement->getAsSelectionNode(); 74 if (selection && selection->getFalseBlock() != NULL) 75 { 76 // Check for if / else if 77 TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode(); 78 if (elseIfBranch) 79 { 80 selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch)); 81 delete elseIfBranch; 82 } 83 84 (*node->getSequence())[statementIndex] = rewriteSelection(selection); 85 delete selection; 86 } 87 } 88 } 89 break; 90 91 case EOpFunction: 92 // Store the current function context (see comment below) 93 mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL); 94 break; 95 96 default: break; 97 } 98 99 return true; 100 } 101 102 TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) 103 { 104 ASSERT(selection != NULL); 105 106 TString temporaryName = "cond_" + str(mTemporaryIndex++); 107 TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); 108 TType resultType(EbtBool, EbpUndefined); 109 TIntermSymbol *conditionSymbolInit = MakeNewTemporary(temporaryName, EbtBool); 110 TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolInit, 111 typedCondition, resultType); 112 TIntermNode *negatedElse = NULL; 113 114 TIntermSelection *falseBlock = NULL; 115 116 if (selection->getFalseBlock()) 117 { 118 // crbug.com/346463 119 // D3D generates error messages claiming a function has no return value, when rewriting 120 // an if-else clause that returns something non-void in a function. By appending dummy 121 // returns (that are unreachable) we can silence this compile error. 122 if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) 123 { 124 TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() : 125 mFunctionType->getBasicString(); 126 TString rawText = "return (" + typeString + ")0"; 127 negatedElse = new TIntermRaw(*mFunctionType, rawText); 128 } 129 130 TIntermSymbol *conditionSymbolElse = MakeNewTemporary(temporaryName, EbtBool); 131 TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse); 132 falseBlock = new TIntermSelection(negatedCondition, 133 selection->getFalseBlock(), negatedElse); 134 } 135 136 TIntermSymbol *conditionSymbolSel = MakeNewTemporary(temporaryName, EbtBool); 137 TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel, 138 selection->getTrueBlock(), falseBlock); 139 140 TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration); 141 declaration->getSequence()->push_back(storeCondition); 142 143 TIntermAggregate *block = new TIntermAggregate(EOpSequence); 144 block->getSequence()->push_back(declaration); 145 block->getSequence()->push_back(newSelection); 146 147 return block; 148 } 149 150 } 151 152 void RewriteElseBlocks(TIntermNode *node) 153 { 154 ElseBlockRewriter rewriter; 155 node->traverse(&rewriter); 156 } 157 158 } 159