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
This commit is contained in:
daniel@transgaming.com 2010-04-15 20:44:53 +00:00
Родитель ec55d29a1c
Коммит b587598cb8
6 изменённых файлов: 198 добавлений и 16 удалений

Просмотреть файл

@ -134,6 +134,8 @@
'compiler/OutputHLSL.h',
'compiler/TranslatorHLSL.cpp',
'compiler/TranslatorHLSL.h',
'compiler/UnfoldSelect.cpp',
'compiler/UnfoldSelect.h',
],
},
{

Просмотреть файл

@ -6,6 +6,7 @@
#include "OutputHLSL.h"
#include "UnfoldSelect.h"
#include "common/debug.h"
#include "InfoSink.h"
@ -13,6 +14,8 @@ namespace sh
{
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 @@ OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, tr
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 @@ void OutputHLSL::output()
mContext.infoSink.obj << mFooter.c_str();
}
TInfoSinkBase &OutputHLSL::getBodyStream()
{
return mBody;
}
void OutputHLSL::header()
{
EShLanguage language = mContext.language;
@ -933,7 +946,22 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
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 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
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 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
}
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 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
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)
{

Просмотреть файл

@ -12,13 +12,25 @@
namespace sh
{
class UnfoldSelect;
class OutputHLSL : public TIntermTraverser
{
public:
OutputHLSL(TParseContext &context);
explicit OutputHLSL(TParseContext &context);
~OutputHLSL();
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:
void header();
void footer();
@ -33,17 +45,12 @@ class OutputHLSL : public TIntermTraverser
bool visitLoop(Visit visit, TIntermLoop*);
bool visitBranch(Visit visit, TIntermBranch*);
bool isSingleStatement(TIntermNode *node);
bool handleExcessiveLoop(TIntermLoop *node);
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;
UnfoldSelect *mUnfoldSelect;
// Output streams
TInfoSinkBase mHeader;

Просмотреть файл

@ -0,0 +1,64 @@
//
// 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;
}
}

Просмотреть файл

@ -0,0 +1,35 @@
//
// 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 @@
RelativePath=".\TranslatorHLSL.cpp"
>
</File>
<File
RelativePath=".\UnfoldSelect.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
@ -176,6 +180,10 @@
RelativePath=".\TranslatorHLSL.h"
>
</File>
<File
RelativePath=".\UnfoldSelect.h"
>
</File>
</Filter>
</Files>
<Globals>