Unroll for-loop if sampler array uses loop index as its index.
If inside a for-loop, sampler array index is the loop index, Mac cg compiler will crash. This CL unroll the loop in such situation. The behavior is:
1) If the for-loop index is a float, we reject the shader.
2) If it is an integer, we unroll the for-loop.
Things that should be done in the future are:
1) Add line number macros.
2) Add a limit to unroll iteration count.
anglebug=94
Review URL: http://codereview.appspot.com/4331048
git-svn-id: https://angleproject.googlecode.com/svn/trunk@606 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/ValidateLimitations.cpp b/src/compiler/ValidateLimitations.cpp
index 886f693..b46e4b9 100644
--- a/src/compiler/ValidateLimitations.cpp
+++ b/src/compiler/ValidateLimitations.cpp
@@ -17,6 +17,17 @@
return false;
}
+void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) {
+ for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId()) {
+ ASSERT(i->loop != NULL);
+ i->loop->setUnrollFlag(true);
+ return;
+ }
+ }
+ UNREACHABLE();
+}
+
// Traverses a node to check if it represents a constant index expression.
// Definition:
// constant-index-expressions are a superset of constant-expressions.
@@ -54,6 +65,48 @@
bool mValid;
const TLoopStack& mLoopStack;
};
+
+// Traverses a node to check if it uses a loop index.
+// If an int loop index is used in its body as a sampler array index,
+// mark the loop for unroll.
+class ValidateLoopIndexExpr : public TIntermTraverser {
+public:
+ ValidateLoopIndexExpr(TLoopStack& stack)
+ : mUsesFloatLoopIndex(false),
+ mUsesIntLoopIndex(false),
+ mLoopStack(stack) {}
+
+ bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; }
+ bool usesIntLoopIndex() const { return mUsesIntLoopIndex; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ if (IsLoopIndex(symbol, mLoopStack)) {
+ switch (symbol->getBasicType()) {
+ case EbtFloat:
+ mUsesFloatLoopIndex = true;
+ break;
+ case EbtInt:
+ mUsesIntLoopIndex = true;
+ MarkLoopForUnroll(symbol, mLoopStack);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit, TIntermBinary*) { return true; }
+ virtual bool visitUnary(Visit, TIntermUnary*) { return true; }
+ virtual bool visitSelection(Visit, TIntermSelection*) { return true; }
+ virtual bool visitAggregate(Visit, TIntermAggregate*) { return true; }
+ virtual bool visitLoop(Visit, TIntermLoop*) { return true; }
+ virtual bool visitBranch(Visit, TIntermBranch*) { return true; }
+
+private:
+ bool mUsesFloatLoopIndex;
+ bool mUsesIntLoopIndex;
+ TLoopStack& mLoopStack;
+};
} // namespace
ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
@@ -80,7 +133,28 @@
// Check indexing.
switch (node->getOp()) {
case EOpIndexDirect:
+ validateIndexing(node);
+ break;
case EOpIndexIndirect:
+#if defined(__APPLE__)
+ // Loop unrolling is a work-around for a Mac Cg compiler bug where it
+ // crashes when a sampler array's index is also the loop index.
+ // Once Apple fixes this bug, we should remove the code in this CL.
+ // See http://codereview.appspot.com/4331048/.
+ if ((node->getLeft() != NULL) && (node->getRight() != NULL) &&
+ (node->getLeft()->getAsSymbolNode())) {
+ TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode();
+ if (IsSampler(symbol->getBasicType()) && symbol->isArray()) {
+ ValidateLoopIndexExpr validate(mLoopStack);
+ node->getRight()->traverse(&validate);
+ if (validate.usesFloatLoopIndex()) {
+ error(node->getLine(),
+ "sampler array index is float loop index",
+ "for");
+ }
+ }
+ }
+#endif
validateIndexing(node);
break;
default: break;
@@ -120,6 +194,7 @@
TLoopInfo info;
memset(&info, 0, sizeof(TLoopInfo));
+ info.loop = node;
if (!validateForLoopHeader(node, &info))
return false;