Commit 63e1ec5c by Olli Etuaho Committed by Commit Bot

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/372624Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 666f65a1
...@@ -391,36 +391,9 @@ TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped( ...@@ -391,36 +391,9 @@ TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(
mFalseBlock = falseCopy; mFalseBlock = falseCopy;
} }
//
// Say whether or not an operation node changes the value of a variable.
//
bool TIntermOperator::isAssignment() const bool TIntermOperator::isAssignment() const
{ {
switch (mOp) return IsAssignment(mOp);
{
case EOpPostIncrement:
case EOpPostDecrement:
case EOpPreIncrement:
case EOpPreDecrement:
case EOpAssign:
case EOpAddAssign:
case EOpSubAssign:
case EOpMulAssign:
case EOpVectorTimesMatrixAssign:
case EOpVectorTimesScalarAssign:
case EOpMatrixTimesScalarAssign:
case EOpMatrixTimesMatrixAssign:
case EOpDivAssign:
case EOpIModAssign:
case EOpBitShiftLeftAssign:
case EOpBitShiftRightAssign:
case EOpBitwiseAndAssign:
case EOpBitwiseXorAssign:
case EOpBitwiseOrAssign:
return true;
default:
return false;
}
} }
bool TIntermOperator::isMultiplication() const bool TIntermOperator::isMultiplication() const
...@@ -612,6 +585,12 @@ void TIntermUnary::promote(const TType *funcReturnType) ...@@ -612,6 +585,12 @@ void TIntermUnary::promote(const TType *funcReturnType)
mType.setQualifier(EvqTemporary); mType.setQualifier(EvqTemporary);
} }
TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
: TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
{
promote();
}
// //
// 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.
...@@ -619,17 +598,15 @@ void TIntermUnary::promote(const TType *funcReturnType) ...@@ -619,17 +598,15 @@ void TIntermUnary::promote(const TType *funcReturnType)
// For lots of operations it should already be established that the operand // 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. // combination is valid, but returns false if operator can't work on operands.
// //
bool TIntermBinary::promote() void TIntermBinary::promote()
{ {
ASSERT(mLeft->isArray() == mRight->isArray()); ASSERT(mLeft->isArray() == mRight->isArray());
ASSERT(!isMultiplication() || ASSERT(!isMultiplication() ||
mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType())); mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
//
// 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.
//
setType(mLeft->getType()); setType(mLeft->getType());
// The result gets promoted to the highest precision. // The result gets promoted to the highest precision.
...@@ -681,13 +658,11 @@ bool TIntermBinary::promote() ...@@ -681,13 +658,11 @@ bool TIntermBinary::promote()
default: default:
break; break;
} }
return true; return;
} }
// If we reach here, at least one of the operands is vector or matrix. // If we reach here, at least one of the operands is vector or matrix.
// The other operand could be a scalar, vector, or matrix. // The other operand could be a scalar, vector, or matrix.
// Can these two operands be combined?
//
TBasicType basicType = mLeft->getBasicType(); TBasicType basicType = mLeft->getBasicType();
switch (mOp) switch (mOp)
...@@ -728,7 +703,6 @@ bool TIntermBinary::promote() ...@@ -728,7 +703,6 @@ bool TIntermBinary::promote()
break; break;
case EOpAssign: case EOpAssign:
case EOpInitialize: case EOpInitialize:
// No more additional checks are needed.
ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
(mLeft->getSecondarySize() == mRight->getSecondarySize())); (mLeft->getSecondarySize() == mRight->getSecondarySize()));
break; break;
...@@ -750,44 +724,15 @@ bool TIntermBinary::promote() ...@@ -750,44 +724,15 @@ bool TIntermBinary::promote()
case EOpBitwiseAndAssign: case EOpBitwiseAndAssign:
case EOpBitwiseXorAssign: case EOpBitwiseXorAssign:
case EOpBitwiseOrAssign: case EOpBitwiseOrAssign:
if ((mLeft->isMatrix() && mRight->isVector()) || {
(mLeft->isVector() && mRight->isMatrix())) const int secondarySize =
{ std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
return false; setType(TType(basicType, higherPrecision, resultQualifier,
} static_cast<unsigned char>(nominalSize),
static_cast<unsigned char>(secondarySize)));
// Are the sizes compatible? ASSERT(!mLeft->isArray() && !mRight->isArray());
if (mLeft->getNominalSize() != mRight->getNominalSize() ||
mLeft->getSecondarySize() != mRight->getSecondarySize())
{
// If the nominal sizes of operands do not match:
// One of them must be a scalar.
if (!mLeft->isScalar() && !mRight->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 (!mRight->isScalar() &&
(isAssignment() || mOp == EOpBitShiftLeft || mOp == EOpBitShiftRight))
return false;
}
{
const int secondarySize =
std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
setType(TType(basicType, higherPrecision, resultQualifier,
static_cast<unsigned char>(nominalSize),
static_cast<unsigned char>(secondarySize)));
if (mLeft->isArray())
{
ASSERT(mLeft->getArraySize() == mRight->getArraySize());
mType.setArraySize(mLeft->getArraySize());
}
}
break; break;
}
case EOpEqual: case EOpEqual:
case EOpNotEqual: case EOpNotEqual:
case EOpLessThan: case EOpLessThan:
...@@ -796,13 +741,21 @@ bool TIntermBinary::promote() ...@@ -796,13 +741,21 @@ bool TIntermBinary::promote()
case EOpGreaterThanEqual: case EOpGreaterThanEqual:
ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
(mLeft->getSecondarySize() == mRight->getSecondarySize())); (mLeft->getSecondarySize() == mRight->getSecondarySize()));
setType(TType(EbtBool, EbpUndefined)); setType(TType(EbtBool, EbpUndefined, resultQualifier));
break; break;
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectInterfaceBlock:
case EOpIndexDirectStruct:
// TODO (oetuaho): These ops could be handled here as well (should be done closer to the
// top of the function).
UNREACHABLE();
break;
default: default:
return false; UNREACHABLE();
break;
} }
return true;
} }
TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics) TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
......
...@@ -410,10 +410,9 @@ class TIntermBinary : public TIntermOperator ...@@ -410,10 +410,9 @@ class TIntermBinary : public TIntermOperator
: TIntermOperator(op), : TIntermOperator(op),
mAddIndexClamp(false) {} mAddIndexClamp(false) {}
TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right) // This constructor determines the type of the binary node based on the operands and op.
: TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false) // This is only supported for math/logical ops, not indexing.
{ TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right);
}
TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); } TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
...@@ -433,7 +432,6 @@ class TIntermBinary : public TIntermOperator ...@@ -433,7 +432,6 @@ class TIntermBinary : public TIntermOperator
void setRight(TIntermTyped *node) { mRight = node; } void setRight(TIntermTyped *node) { mRight = node; }
TIntermTyped *getLeft() const { return mLeft; } TIntermTyped *getLeft() const { return mLeft; }
TIntermTyped *getRight() const { return mRight; } TIntermTyped *getRight() const { return mRight; }
bool promote();
TIntermTyped *fold(TDiagnostics *diagnostics); TIntermTyped *fold(TDiagnostics *diagnostics);
void setAddIndexClamp() { mAddIndexClamp = true; } void setAddIndexClamp() { mAddIndexClamp = true; }
...@@ -447,6 +445,8 @@ class TIntermBinary : public TIntermOperator ...@@ -447,6 +445,8 @@ class TIntermBinary : public TIntermOperator
bool mAddIndexClamp; bool mAddIndexClamp;
private: private:
void promote();
TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private! TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private!
}; };
......
...@@ -199,3 +199,31 @@ const char *GetOperatorString(TOperator op) ...@@ -199,3 +199,31 @@ const char *GetOperatorString(TOperator op)
return ""; return "";
} }
bool IsAssignment(TOperator op)
{
switch (op)
{
case EOpPostIncrement:
case EOpPostDecrement:
case EOpPreIncrement:
case EOpPreDecrement:
case EOpAssign:
case EOpAddAssign:
case EOpSubAssign:
case EOpMulAssign:
case EOpVectorTimesMatrixAssign:
case EOpVectorTimesScalarAssign:
case EOpMatrixTimesScalarAssign:
case EOpMatrixTimesMatrixAssign:
case EOpDivAssign:
case EOpIModAssign:
case EOpBitShiftLeftAssign:
case EOpBitShiftRightAssign:
case EOpBitwiseAndAssign:
case EOpBitwiseXorAssign:
case EOpBitwiseOrAssign:
return true;
default:
return false;
}
}
\ No newline at end of file
...@@ -228,4 +228,7 @@ enum TOperator ...@@ -228,4 +228,7 @@ enum TOperator
// Returns the string corresponding to the operator in GLSL // Returns the string corresponding to the operator in GLSL
const char* GetOperatorString(TOperator op); const char* GetOperatorString(TOperator op);
// Say whether or not a binary or unary operation changes the value of a variable.
bool IsAssignment(TOperator op);
#endif // COMPILER_TRANSLATOR_OPERATOR_H_ #endif // COMPILER_TRANSLATOR_OPERATOR_H_
...@@ -3533,8 +3533,10 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, ...@@ -3533,8 +3533,10 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
return false; return false;
} }
// Check that type sizes match exactly on ops that require that. // Check that:
// Also check restrictions for structs that contain arrays or samplers. // 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) switch (op)
{ {
case EOpAssign: case EOpAssign:
...@@ -3567,6 +3569,48 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, ...@@ -3567,6 +3569,48 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
{ {
return false; 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: default:
break; break;
} }
...@@ -3671,8 +3715,6 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, ...@@ -3671,8 +3715,6 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
return nullptr; return nullptr;
} }
break; break;
// Note that for bitwise ops, type checking is done in promote() to
// share code between ops and compound assignment
default: default:
break; break;
} }
...@@ -3689,9 +3731,6 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, ...@@ -3689,9 +3731,6 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
TIntermBinary *node = new TIntermBinary(op, left, right); TIntermBinary *node = new TIntermBinary(op, left, right);
node->setLine(loc); node->setLine(loc);
if (!node->promote())
return nullptr;
// See if we can fold constants. // See if we can fold constants.
TIntermTyped *foldedNode = node->fold(&mDiagnostics); TIntermTyped *foldedNode = node->fold(&mDiagnostics);
if (foldedNode) if (foldedNode)
...@@ -3751,9 +3790,6 @@ TIntermTyped *TParseContext::createAssign(TOperator op, ...@@ -3751,9 +3790,6 @@ TIntermTyped *TParseContext::createAssign(TOperator op,
TIntermBinary *node = new TIntermBinary(op, left, right); TIntermBinary *node = new TIntermBinary(op, left, right);
node->setLine(loc); node->setLine(loc);
if (!node->promote())
return nullptr;
return node; return node;
} }
return nullptr; return nullptr;
......
...@@ -63,9 +63,6 @@ bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -63,9 +63,6 @@ bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType()); TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType());
TIntermBinary *mul = new TIntermBinary(op, y, log); TIntermBinary *mul = new TIntermBinary(op, y, log);
mul->setLine(node->getLine()); mul->setLine(node->getLine());
bool valid = mul->promote();
UNUSED_ASSERTION_VARIABLE(valid);
ASSERT(valid);
TIntermUnary *exp = new TIntermUnary(EOpExp2); TIntermUnary *exp = new TIntermUnary(EOpExp2);
exp->setOperand(mul); exp->setOperand(mul);
......
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