Commit 47fd36a7 by Olli Etuaho

Move some validation from IntermBinary::promote to ParseContext

This makes the role of promote() in the system clearer and helps to make the code more understandable, since more of the checks are in the same logical place. BUG=angleproject:952 TEST=angle_unittests, WebGL conformance tests Change-Id: Idb2de927d872e46210d71cf6de06a6f8c1fc5da1 Reviewed-on: https://chromium-review.googlesource.com/260803Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 4904a79b
...@@ -383,53 +383,13 @@ bool TIntermUnary::promote(TInfoSink &) ...@@ -383,53 +383,13 @@ bool TIntermUnary::promote(TInfoSink &)
// Establishes the type of the resultant operation, as well as // Establishes the type of the resultant operation, as well as
// makes the operator the correct one for the operands. // makes the operator the correct one for the operands.
// //
// Returns false if operator can't work on operands. // For lots of operations it should already be established that the operand
// combination is valid, but returns false if operator can't work on operands.
// //
bool TIntermBinary::promote(TInfoSink &infoSink) bool TIntermBinary::promote(TInfoSink &infoSink)
{ {
ASSERT(mLeft->isArray() == mRight->isArray()); ASSERT(mLeft->isArray() == mRight->isArray());
// GLSL ES 2.0 does not support implicit type casting.
// So the basic type should usually match.
bool basicTypesMustMatch = true;
// Check ops which require integer / ivec parameters
switch (mOp)
{
case EOpBitShiftLeft:
case EOpBitShiftRight:
case EOpBitShiftLeftAssign:
case EOpBitShiftRightAssign:
// Unsigned can be bit-shifted by signed and vice versa, but we need to
// check that the basic type is an integer type.
basicTypesMustMatch = false;
if (!IsInteger(mLeft->getBasicType()) || !IsInteger(mRight->getBasicType()))
{
return false;
}
break;
case EOpBitwiseAnd:
case EOpBitwiseXor:
case EOpBitwiseOr:
case EOpBitwiseAndAssign:
case EOpBitwiseXorAssign:
case EOpBitwiseOrAssign:
// It is enough to check the type of only one operand, since later it
// is checked that the operand types match.
if (!IsInteger(mLeft->getBasicType()))
{
return false;
}
break;
default:
break;
}
if (basicTypesMustMatch && mLeft->getBasicType() != mRight->getBasicType())
{
return false;
}
// //
// Base assumption: just make the type the same as the left // Base assumption: just make the type the same as the left
// operand. Then only deviations from this need be coded. // operand. Then only deviations from this need be coded.
...@@ -474,12 +434,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink) ...@@ -474,12 +434,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
// And and Or operate on conditionals // And and Or operate on conditionals
// //
case EOpLogicalAnd: case EOpLogicalAnd:
case EOpLogicalXor:
case EOpLogicalOr: case EOpLogicalOr:
// Both operands must be of type bool. ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool)
{
return false;
}
setType(TType(EbtBool, EbpUndefined)); setType(TType(EbtBool, EbpUndefined));
break; break;
...@@ -616,6 +573,10 @@ bool TIntermBinary::promote(TInfoSink &infoSink) ...@@ -616,6 +573,10 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
case EOpAssign: case EOpAssign:
case EOpInitialize: case EOpInitialize:
// No more additional checks are needed.
ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
(mLeft->getSecondarySize() == mRight->getSecondarySize()));
break;
case EOpAdd: case EOpAdd:
case EOpSub: case EOpSub:
case EOpDiv: case EOpDiv:
...@@ -658,10 +619,6 @@ bool TIntermBinary::promote(TInfoSink &infoSink) ...@@ -658,10 +619,6 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
mOp == EOpBitShiftLeft || mOp == EOpBitShiftLeft ||
mOp == EOpBitShiftRight)) mOp == EOpBitShiftRight))
return false; return false;
// Operator cannot be of type pure assignment.
if (mOp == EOpAssign || mOp == EOpInitialize)
return false;
} }
{ {
...@@ -683,11 +640,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink) ...@@ -683,11 +640,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink)
case EOpGreaterThan: case EOpGreaterThan:
case EOpLessThanEqual: case EOpLessThanEqual:
case EOpGreaterThanEqual: case EOpGreaterThanEqual:
if ((mLeft->getNominalSize() != mRight->getNominalSize()) || ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
(mLeft->getSecondarySize() != mRight->getSecondarySize())) (mLeft->getSecondarySize() == mRight->getSecondarySize()));
{
return false;
}
setType(TType(EbtBool, EbpUndefined)); setType(TType(EbtBool, EbpUndefined));
break; break;
......
...@@ -2716,7 +2716,7 @@ TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *chil ...@@ -2716,7 +2716,7 @@ TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *chil
return addUnaryMath(op, child, loc); return addUnaryMath(op, child, loc);
} }
bool TParseContext::binaryOpArrayCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc) const TSourceLoc &loc)
{ {
if (left->isArray() || right->isArray()) if (left->isArray() || right->isArray())
...@@ -2750,13 +2750,74 @@ bool TParseContext::binaryOpArrayCheck(TOperator op, TIntermTyped *left, TInterm ...@@ -2750,13 +2750,74 @@ bool TParseContext::binaryOpArrayCheck(TOperator op, TIntermTyped *left, TInterm
return false; return false;
} }
} }
// Check ops which require integer / ivec parameters
bool isBitShift = false;
switch (op)
{
case EOpBitShiftLeft:
case EOpBitShiftRight:
case EOpBitShiftLeftAssign:
case EOpBitShiftRightAssign:
// Unsigned can be bit-shifted by signed and vice versa, but we need to
// check that the basic type is an integer type.
isBitShift = true;
if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
{
return false;
}
break;
case EOpBitwiseAnd:
case EOpBitwiseXor:
case EOpBitwiseOr:
case EOpBitwiseAndAssign:
case EOpBitwiseXorAssign:
case EOpBitwiseOrAssign:
// It is enough to check the type of only one operand, since later it
// is checked that the operand types match.
if (!IsInteger(left->getBasicType()))
{
return false;
}
break;
default:
break;
}
// GLSL ES 1.00 and 3.00 do not support implicit type casting.
// So the basic type should usually match.
if (!isBitShift && left->getBasicType() != right->getBasicType())
{
return false;
}
// Check that type sizes match exactly on ops that require that:
switch(op)
{
case EOpAssign:
case EOpInitialize:
case EOpEqual:
case EOpNotEqual:
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
case EOpGreaterThanEqual:
if ((left->getNominalSize() != right->getNominalSize()) ||
(left->getSecondarySize() != right->getSecondarySize()))
{
return false;
}
default:
break;
}
return true; return true;
} }
TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc) const TSourceLoc &loc)
{ {
if (!binaryOpArrayCheck(op, left, right, loc)) if (!binaryOpCommonCheck(op, left, right, loc))
return nullptr; return nullptr;
switch (op) switch (op)
...@@ -2809,12 +2870,6 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *l ...@@ -2809,12 +2870,6 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *l
break; break;
} }
// This check is duplicated between here and node->promote() as an optimization.
if (left->getBasicType() != right->getBasicType() && op != EOpBitShiftLeft && op != EOpBitShiftRight)
{
return nullptr;
}
return intermediate.addBinaryMath(op, left, right, loc); return intermediate.addBinaryMath(op, left, right, loc);
} }
...@@ -2849,7 +2904,7 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyp ...@@ -2849,7 +2904,7 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyp
TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc) const TSourceLoc &loc)
{ {
if (binaryOpArrayCheck(op, left, right, loc)) if (binaryOpCommonCheck(op, left, right, loc))
{ {
return intermediate.addAssign(op, left, right, loc); return intermediate.addAssign(op, left, right, loc);
} }
......
...@@ -192,8 +192,8 @@ struct TParseContext { ...@@ -192,8 +192,8 @@ struct TParseContext {
TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc); const TSourceLoc &loc);
// Return true if array-related checks pass // Return true if the checks pass
bool binaryOpArrayCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, bool binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right,
const TSourceLoc &loc); const TSourceLoc &loc);
}; };
......
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