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.
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.
11 #include "compiler/translator/UnfoldShortCircuit.h"
13 #include "compiler/translator/InfoSink.h"
14 #include "compiler/translator/OutputHLSL.h"
15 #include "compiler/translator/UtilsHLSL.h"
19 UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
24 void UnfoldShortCircuit::traverse(TIntermNode *node)
26 int rewindIndex = mTemporaryIndex;
28 mTemporaryIndex = rewindIndex;
31 bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
33 TInfoSinkBase &out = mOutputHLSL->getBodyStream();
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())
43 switch (node->getOp())
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;".
49 int i = mTemporaryIndex;
51 out << "bool s" << i << ";\n";
55 mTemporaryIndex = i + 1;
56 node->getLeft()->traverse(this);
57 out << "s" << i << " = ";
58 mTemporaryIndex = i + 1;
59 node->getLeft()->traverse(mOutputHLSL);
61 out << "if (!s" << i << ")\n"
63 mTemporaryIndex = i + 1;
64 node->getRight()->traverse(this);
65 out << " s" << i << " = ";
66 mTemporaryIndex = i + 1;
67 node->getRight()->traverse(mOutputHLSL);
73 mTemporaryIndex = i + 1;
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;".
80 int i = mTemporaryIndex;
82 out << "bool s" << i << ";\n";
86 mTemporaryIndex = i + 1;
87 node->getLeft()->traverse(this);
88 out << "s" << i << " = ";
89 mTemporaryIndex = i + 1;
90 node->getLeft()->traverse(mOutputHLSL);
92 out << "if (s" << i << ")\n"
94 mTemporaryIndex = i + 1;
95 node->getRight()->traverse(this);
96 out << " s" << i << " = ";
97 mTemporaryIndex = i + 1;
98 node->getRight()->traverse(mOutputHLSL);
104 mTemporaryIndex = i + 1;
112 bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
114 TInfoSinkBase &out = mOutputHLSL->getBodyStream();
116 // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
117 if (node->usesTernaryOperator())
119 int i = mTemporaryIndex;
121 out << TypeString(node->getType()) << " s" << i << ";\n";
125 mTemporaryIndex = i + 1;
126 node->getCondition()->traverse(this);
128 mTemporaryIndex = i + 1;
129 node->getCondition()->traverse(mOutputHLSL);
132 mTemporaryIndex = i + 1;
133 node->getTrueBlock()->traverse(this);
134 out << " s" << i << " = ";
135 mTemporaryIndex = i + 1;
136 node->getTrueBlock()->traverse(mOutputHLSL);
141 mTemporaryIndex = i + 1;
142 node->getFalseBlock()->traverse(this);
143 out << " s" << i << " = ";
144 mTemporaryIndex = i + 1;
145 node->getFalseBlock()->traverse(mOutputHLSL);
151 mTemporaryIndex = i + 1;
157 bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node)
159 int rewindIndex = mTemporaryIndex;
163 node->getInit()->traverse(this);
166 if (node->getCondition())
168 node->getCondition()->traverse(this);
171 if (node->getExpression())
173 node->getExpression()->traverse(this);
176 mTemporaryIndex = rewindIndex;
181 int UnfoldShortCircuit::getNextTemporaryIndex()
183 return mTemporaryIndex++;