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/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
ElseBlockRewriter(TSymbolTable * symbolTable)39 ElseBlockRewriter::ElseBlockRewriter(TSymbolTable *symbolTable)
40 : TIntermTraverser(true, false, true, symbolTable), mFunctionType(nullptr)
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 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 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 = 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
RewriteElseBlocks(TCompiler * compiler,TIntermNode * node,TSymbolTable * symbolTable)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
124