Break up loops with over 255 iterations.

TRAC# 11724 fixes acos/asin conformance Signed-off-by: Shannon Woods Signed-off-by: Daniel Koch Author: Nicolas Capens git-svn-id: https://angleproject.googlecode.com/svn/trunk@105 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent cf2560dd
......@@ -1165,6 +1165,11 @@ void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
{
if (handleExcessiveLoop(node))
{
return false;
}
TInfoSinkBase &out = context.infoSink.obj;
if (!node->testFirst())
......@@ -1252,6 +1257,172 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
return true;
}
// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
{
TInfoSinkBase &out = context.infoSink.obj;
// Parse loops of the form:
// for(int index = initial; index [comparator] limit; index += increment)
TIntermSymbol *index = NULL;
TOperator comparator = EOpNull;
int initial = 0;
int limit = 0;
int increment = 0;
// Parse index name and intial value
if (node->getInit())
{
TIntermAggregate *init = node->getInit()->getAsAggregate();
if (init)
{
TIntermSequence &sequence = init->getSequence();
TIntermTyped *variable = sequence[0]->getAsTyped();
if (variable && variable->getQualifier() == EvqTemporary)
{
TIntermBinary *assign = variable->getAsBinaryNode();
if (assign->getOp() == EOpInitialize)
{
TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
if (symbol && constant)
{
if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
{
index = symbol;
initial = constant->getUnionArrayPointer()[0].getIConst();
}
}
}
}
}
}
// Parse comparator and limit value
if (index != NULL && node->getTest())
{
TIntermBinary *test = node->getTest()->getAsBinaryNode();
if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
{
TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
if (constant)
{
if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
{
comparator = test->getOp();
limit = constant->getUnionArrayPointer()[0].getIConst();
}
}
}
}
// Parse increment
if (index != NULL && comparator != EOpNull && node->getTerminal())
{
TIntermBinary *binaryTerminal = node->getTerminal()->getAsBinaryNode();
TIntermUnary *unaryTerminal = node->getTerminal()->getAsUnaryNode();
if (binaryTerminal)
{
TOperator op = binaryTerminal->getOp();
TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
if (constant)
{
if (constant->getBasicType() == EbtInt && constant->getSize() == 1)
{
int value = constant->getUnionArrayPointer()[0].getIConst();
switch (op)
{
case EOpAddAssign: increment = value; break;
case EOpSubAssign: increment = -value; break;
default: UNIMPLEMENTED();
}
}
}
}
else if (unaryTerminal)
{
TOperator op = unaryTerminal->getOp();
switch (op)
{
case EOpPostIncrement: increment = 1; break;
case EOpPostDecrement: increment = -1; break;
case EOpPreIncrement: increment = 1; break;
case EOpPreDecrement: increment = -1; break;
default: UNIMPLEMENTED();
}
}
}
if (index != NULL && comparator != EOpNull && increment != 0)
{
if (comparator == EOpLessThanEqual)
{
comparator = EOpLessThan;
limit += 1;
}
if (comparator == EOpLessThan)
{
int iterations = (limit - initial + 1) / increment;
if (iterations <= 255)
{
return false; // Not an excessive loop
}
while (iterations > 0)
{
int remainder = (limit - initial + 1) % increment;
int clampedLimit = initial + increment * min(255, iterations) - 1 - remainder;
// for(int index = initial; index < clampedLimit; index += increment)
out << "for(int ";
index->traverse(this);
out << " = ";
out << initial;
out << "; ";
index->traverse(this);
out << " < ";
out << clampedLimit;
out << "; ";
index->traverse(this);
out << " += ";
out << increment;
out << ")\n"
"{\n";
if (node->getBody())
{
node->getBody()->traverse(this);
}
out << "}\n";
initial += 255 * increment;
iterations -= 255;
}
return true;
}
else UNIMPLEMENTED();
}
return false; // Not handled as an excessive loop
}
void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString)
{
TInfoSinkBase &out = context.infoSink.obj;
......
......@@ -30,6 +30,7 @@ class OutputHLSL : public TIntermTraverser
bool visitLoop(Visit visit, TIntermLoop*);
bool visitBranch(Visit visit, TIntermBranch*);
bool handleExcessiveLoop(TIntermLoop *node);
void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString);
static TString typeString(const TType &type);
......
......@@ -185,6 +185,7 @@ enum TOperator {
class TIntermTraverser;
class TIntermAggregate;
class TIntermBinary;
class TIntermUnary;
class TIntermConstantUnion;
class TIntermSelection;
class TIntermTyped;
......@@ -206,6 +207,7 @@ public:
virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
virtual TIntermAggregate* getAsAggregate() { return 0; }
virtual TIntermBinary* getAsBinaryNode() { return 0; }
virtual TIntermUnary* getAsUnaryNode() { return 0; }
virtual TIntermSelection* getAsSelectionNode() { return 0; }
virtual TIntermSymbol* getAsSymbolNode() { return 0; }
virtual ~TIntermNode() { }
......@@ -221,9 +223,6 @@ struct TIntermNodePair {
TIntermNode* node2;
};
class TIntermSymbol;
class TIntermBinary;
//
// Intermediate class for nodes that have a type.
//
......@@ -365,6 +364,7 @@ public:
virtual void traverse(TIntermTraverser*);
virtual void setOperand(TIntermTyped* o) { operand = o; }
virtual TIntermTyped* getOperand() { return operand; }
virtual TIntermUnary* getAsUnaryNode() { return this; }
virtual bool promote(TInfoSink&);
protected:
TIntermTyped* operand;
......
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