TIntermBinary::promote() was incorrectly marking the type of result as const in some cases. The result can only be const if both operands are const. Also cleaned up the function to remove redundant/repeated checks.
BUG=24
TEST=OpenGL ES 2.0 Conformance tests
Review URL: http://codereview.appspot.com/1938047
git-svn-id: https://angleproject.googlecode.com/svn/trunk@385 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/Intermediate.cpp b/src/compiler/Intermediate.cpp
index f65bc80..4a1e02f 100644
--- a/src/compiler/Intermediate.cpp
+++ b/src/compiler/Intermediate.cpp
@@ -10,6 +10,7 @@
#include <float.h>
#include <limits.h>
+#include <algorithm>
#include "compiler/localintermediate.h"
#include "compiler/QualifierAlive.h"
@@ -17,9 +18,10 @@
bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
-TPrecision GetHighestPrecision( TPrecision left, TPrecision right ){
+static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
return left > right ? left : right;
}
+
////////////////////////////////////////////////////////////////////////////
//
// First set of functions are to help build the intermediate representation.
@@ -111,12 +113,6 @@
TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
- if (leftTempConstant)
- leftTempConstant = left->getAsConstantUnion();
-
- if (rightTempConstant)
- rightTempConstant = right->getAsConstantUnion();
-
//
// See if we can fold constants.
//
@@ -764,16 +760,9 @@
//
bool TIntermBinary::promote(TInfoSink& infoSink)
{
- int size = left->getNominalSize();
- if (right->getNominalSize() > size)
- size = right->getNominalSize();
-
- TBasicType type = left->getBasicType();
-
- //
- // Arrays have to be exact matches.
- //
- if ((left->isArray() || right->isArray()) && (left->getType() != right->getType()))
+ // GLSL ES 2.0 does not support implicit type casting.
+ // So the basic type should always match.
+ if (left->getBasicType() != right->getBasicType())
return false;
//
@@ -782,16 +771,27 @@
//
setType(left->getType());
- TPrecision highestPrecision = GetHighestPrecision(left->getPrecision(), right->getPrecision());
- getTypePointer()->changePrecision(highestPrecision);
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
+ getTypePointer()->changePrecision(higherPrecision);
+
+ // Binary operations results in temporary variables unless both
+ // operands are const.
+ if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
+ getTypePointer()->changeQualifier(EvqTemporary);
+ }
//
// Array operations.
//
- if (left->isArray()) {
+ if (left->isArray() || right->isArray()) {
+ //
+ // Arrays types have to be exact matches.
+ //
+ if (left->getType() != right->getType())
+ return false;
switch (op) {
-
//
// Promote to conditional
//
@@ -812,17 +812,16 @@
default:
return false;
}
-
return true;
}
+ int size = std::max(left->getNominalSize(), right->getNominalSize());
+
//
- // All scalars. Code after this test assumes this case is removed!
+ // All scalars. Code after this test assumes this case is removed!
//
if (size == 1) {
-
switch (op) {
-
//
// Promote to conditional
//
@@ -840,33 +839,36 @@
//
case EOpLogicalAnd:
case EOpLogicalOr:
+ // Both operands must be of type bool.
if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
return false;
setType(TType(EbtBool, EbpUndefined));
break;
- //
- // Everything else should have matching types
- //
default:
- if (left->getBasicType() != right->getBasicType() ||
- left->isMatrix() != right->isMatrix())
- return false;
+ break;
}
-
return true;
}
- //
+ // If we reach here, at least one of the operands is vector or matrix.
+ // The other operand could be a scalar, vector, or matrix.
// Are the sizes compatible?
//
- if ( left->getNominalSize() != size && left->getNominalSize() != 1 ||
- right->getNominalSize() != size && right->getNominalSize() != 1)
- return false;
+ if (left->getNominalSize() != right->getNominalSize()) {
+ // If the nominal size of operands do not match:
+ // One of them must be scalar.
+ if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
+ return false;
+ // Operator cannot be of type pure assignment.
+ if (op == EOpAssign || op == EOpInitialize)
+ return false;
+ }
//
// Can these two operands be combined?
//
+ TBasicType basicType = left->getBasicType();
switch (op) {
case EOpMul:
if (!left->isMatrix() && right->isMatrix()) {
@@ -874,12 +876,12 @@
op = EOpVectorTimesMatrix;
else {
op = EOpMatrixTimesScalar;
- setType(TType(type, highestPrecision, EvqTemporary, size, true));
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
}
} else if (left->isMatrix() && !right->isMatrix()) {
if (right->isVector()) {
op = EOpMatrixTimesVector;
- setType(TType(type, highestPrecision, EvqTemporary, size, false));
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
} else {
op = EOpMatrixTimesScalar;
}
@@ -890,7 +892,7 @@
// leave as component product
} else if (left->isVector() || right->isVector()) {
op = EOpVectorTimesScalar;
- setType(TType(type, highestPrecision, EvqTemporary, size, false));
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
}
} else {
infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
@@ -919,18 +921,16 @@
if (! left->isVector())
return false;
op = EOpVectorTimesScalarAssign;
- setType(TType(type, highestPrecision, EvqTemporary, size, false));
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
}
} else {
infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
return false;
}
break;
+
case EOpAssign:
case EOpInitialize:
- if (left->getNominalSize() != right->getNominalSize())
- return false;
- // fall through
case EOpAdd:
case EOpSub:
case EOpDiv:
@@ -938,10 +938,9 @@
case EOpSubAssign:
case EOpDivAssign:
if (left->isMatrix() && right->isVector() ||
- left->isVector() && right->isMatrix() ||
- left->getBasicType() != right->getBasicType())
+ left->isVector() && right->isMatrix())
return false;
- setType(TType(type, highestPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
break;
case EOpEqual:
@@ -951,8 +950,7 @@
case EOpLessThanEqual:
case EOpGreaterThanEqual:
if (left->isMatrix() && right->isVector() ||
- left->isVector() && right->isMatrix() ||
- left->getBasicType() != right->getBasicType())
+ left->isVector() && right->isMatrix())
return false;
setType(TType(EbtBool, EbpUndefined));
break;
@@ -960,24 +958,7 @@
default:
return false;
}
-
- //
- // One more check for assignment. The Resulting type has to match the left operand.
- //
- switch (op) {
- case EOpAssign:
- case EOpInitialize:
- case EOpAddAssign:
- case EOpSubAssign:
- case EOpMulAssign:
- case EOpDivAssign:
- if (getType() != left->getType())
- return false;
- break;
- default:
- break;
- }
-
+
return true;
}