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
parent ec55d29a
...@@ -134,6 +134,8 @@ ...@@ -134,6 +134,8 @@
'compiler/OutputHLSL.h', 'compiler/OutputHLSL.h',
'compiler/TranslatorHLSL.cpp', 'compiler/TranslatorHLSL.cpp',
'compiler/TranslatorHLSL.h', 'compiler/TranslatorHLSL.h',
'compiler/UnfoldSelect.cpp',
'compiler/UnfoldSelect.h',
], ],
}, },
{ {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "OutputHLSL.h" #include "OutputHLSL.h"
#include "UnfoldSelect.h"
#include "common/debug.h" #include "common/debug.h"
#include "InfoSink.h" #include "InfoSink.h"
...@@ -13,6 +14,8 @@ namespace sh ...@@ -13,6 +14,8 @@ namespace sh
{ {
OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context) OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
{ {
mUnfoldSelect = new UnfoldSelect(context, this);
mUsesEqualMat2 = false; mUsesEqualMat2 = false;
mUsesEqualMat3 = false; mUsesEqualMat3 = false;
mUsesEqualMat4 = false; mUsesEqualMat4 = false;
...@@ -27,6 +30,11 @@ OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, tr ...@@ -27,6 +30,11 @@ OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, tr
mUsesEqualBVec4 = false; mUsesEqualBVec4 = false;
} }
OutputHLSL::~OutputHLSL()
{
delete mUnfoldSelect;
}
void OutputHLSL::output() void OutputHLSL::output()
{ {
mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header and footer
...@@ -38,6 +46,11 @@ void OutputHLSL::output() ...@@ -38,6 +46,11 @@ void OutputHLSL::output()
mContext.infoSink.obj << mFooter.c_str(); mContext.infoSink.obj << mFooter.c_str();
} }
TInfoSinkBase &OutputHLSL::getBodyStream()
{
return mBody;
}
void OutputHLSL::header() void OutputHLSL::header()
{ {
EShLanguage language = mContext.language; EShLanguage language = mContext.language;
...@@ -933,7 +946,22 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -933,7 +946,22 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
switch (node->getOp()) 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: case EOpDeclaration:
if (visit == PreVisit) if (visit == PreVisit)
{ {
...@@ -1200,16 +1228,12 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) ...@@ -1200,16 +1228,12 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
if (node->usesTernaryOperator()) if (node->usesTernaryOperator())
{ {
out << "("; out << "t" << mUnfoldSelect->getTemporaryIndex();
node->getCondition()->traverse(this);
out << ") ? (";
node->getTrueBlock()->traverse(this);
out << ") : (";
node->getFalseBlock()->traverse(this);
out << ")\n";
} }
else // if/else statement else // if/else statement
{ {
mUnfoldSelect->traverse(node->getCondition());
out << "if("; out << "if(";
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
...@@ -1373,6 +1397,21 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) ...@@ -1373,6 +1397,21 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
} }
else else
{ {
if (node->getInit())
{
mUnfoldSelect->traverse(node->getInit());
}
if (node->getTest())
{
mUnfoldSelect->traverse(node->getTest());
}
if (node->getTerminal())
{
mUnfoldSelect->traverse(node->getTerminal());
}
out << "for("; out << "for(";
if (node->getInit()) if (node->getInit())
...@@ -1451,6 +1490,33 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) ...@@ -1451,6 +1490,33 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
return true; 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 // Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
{ {
......
...@@ -12,13 +12,25 @@ ...@@ -12,13 +12,25 @@
namespace sh namespace sh
{ {
class UnfoldSelect;
class OutputHLSL : public TIntermTraverser class OutputHLSL : public TIntermTraverser
{ {
public: public:
OutputHLSL(TParseContext &context); explicit OutputHLSL(TParseContext &context);
~OutputHLSL();
void output(); void output();
TInfoSinkBase &getBodyStream();
static TString argumentString(const TIntermSymbol *symbol);
static TString qualifierString(TQualifier qualifier);
static TString typeString(const TType &type);
static TString arrayString(const TType &type);
static TString initializer(const TType &type);
static TString decorate(const TString &string); // Prepend an underscore to avoid naming clashes
protected: protected:
void header(); void header();
void footer(); void footer();
...@@ -33,17 +45,12 @@ class OutputHLSL : public TIntermTraverser ...@@ -33,17 +45,12 @@ class OutputHLSL : public TIntermTraverser
bool visitLoop(Visit visit, TIntermLoop*); bool visitLoop(Visit visit, TIntermLoop*);
bool visitBranch(Visit visit, TIntermBranch*); bool visitBranch(Visit visit, TIntermBranch*);
bool isSingleStatement(TIntermNode *node);
bool handleExcessiveLoop(TIntermLoop *node); bool handleExcessiveLoop(TIntermLoop *node);
void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString); void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString);
static TString argumentString(const TIntermSymbol *symbol);
static TString qualifierString(TQualifier qualifier);
static TString typeString(const TType &type);
static TString arrayString(const TType &type);
static TString initializer(const TType &type);
static TString decorate(const TString &string); // Prepend an underscore to avoid naming clashes
TParseContext &mContext; TParseContext &mContext;
UnfoldSelect *mUnfoldSelect;
// Output streams // Output streams
TInfoSinkBase mHeader; TInfoSinkBase mHeader;
......
//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "UnfoldSelect.h"
#include "OutputHLSL.h"
#include "common/debug.h"
#include "InfoSink.h"
namespace sh
{
UnfoldSelect::UnfoldSelect(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
{
mTemporaryIndex = 0;
}
void UnfoldSelect::traverse(TIntermNode *node)
{
mTemporaryIndex++;
node->traverse(this);
}
bool UnfoldSelect::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = mOutputHLSL->getBodyStream();
if (node->usesTernaryOperator())
{
int i = mTemporaryIndex++;
out << OutputHLSL::typeString(node->getType()) << " t" << i << ";\n";
node->getCondition()->traverse(this);
out << "if(";
node->getCondition()->traverse(mOutputHLSL);
out << ")\n"
"{\n";
node->getTrueBlock()->traverse(this);
out << " t" << i << " = ";
node->getTrueBlock()->traverse(mOutputHLSL);
out << ";\n"
"}\n"
"else\n"
"{\n";
node->getCondition()->traverse(this);
out << " t" << i << " = ";
node->getFalseBlock()->traverse(mOutputHLSL);
out << ";\n"
"}\n";
mTemporaryIndex--;
}
return false;
}
int UnfoldSelect::getTemporaryIndex()
{
return mTemporaryIndex;
}
}
//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_UNFOLDSELECT_H_
#define COMPILER_UNFOLDSELECT_H_
#include "intermediate.h"
#include "ParseHelper.h"
namespace sh
{
class OutputHLSL;
class UnfoldSelect : public TIntermTraverser
{
public:
UnfoldSelect(TParseContext &context, OutputHLSL *outputHLSL);
void traverse(TIntermNode *node);
bool visitSelection(Visit visit, TIntermSelection *node);
int getTemporaryIndex();
protected:
TParseContext &mContext;
OutputHLSL *const mOutputHLSL;
int mTemporaryIndex;
};
}
#endif // COMPILER_UNFOLDSELECT_H_
...@@ -162,6 +162,10 @@ ...@@ -162,6 +162,10 @@
RelativePath=".\TranslatorHLSL.cpp" RelativePath=".\TranslatorHLSL.cpp"
> >
</File> </File>
<File
RelativePath=".\UnfoldSelect.cpp"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Header Files" Name="Header Files"
...@@ -176,6 +180,10 @@ ...@@ -176,6 +180,10 @@
RelativePath=".\TranslatorHLSL.h" RelativePath=".\TranslatorHLSL.h"
> >
</File> </File>
<File
RelativePath=".\UnfoldSelect.h"
>
</File>
</Filter> </Filter>
</Files> </Files>
<Globals> <Globals>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment