Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / translator / UnfoldShortCircuit.cpp
1 //
2 // Copyright (c) 2002-2013 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 // UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements.
7 // The results are assigned to s# temporaries, which are used by the main translator instead of
8 // the original expression.
9 //
10
11 #include "compiler/translator/UnfoldShortCircuit.h"
12
13 #include "compiler/translator/InfoSink.h"
14 #include "compiler/translator/OutputHLSL.h"
15 #include "compiler/translator/UtilsHLSL.h"
16
17 namespace sh
18 {
19 UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
20 {
21     mTemporaryIndex = 0;
22 }
23
24 void UnfoldShortCircuit::traverse(TIntermNode *node)
25 {
26     int rewindIndex = mTemporaryIndex;
27     node->traverse(this);
28     mTemporaryIndex = rewindIndex;
29 }
30
31 bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
32 {
33     TInfoSinkBase &out = mOutputHLSL->getBodyStream();
34
35     // If our right node doesn't have side effects, we know we don't need to unfold this
36     // expression: there will be no short-circuiting side effects to avoid
37     // (note: unfolding doesn't depend on the left node -- it will always be evaluated)
38     if (!node->getRight()->hasSideEffects())
39     {
40         return true;
41     }
42
43     switch (node->getOp())
44     {
45       case EOpLogicalOr:
46         // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;",
47         // and then further simplifies down to "bool s = x; if(!s) s = y;".
48         {
49             int i = mTemporaryIndex;
50
51             out << "bool s" << i << ";\n";
52
53             out << "{\n";
54
55             mTemporaryIndex = i + 1;
56             node->getLeft()->traverse(this);
57             out << "s" << i << " = ";
58             mTemporaryIndex = i + 1;
59             node->getLeft()->traverse(mOutputHLSL);
60             out << ";\n";
61             out << "if (!s" << i << ")\n"
62                    "{\n";
63             mTemporaryIndex = i + 1;
64             node->getRight()->traverse(this);
65             out << "    s" << i << " = ";
66             mTemporaryIndex = i + 1;
67             node->getRight()->traverse(mOutputHLSL);
68             out << ";\n"
69                    "}\n";
70
71             out << "}\n";
72
73             mTemporaryIndex = i + 1;
74         }
75         return false;
76       case EOpLogicalAnd:
77         // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;",
78         // and then further simplifies down to "bool s = x; if(s) s = y;".
79         {
80             int i = mTemporaryIndex;
81
82             out << "bool s" << i << ";\n";
83
84             out << "{\n";
85
86             mTemporaryIndex = i + 1;
87             node->getLeft()->traverse(this);
88             out << "s" << i << " = ";
89             mTemporaryIndex = i + 1;
90             node->getLeft()->traverse(mOutputHLSL);
91             out << ";\n";
92             out << "if (s" << i << ")\n"
93                    "{\n";
94             mTemporaryIndex = i + 1;
95             node->getRight()->traverse(this);
96             out << "    s" << i << " = ";
97             mTemporaryIndex = i + 1;
98             node->getRight()->traverse(mOutputHLSL);
99             out << ";\n"
100                    "}\n";
101
102             out << "}\n";
103
104             mTemporaryIndex = i + 1;
105         }
106         return false;
107       default:
108         return true;
109     }
110 }
111
112 bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
113 {
114     TInfoSinkBase &out = mOutputHLSL->getBodyStream();
115
116     // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
117     if (node->usesTernaryOperator())
118     {
119         int i = mTemporaryIndex;
120
121         out << TypeString(node->getType()) << " s" << i << ";\n";
122
123         out << "{\n";
124
125         mTemporaryIndex = i + 1;
126         node->getCondition()->traverse(this);
127         out << "if (";
128         mTemporaryIndex = i + 1;
129         node->getCondition()->traverse(mOutputHLSL);
130         out << ")\n"
131                "{\n";
132         mTemporaryIndex = i + 1;
133         node->getTrueBlock()->traverse(this);
134         out << "    s" << i << " = ";
135         mTemporaryIndex = i + 1;
136         node->getTrueBlock()->traverse(mOutputHLSL);
137         out << ";\n"
138                "}\n"
139                "else\n"
140                "{\n";
141         mTemporaryIndex = i + 1;
142         node->getFalseBlock()->traverse(this);
143         out << "    s" << i << " = ";
144         mTemporaryIndex = i + 1;
145         node->getFalseBlock()->traverse(mOutputHLSL);
146         out << ";\n"
147                "}\n";
148
149         out << "}\n";
150
151         mTemporaryIndex = i + 1;
152     }
153
154     return false;
155 }
156
157 bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node)
158 {
159     int rewindIndex = mTemporaryIndex;
160
161     if (node->getInit())
162     {
163         node->getInit()->traverse(this);
164     }
165     
166     if (node->getCondition())
167     {
168         node->getCondition()->traverse(this);
169     }
170
171     if (node->getExpression())
172     {
173         node->getExpression()->traverse(this);
174     }
175
176     mTemporaryIndex = rewindIndex;
177
178     return false;
179 }
180
181 int UnfoldShortCircuit::getNextTemporaryIndex()
182 {
183     return mTemporaryIndex++;
184 }
185 }