// // Establishes the type of the resultant operation, as well as // makes the operator the correct one for the operands. // // Returns false if operator can't work on operands. // bool TIntermBinary::promote(TInfoSink &infoSink) { // This function only handles scalars, vectors, and matrices. if (mLeft->isArray() || mRight->isArray()) { infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); return false; } // 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 // operand. Then only deviations from this need be coded. // setType(mLeft->getType()); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision( mLeft->getPrecision(), mRight->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // Binary operations results in temporary variables unless both // operands are const. if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) { getTypePointer()->setQualifier(EvqTemporary); } const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize()); // // All scalars or structs. Code after this test assumes this case is removed! // if (nominalSize == 1) { switch (mOp) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: setType(TType(EbtBool, EbpUndefined)); break; // // And and Or operate on conditionals // case EOpLogicalAnd: case EOpLogicalOr: // Both operands must be of type bool. if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) { return false; } setType(TType(EbtBool, EbpUndefined)); break; default: 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. // Can these two operands be combined? // TBasicType basicType = mLeft->getBasicType(); switch (mOp) { case EOpMul: if (!mLeft->isMatrix() && mRight->isMatrix()) { if (mLeft->isVector()) { mOp = EOpVectorTimesMatrix; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), 1)); } else { mOp = EOpMatrixTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mRight->getRows())); } } else if (mLeft->isMatrix() && !mRight->isMatrix()) { if (mRight->isVector()) { mOp = EOpMatrixTimesVector; setType(TType(basicType, higherPrecision, EvqTemporary, mLeft->getRows(), 1)); } else { mOp = EOpMatrixTimesScalar; } } else if (mLeft->isMatrix() && mRight->isMatrix()) { mOp = EOpMatrixTimesMatrix; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mLeft->getRows())); } else if (!mLeft->isMatrix() && !mRight->isMatrix()) { if (mLeft->isVector() && mRight->isVector()) { // leave as component product } else if (mLeft->isVector() || mRight->isVector()) { mOp = EOpVectorTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, 1)); } } else { infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); return false; } if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) { return false; } break; case EOpMulAssign: if (!mLeft->isMatrix() && mRight->isMatrix()) { if (mLeft->isVector()) { mOp = EOpVectorTimesMatrixAssign; } else { return false; } } else if (mLeft->isMatrix() && !mRight->isMatrix()) { if (mRight->isVector()) { return false; } else { mOp = EOpMatrixTimesScalarAssign; } } else if (mLeft->isMatrix() && mRight->isMatrix()) { mOp = EOpMatrixTimesMatrixAssign; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mLeft->getRows())); } else if (!mLeft->isMatrix() && !mRight->isMatrix()) { if (mLeft->isVector() && mRight->isVector()) { // leave as component product } else if (mLeft->isVector() || mRight->isVector()) { if (!mLeft->isVector()) return false; mOp = EOpVectorTimesScalarAssign; setType(TType(basicType, higherPrecision, EvqTemporary, mLeft->getNominalSize(), 1)); } } else { infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); return false; } if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) { return false; } break; case EOpAssign: case EOpInitialize: 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 ((mLeft->isMatrix() && mRight->isVector()) || (mLeft->isVector() && mRight->isMatrix())) { return false; } // Are the sizes compatible? 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; // Operator cannot be of type pure assignment. if (mOp == EOpAssign || mOp == EOpInitialize) return false; } { const int secondarySize = std::max( mLeft->getSecondarySize(), mRight->getSecondarySize()); setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize)); } break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if ((mLeft->getNominalSize() != mRight->getNominalSize()) || (mLeft->getSecondarySize() != mRight->getSecondarySize())) { return false; } setType(TType(EbtBool, EbpUndefined)); break; default: return false; } return true; }
// // Establishes the type of the resultant operation, as well as // makes the operator the correct one for the operands. // // Returns false if operator can't work on operands. // bool TIntermBinary::promote(TInfoSink &infoSink) { // This function only handles scalars, vectors, and matrices. if (mLeft->isArray() || mRight->isArray()) { infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); return false; } // GLSL ES 2.0 does not support implicit type casting. // So the basic type should always match. if (mLeft->getBasicType() != mRight->getBasicType()) { return false; } // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // setType(mLeft->getType()); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision( mLeft->getPrecision(), mRight->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // Binary operations results in temporary variables unless both // operands are const. if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) { getTypePointer()->setQualifier(EvqTemporary); } const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize()); // // All scalars or structs. Code after this test assumes this case is removed! // if (nominalSize == 1) { switch (mOp) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: setType(TType(EbtBool, EbpUndefined)); break; // // And and Or operate on conditionals // case EOpLogicalAnd: case EOpLogicalOr: // Both operands must be of type bool. if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) { return false; } setType(TType(EbtBool, EbpUndefined)); break; default: 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. // Can these two operands be combined? // TBasicType basicType = mLeft->getBasicType(); switch (mOp) { case EOpMul: if (!mLeft->isMatrix() && mRight->isMatrix()) { if (mLeft->isVector()) { mOp = EOpVectorTimesMatrix; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), 1)); } else { mOp = EOpMatrixTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mRight->getRows())); } } else if (mLeft->isMatrix() && !mRight->isMatrix()) { if (mRight->isVector()) { mOp = EOpMatrixTimesVector; setType(TType(basicType, higherPrecision, EvqTemporary, mLeft->getRows(), 1)); } else { mOp = EOpMatrixTimesScalar; } } else if (mLeft->isMatrix() && mRight->isMatrix()) { mOp = EOpMatrixTimesMatrix; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mLeft->getRows())); } else if (!mLeft->isMatrix() && !mRight->isMatrix()) { if (mLeft->isVector() && mRight->isVector()) { // leave as component product } else if (mLeft->isVector() || mRight->isVector()) { mOp = EOpVectorTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, 1)); } } else { infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); return false; } if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) { return false; } break; case EOpMulAssign: if (!mLeft->isMatrix() && mRight->isMatrix()) { if (mLeft->isVector()) { mOp = EOpVectorTimesMatrixAssign; } else { return false; } } else if (mLeft->isMatrix() && !mRight->isMatrix()) { if (mRight->isVector()) { return false; } else { mOp = EOpMatrixTimesScalarAssign; } } else if (mLeft->isMatrix() && mRight->isMatrix()) { mOp = EOpMatrixTimesMatrixAssign; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mLeft->getRows())); } else if (!mLeft->isMatrix() && !mRight->isMatrix()) { if (mLeft->isVector() && mRight->isVector()) { // leave as component product } else if (mLeft->isVector() || mRight->isVector()) { if (!mLeft->isVector()) return false; mOp = EOpVectorTimesScalarAssign; setType(TType(basicType, higherPrecision, EvqTemporary, mLeft->getNominalSize(), 1)); } } else { infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); return false; } if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) { return false; } break; case EOpAssign: case EOpInitialize: case EOpAdd: case EOpSub: case EOpDiv: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: if ((mLeft->isMatrix() && mRight->isVector()) || (mLeft->isVector() && mRight->isMatrix())) { return false; } // Are the sizes compatible? if (mLeft->getNominalSize() != mRight->getNominalSize() || mLeft->getSecondarySize() != mRight->getSecondarySize()) { // If the nominal size of operands do not match: // One of them must be scalar. if (!mLeft->isScalar() && !mRight->isScalar()) return false; // Operator cannot be of type pure assignment. if (mOp == EOpAssign || mOp == EOpInitialize) return false; } { const int secondarySize = std::max( mLeft->getSecondarySize(), mRight->getSecondarySize()); setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize)); } break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if ((mLeft->getNominalSize() != mRight->getNominalSize()) || (mLeft->getSecondarySize() != mRight->getSecondarySize())) { return false; } setType(TType(EbtBool, EbpUndefined)); break; default: return false; } return true; }
// // Establishes the type of the resultant operation, as well as // makes the operator the correct one for the 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) { ASSERT(mLeft->isArray() == mRight->isArray()); // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // setType(mLeft->getType()); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision( mLeft->getPrecision(), mRight->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // Binary operations results in temporary variables unless both // operands are const. if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) { getTypePointer()->setQualifier(EvqTemporary); } const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize()); // // All scalars or structs. Code after this test assumes this case is removed! // if (nominalSize == 1) { switch (mOp) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: setType(TType(EbtBool, EbpUndefined)); break; // // And and Or operate on conditionals // case EOpLogicalAnd: case EOpLogicalXor: case EOpLogicalOr: ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); setType(TType(EbtBool, EbpUndefined)); break; default: 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. // Can these two operands be combined? // TBasicType basicType = mLeft->getBasicType(); switch (mOp) { case EOpMul: if (!mLeft->isMatrix() && mRight->isMatrix()) { if (mLeft->isVector()) { mOp = EOpVectorTimesMatrix; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), 1)); } else { mOp = EOpMatrixTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mRight->getRows())); } } else if (mLeft->isMatrix() && !mRight->isMatrix()) { if (mRight->isVector()) { mOp = EOpMatrixTimesVector; setType(TType(basicType, higherPrecision, EvqTemporary, mLeft->getRows(), 1)); } else { mOp = EOpMatrixTimesScalar; } } else if (mLeft->isMatrix() && mRight->isMatrix()) { mOp = EOpMatrixTimesMatrix; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mLeft->getRows())); } else if (!mLeft->isMatrix() && !mRight->isMatrix()) { if (mLeft->isVector() && mRight->isVector()) { // leave as component product } else if (mLeft->isVector() || mRight->isVector()) { mOp = EOpVectorTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, 1)); } } else { infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); return false; } if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) { return false; } break; case EOpMulAssign: if (!mLeft->isMatrix() && mRight->isMatrix()) { if (mLeft->isVector()) { mOp = EOpVectorTimesMatrixAssign; } else { return false; } } else if (mLeft->isMatrix() && !mRight->isMatrix()) { if (mRight->isVector()) { return false; } else { mOp = EOpMatrixTimesScalarAssign; } } else if (mLeft->isMatrix() && mRight->isMatrix()) { mOp = EOpMatrixTimesMatrixAssign; setType(TType(basicType, higherPrecision, EvqTemporary, mRight->getCols(), mLeft->getRows())); } else if (!mLeft->isMatrix() && !mRight->isMatrix()) { if (mLeft->isVector() && mRight->isVector()) { // leave as component product } else if (mLeft->isVector() || mRight->isVector()) { if (!mLeft->isVector()) return false; mOp = EOpVectorTimesScalarAssign; setType(TType(basicType, higherPrecision, EvqTemporary, mLeft->getNominalSize(), 1)); } } else { infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); return false; } if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) { return false; } break; case EOpAssign: case EOpInitialize: // No more additional checks are needed. ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && (mLeft->getSecondarySize() == mRight->getSecondarySize())); 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 ((mLeft->isMatrix() && mRight->isVector()) || (mLeft->isVector() && mRight->isMatrix())) { return false; } // Are the sizes compatible? 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, EvqTemporary, nominalSize, secondarySize)); if (mLeft->isArray()) { ASSERT(mLeft->getArraySize() == mRight->getArraySize()); mType.setArraySize(mLeft->getArraySize()); } } break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && (mLeft->getSecondarySize() == mRight->getSecondarySize())); setType(TType(EbtBool, EbpUndefined)); break; default: return false; } return true; }