• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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