RewriteElseBlocks.cpp (4093B)
1 // 2 // Copyright 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/tree_ops/d3d/RewriteElseBlocks.h" 11 12 #include "compiler/translator/Compiler.h" 13 #include "compiler/translator/IntermNode.h" 14 #include "compiler/translator/SymbolTable.h" 15 #include "compiler/translator/tree_util/IntermNode_util.h" 16 #include "compiler/translator/tree_util/NodeSearch.h" 17 18 namespace sh 19 { 20 21 namespace 22 { 23 24 class ElseBlockRewriter : public TIntermTraverser 25 { 26 public: 27 ElseBlockRewriter(TSymbolTable *symbolTable); 28 29 protected: 30 bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override; 31 bool visitBlock(Visit visit, TIntermBlock *block) override; 32 33 private: 34 TIntermNode *rewriteIfElse(TIntermIfElse *ifElse); 35 36 const TType *mFunctionType; 37 }; 38 39 ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable) 40 : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr) 41 {} 42 43 bool ElseBlockRewriter::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) 44 { 45 // Store the current function context (see comment below) 46 mFunctionType = ((visit == PreVisit) ? &node->getFunctionPrototype()->getType() : nullptr); 47 return true; 48 } 49 50 bool ElseBlockRewriter::visitBlock(Visit visit, TIntermBlock *node) 51 { 52 if (visit == PostVisit) 53 { 54 for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); 55 statementIndex++) 56 { 57 TIntermNode *statement = (*node->getSequence())[statementIndex]; 58 TIntermIfElse *ifElse = statement->getAsIfElseNode(); 59 if (ifElse && ifElse->getFalseBlock() != nullptr) 60 { 61 (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse); 62 } 63 } 64 } 65 return true; 66 } 67 68 TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse) 69 { 70 ASSERT(ifElse != nullptr); 71 72 TIntermDeclaration *storeCondition = nullptr; 73 TVariable *conditionVariable = 74 DeclareTempVariable(mSymbolTable, ifElse->getCondition(), EvqTemporary, &storeCondition); 75 76 TIntermBlock *falseBlock = nullptr; 77 78 TType boolType(EbtBool, EbpUndefined, EvqTemporary); 79 80 if (ifElse->getFalseBlock()) 81 { 82 TIntermBlock *negatedElse = nullptr; 83 // crbug.com/346463 84 // D3D generates error messages claiming a function has no return value, when rewriting 85 // an if-else clause that returns something non-void in a function. By appending mock 86 // returns (that are unreachable) we can silence this compile error. 87 if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) 88 { 89 TIntermNode *returnNode = new TIntermBranch(EOpReturn, CreateZeroNode(*mFunctionType)); 90 negatedElse = new TIntermBlock(); 91 negatedElse->appendStatement(returnNode); 92 } 93 94 TIntermSymbol *conditionSymbolElse = CreateTempSymbolNode(conditionVariable); 95 TIntermUnary *negatedCondition = 96 new TIntermUnary(EOpLogicalNot, conditionSymbolElse, nullptr); 97 TIntermIfElse *falseIfElse = 98 new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse); 99 falseBlock = EnsureBlock(falseIfElse); 100 } 101 102 TIntermSymbol *conditionSymbolSel = CreateTempSymbolNode(conditionVariable); 103 TIntermIfElse *newIfElse = 104 new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock); 105 106 TIntermBlock *block = new TIntermBlock(); 107 block->getSequence()->push_back(storeCondition); 108 block->getSequence()->push_back(newIfElse); 109 110 return block; 111 } 112 113 } // anonymous namespace 114 115 bool RewriteElseBlocks(TCompiler *compiler, TIntermNode *node, TSymbolTable *symbolTable) 116 { 117 ElseBlockRewriter rewriter(symbolTable); 118 node->traverse(&rewriter); 119 120 return compiler->validateAST(node); 121 } 122 123 } // namespace sh