• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "compiler/translator/NodeSearch.h"
12 #include "compiler/translator/SymbolTable.h"
13 
14 namespace sh
15 {
16 
17 namespace
18 {
19 
20 class ElseBlockRewriter : public TIntermTraverser
21 {
22   public:
23     ElseBlockRewriter();
24 
25   protected:
26     bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
27 
28   private:
29     int mTemporaryIndex;
30     const TType *mFunctionType;
31 
32     TIntermNode *rewriteSelection(TIntermSelection *selection);
33 };
34 
MakeNewTemporary(const TString & name,TBasicType type)35 TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
36 {
37     TType variableType(type, EbpHigh, EvqInternal);
38     return new TIntermSymbol(-1, name, variableType);
39 }
40 
MakeNewBinary(TOperator op,TIntermTyped * left,TIntermTyped * right,const TType & resultType)41 TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
42 {
43     TIntermBinary *binary = new TIntermBinary(op);
44     binary->setLeft(left);
45     binary->setRight(right);
46     binary->setType(resultType);
47     return binary;
48 }
49 
MakeNewUnary(TOperator op,TIntermTyped * operand)50 TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
51 {
52     TIntermUnary *unary = new TIntermUnary(op, operand->getType());
53     unary->setOperand(operand);
54     return unary;
55 }
56 
ElseBlockRewriter()57 ElseBlockRewriter::ElseBlockRewriter()
58     : TIntermTraverser(true, false, true, false),
59       mTemporaryIndex(0),
60       mFunctionType(NULL)
61 {}
62 
visitAggregate(Visit visit,TIntermAggregate * node)63 bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
64 {
65     switch (node->getOp())
66     {
67       case EOpSequence:
68         if (visit == PostVisit)
69         {
70             for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++)
71             {
72                 TIntermNode *statement = (*node->getSequence())[statementIndex];
73                 TIntermSelection *selection = statement->getAsSelectionNode();
74                 if (selection && selection->getFalseBlock() != NULL)
75                 {
76                     // Check for if / else if
77                     TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode();
78                     if (elseIfBranch)
79                     {
80                         selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch));
81                         delete elseIfBranch;
82                     }
83 
84                     (*node->getSequence())[statementIndex] = rewriteSelection(selection);
85                     delete selection;
86                 }
87             }
88         }
89         break;
90 
91       case EOpFunction:
92         // Store the current function context (see comment below)
93         mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
94         break;
95 
96       default: break;
97     }
98 
99     return true;
100 }
101 
rewriteSelection(TIntermSelection * selection)102 TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
103 {
104     ASSERT(selection != NULL);
105 
106     TString temporaryName = "cond_" + str(mTemporaryIndex++);
107     TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
108     TType resultType(EbtBool, EbpUndefined);
109     TIntermSymbol *conditionSymbolInit = MakeNewTemporary(temporaryName, EbtBool);
110     TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolInit,
111                                                   typedCondition, resultType);
112     TIntermNode *negatedElse = NULL;
113 
114     TIntermSelection *falseBlock = NULL;
115 
116     if (selection->getFalseBlock())
117     {
118         // crbug.com/346463
119         // D3D generates error messages claiming a function has no return value, when rewriting
120         // an if-else clause that returns something non-void in a function. By appending dummy
121         // returns (that are unreachable) we can silence this compile error.
122         if (mFunctionType && mFunctionType->getBasicType() != EbtVoid)
123         {
124             TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() :
125                 mFunctionType->getBasicString();
126             TString rawText = "return (" + typeString + ")0";
127             negatedElse = new TIntermRaw(*mFunctionType, rawText);
128         }
129 
130         TIntermSymbol *conditionSymbolElse = MakeNewTemporary(temporaryName, EbtBool);
131         TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse);
132         falseBlock = new TIntermSelection(negatedCondition,
133                                           selection->getFalseBlock(), negatedElse);
134     }
135 
136     TIntermSymbol *conditionSymbolSel = MakeNewTemporary(temporaryName, EbtBool);
137     TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel,
138                                                           selection->getTrueBlock(), falseBlock);
139 
140     TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
141     declaration->getSequence()->push_back(storeCondition);
142 
143     TIntermAggregate *block = new TIntermAggregate(EOpSequence);
144     block->getSequence()->push_back(declaration);
145     block->getSequence()->push_back(newSelection);
146 
147     return block;
148 }
149 
150 }
151 
RewriteElseBlocks(TIntermNode * node)152 void RewriteElseBlocks(TIntermNode *node)
153 {
154     ElseBlockRewriter rewriter;
155     node->traverse(&rewriter);
156 }
157 
158 }
159