Implemented short-circuiting behavior for the ternary operator
TRAC #11444
This is achieved by turning the ternary operator into conditional code.
The UnfoldSelect intermediate code traverser places this conditional
code before the statement containing the ternary operator (aka. select).
The computed value is assigned to a temporary variable.
On outputting the actual statement the ternary operator is
replaced by the temporary variable.
Signed-off-by: Andrew Lewycky
Signed-off-by: Daniel Koch
Author: Nicolas Capens
git-svn-id: https://angleproject.googlecode.com/svn/trunk@148 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 38fd3c6..30d77df 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -6,6 +6,7 @@
#include "OutputHLSL.h"
+#include "UnfoldSelect.h"
#include "common/debug.h"
#include "InfoSink.h"
@@ -13,6 +14,8 @@
{
OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
{
+ mUnfoldSelect = new UnfoldSelect(context, this);
+
mUsesEqualMat2 = false;
mUsesEqualMat3 = false;
mUsesEqualMat4 = false;
@@ -27,6 +30,11 @@
mUsesEqualBVec4 = false;
}
+OutputHLSL::~OutputHLSL()
+{
+ delete mUnfoldSelect;
+}
+
void OutputHLSL::output()
{
mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
@@ -38,6 +46,11 @@
mContext.infoSink.obj << mFooter.c_str();
}
+TInfoSinkBase &OutputHLSL::getBodyStream()
+{
+ return mBody;
+}
+
void OutputHLSL::header()
{
EShLanguage language = mContext.language;
@@ -933,7 +946,22 @@
switch (node->getOp())
{
- case EOpSequence: outputTriplet(visit, NULL, ";\n", ";\n"); break;
+ case EOpSequence:
+ {
+ for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
+ {
+ if (isSingleStatement(*sit))
+ {
+ mUnfoldSelect->traverse(*sit);
+ }
+
+ (*sit)->traverse(this);
+
+ out << ";\n";
+ }
+
+ return false;
+ }
case EOpDeclaration:
if (visit == PreVisit)
{
@@ -1200,16 +1228,12 @@
if (node->usesTernaryOperator())
{
- out << "(";
- node->getCondition()->traverse(this);
- out << ") ? (";
- node->getTrueBlock()->traverse(this);
- out << ") : (";
- node->getFalseBlock()->traverse(this);
- out << ")\n";
+ out << "t" << mUnfoldSelect->getTemporaryIndex();
}
else // if/else statement
{
+ mUnfoldSelect->traverse(node->getCondition());
+
out << "if(";
node->getCondition()->traverse(this);
@@ -1373,6 +1397,21 @@
}
else
{
+ if (node->getInit())
+ {
+ mUnfoldSelect->traverse(node->getInit());
+ }
+
+ if (node->getTest())
+ {
+ mUnfoldSelect->traverse(node->getTest());
+ }
+
+ if (node->getTerminal())
+ {
+ mUnfoldSelect->traverse(node->getTerminal());
+ }
+
out << "for(";
if (node->getInit())
@@ -1451,6 +1490,33 @@
return true;
}
+bool OutputHLSL::isSingleStatement(TIntermNode *node)
+{
+ TIntermAggregate *aggregate = node->getAsAggregate();
+
+ if (aggregate)
+ {
+ if (aggregate->getOp() == EOpSequence)
+ {
+ return false;
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
+ {
+ if (!isSingleStatement(*sit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return true;
+}
+
// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
{