Move the rest of the validation out of TIntermBinary::promote
TIntermBinary::promote now has a single purpose of determining the
type resulting from a binary math operation. The TIntermBinary
constructor taking the left and right nodes can now also call promote
automatically, and promote is made into a private member of
TIntermBinary. Validation of binary math operand types is done
inside ParseContext.
BUG=angleproject:952
TEST=angle_unittests
Change-Id: I52a409f680c8d4120b757193972d03aed34c6895
Reviewed-on: https://chromium-review.googlesource.com/372624
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index abe3712..66fdceb 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -3533,8 +3533,10 @@
return false;
}
- // Check that type sizes match exactly on ops that require that.
- // Also check restrictions for structs that contain arrays or samplers.
+ // Check that:
+ // 1. Type sizes match exactly on ops that require that.
+ // 2. Restrictions for structs that contain arrays or samplers are respected.
+ // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected.
switch (op)
{
case EOpAssign:
@@ -3567,6 +3569,48 @@
{
return false;
}
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpIMod:
+ case EOpBitShiftLeft:
+ case EOpBitShiftRight:
+ case EOpBitwiseAnd:
+ case EOpBitwiseXor:
+ case EOpBitwiseOr:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ case EOpIModAssign:
+ case EOpBitShiftLeftAssign:
+ case EOpBitShiftRightAssign:
+ case EOpBitwiseAndAssign:
+ case EOpBitwiseXorAssign:
+ case EOpBitwiseOrAssign:
+ if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()))
+ {
+ return false;
+ }
+
+ // Are the sizes compatible?
+ if (left->getNominalSize() != right->getNominalSize() ||
+ left->getSecondarySize() != right->getSecondarySize())
+ {
+ // If the nominal sizes of operands do not match:
+ // One of them must be a scalar.
+ if (!left->isScalar() && !right->isScalar())
+ return false;
+
+ // In the case of compound assignment other than multiply-assign,
+ // the right side needs to be a scalar. Otherwise a vector/matrix
+ // would be assigned to a scalar. A scalar can't be shifted by a
+ // vector either.
+ if (!right->isScalar() &&
+ (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight))
+ return false;
+ }
+ break;
default:
break;
}
@@ -3671,8 +3715,6 @@
return nullptr;
}
break;
- // Note that for bitwise ops, type checking is done in promote() to
- // share code between ops and compound assignment
default:
break;
}
@@ -3689,9 +3731,6 @@
TIntermBinary *node = new TIntermBinary(op, left, right);
node->setLine(loc);
- if (!node->promote())
- return nullptr;
-
// See if we can fold constants.
TIntermTyped *foldedNode = node->fold(&mDiagnostics);
if (foldedNode)
@@ -3751,9 +3790,6 @@
TIntermBinary *node = new TIntermBinary(op, left, right);
node->setLine(loc);
- if (!node->promote())
- return nullptr;
-
return node;
}
return nullptr;