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 
12 #include "compiler/translator/IntermNode.h"
13 #include "compiler/translator/IntermNode_util.h"
14 #include "compiler/translator/NodeSearch.h"
15 #include "compiler/translator/SymbolTable.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
23 class ElseBlockRewriter : public TIntermTraverser
24 {
25   public:
26     ElseBlockRewriter(TSymbolTable *symbolTable);
27 
28   protected:
29     bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *aggregate) override;
30     bool visitBlock(Visit visit, TIntermBlock *block) override;
31 
32   private:
33     TIntermNode *rewriteIfElse(TIntermIfElse *ifElse);
34 
35     const TType *mFunctionType;
36 };
37 
ElseBlockRewriter(TSymbolTable * symbolTable)38 ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable)
39     : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr)
40 {
41 }
42 
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * node)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 
visitBlock(Visit visit,TIntermBlock * node)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 
rewriteIfElse(TIntermIfElse * ifElse)68 TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse)
69 {
70     ASSERT(ifElse != nullptr);
71 
72     nextTemporaryId();
73 
74     TIntermDeclaration *storeCondition = createTempInitDeclaration(ifElse->getCondition());
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 dummy
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 = createTempSymbol(boolType);
95         TIntermUnary *negatedCondition     = new TIntermUnary(EOpLogicalNot, conditionSymbolElse);
96         TIntermIfElse *falseIfElse =
97             new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse);
98         falseBlock = EnsureBlock(falseIfElse);
99     }
100 
101     TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType);
102     TIntermIfElse *newIfElse =
103         new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock);
104 
105     TIntermBlock *block = new TIntermBlock();
106     block->getSequence()->push_back(storeCondition);
107     block->getSequence()->push_back(newIfElse);
108 
109     return block;
110 }
111 
112 }  // anonymous namespace
113 
RewriteElseBlocks(TIntermNode * node,TSymbolTable * symbolTable)114 void RewriteElseBlocks(TIntermNode *node, TSymbolTable *symbolTable)
115 {
116     ElseBlockRewriter rewriter(symbolTable);
117     node->traverse(&rewriter);
118 }
119 
120 }  // namespace sh
121