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