void TIntermAggregate::setPrecisionFromChildren() { if (getBasicType() == EbtBool) { mType.setPrecision(EbpUndefined); return; } TPrecision precision = EbpUndefined; TIntermSequence::iterator childIter = mSequence.begin(); while (childIter != mSequence.end()) { TIntermTyped *typed = (*childIter)->getAsTyped(); if (typed) precision = GetHigherPrecision(typed->getPrecision(), precision); ++childIter; } mType.setPrecision(precision); }
bool TIntermSelection::promoteTernary(TInfoSink& infoSink) { if (!condition->isVector()) return true; int size = condition->getRowsCount(); TIntermTyped* trueb = trueBlock->getAsTyped(); TIntermTyped* falseb = falseBlock->getAsTyped(); if (!trueb || !falseb) return false; if (trueb->getRowsCount() == size && falseb->getRowsCount() == size) return true; // Base assumption: just make the type a float vector TPrecision higherPrecision = GetHigherPrecision(trueb->getPrecision(), falseb->getPrecision()); setType(TType(EbtFloat, higherPrecision, EvqTemporary, 1, size, condition->isMatrix())); TOperator convert = EOpNull; { convert = TOperator( EOpConstructVec2 + size - 2); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(trueb->getLine()); node->setType(TType(condition->getBasicType(), higherPrecision, trueb->getQualifier() == EvqConst ? EvqConst : EvqTemporary, 1, size, condition->isMatrix())); node->getNodes().push_back(trueb); trueBlock = node; } { convert = TOperator( EOpConstructVec2 + size - 2); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(falseb->getLine()); node->setType(TType(condition->getBasicType(), higherPrecision, falseb->getQualifier() == EvqConst ? EvqConst : EvqTemporary, 1, size, condition->isMatrix())); node->getNodes().push_back(falseb); falseBlock = node; } 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(TParseContext& ctx) { TBasicType type = left->getBasicType(); // // Arrays have to be exact matches. // if ((left->isArray() || right->isArray()) && (left->getType() != right->getType())) return false; // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // setType(TType(type, left->getPrecision(), EvqTemporary, left->getColsCount(), left->getRowsCount(), left->isMatrix())); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // // Array operations. // if (left->isArray()) { switch (op) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: setType(TType(EbtBool, EbpUndefined)); break; // // Set array information. // case EOpAssign: getType().setArraySize(left->getType().getArraySize()); getType().setArrayInformationType(left->getType().getArrayInformationType()); break; default: return false; } return true; } // // All scalars. Code after this test assumes this case is removed! // if (left->isScalar() && right->isScalar()) { switch (op) { // // 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: if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) return false; setType(TType(EbtBool, EbpUndefined)); break; // // Check for integer only operands. // case EOpRightShift: case EOpLeftShift: case EOpAnd: case EOpInclusiveOr: case EOpExclusiveOr: if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) return false; break; case EOpModAssign: case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) return false; // fall through // // Everything else should have matching types // default: if (left->getBasicType() != right->getBasicType() || left->isMatrix() != right->isMatrix()) return false; } return true; } // this is not an allowed promotion : float3x4 * float4x3 if (left->getRowsCount() != right->getRowsCount() && left->getColsCount() != right->getColsCount() && (left->getRowsCount() > right->getRowsCount()) != (left->getColsCount() > right->getColsCount())) return false; //determine if this is an assignment bool assignment = ( op >= EOpAssign && op <= EOpRightShiftAssign) ? true : false; // find size of the resulting value int cols = 0; int rows = 0; if (!left->isScalar() && !right->isScalar()) // no scalars, so downcast of the larger type { cols = std::min(left->getColsCount(), right->getColsCount()); rows = std::min(left->getRowsCount(), right->getRowsCount()); } else { cols = std::max(left->getColsCount(), right->getColsCount()); rows = std::max(left->getRowsCount(), right->getRowsCount()); } assert(cols > 0); assert(rows > 0); // // Downcast needed ? // if ( left->getColsCount() > cols || left->getRowsCount() > rows) { if (assignment) return false; //can't promote the destination //down convert left to match right TOperator convert = EOpNull; if (left->getTypePointer()->isMatrix()) { convert = getMatrixConstructOp(*right, ctx); if (convert == EOpNull) return false; } else if (left->getTypePointer()->isVector()) { switch (right->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + rows - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + rows - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + rows - 2); break; default: break; } } else { assert(0); //size 1 case should have been handled } TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(left->getLine()); node->setType(TType(left->getBasicType(), left->getPrecision(), EvqTemporary, right->getColsCount(), right->getRowsCount(), left->isMatrix())); node->getNodes().push_back(left); left = node; //now reset this node's type setType(TType(left->getBasicType(), left->getPrecision(), EvqTemporary, right->getColsCount(), right->getRowsCount(), left->isMatrix())); } else if ( right->getColsCount() > cols || right->getRowsCount() > rows) { //down convert right to match left TOperator convert = EOpNull; if (right->getTypePointer()->isMatrix()) { convert = getMatrixConstructOp(*left, ctx); if (convert == EOpNull) return false; } else if (right->getTypePointer()->isVector()) { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + rows - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + rows - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + rows - 2); break; default: break; } } else { assert(0); //size 1 case should have been handled } TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(right->getLine()); node->setType(TType(right->getBasicType(), right->getPrecision(), EvqTemporary, left->getColsCount(), left->getRowsCount(), right->isMatrix())); node->getNodes().push_back(right); right = node; } // // Can these two operands be combined? // switch (op) { case EOpMul: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrix; else { op = EOpMatrixTimesScalar; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, true)); } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { op = EOpMatrixTimesVector; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, false)); } else { op = EOpMatrixTimesScalar; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrix; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { op = EOpVectorTimesScalar; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, false)); } } else { ctx.infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpMulAssign: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrixAssign; else { return false; } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { return false; } else { op = EOpMatrixTimesScalarAssign; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrixAssign; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { if (! left->isVector()) return false; op = EOpVectorTimesScalarAssign; setType(TType(type, higherPrecision, EvqTemporary, cols, rows, false)); } } else { ctx.infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpAssign: if ( left->getColsCount() != right->getColsCount() || left->getRowsCount() != right->getRowsCount()) { //right needs to be forced to match left TOperator convert = EOpNull; if (left->isMatrix() ) { convert = getMatrixConstructOp(*left, ctx); if (convert == EOpNull) return false; } else if (left->isVector() ) { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + left->getRowsCount() - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + left->getRowsCount() - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + left->getRowsCount() - 2); break; default: break; } } else { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = EOpConstructBool; break; case EbtInt: convert = EOpConstructInt; break; case EbtFloat: convert = EOpConstructFloat; break; default: break; } } assert( convert != EOpNull); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(right->getLine()); node->setType(TType(left->getBasicType(), left->getPrecision(), right->getQualifier() == EvqConst ? EvqConst : EvqTemporary, left->getColsCount(), left->getRowsCount(), left->isMatrix())); node->getNodes().push_back(right); right = node; cols = right->getColsCount(); rows = right->getRowsCount(); } // fall through case EOpMod: case EOpAdd: case EOpSub: case EOpDiv: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: case EOpModAssign: if (op == EOpMod) type = EbtFloat; if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()) || left->getBasicType() != right->getBasicType()) return false; setType(TType(type, left->getPrecision(), EvqTemporary, cols, rows, left->isMatrix() || right->isMatrix())); break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()) || left->getBasicType() != right->getBasicType()) return false; setType(TType(EbtBool, higherPrecision, EvqTemporary, cols, rows, false)); break; default: return false; } // // One more check for assignment. The Resulting type has to match the left operand. // switch (op) { case EOpAssign: case EOpAddAssign: case EOpSubAssign: case EOpMulAssign: case EOpDivAssign: case EOpModAssign: case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: if (getType() != left->getType()) return false; break; default: break; } 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 (left->isArray() || right->isArray()) { infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine()); return false; } // GLSL ES 2.0 does not support implicit type casting. // So the basic type should always match. if (left->getBasicType() != right->getBasicType()) return false; // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // setType(left->getType()); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // Binary operations results in temporary variables unless both // operands are const. if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { getTypePointer()->setQualifier(EvqTemporary); } int size = std::max(left->getNominalSize(), right->getNominalSize()); // // All scalars. Code after this test assumes this case is removed! // if (size == 1) { switch (op) { // // 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 (left->getBasicType() != EbtBool || right->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. // Are the sizes compatible? // 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()) { if (left->isVector()) op = EOpVectorTimesMatrix; else { op = EOpMatrixTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { op = EOpMatrixTimesVector; setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); } else { op = EOpMatrixTimesScalar; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrix; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { op = EOpVectorTimesScalar; setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); } } else { infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpMulAssign: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrixAssign; else { return false; } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { return false; } else { op = EOpMatrixTimesScalarAssign; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrixAssign; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { if (! left->isVector()) return false; op = EOpVectorTimesScalarAssign; setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); } } else { infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpAssign: case EOpInitialize: case EOpAdd: case EOpSub: case EOpDiv: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) return false; setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) 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) { int size = left->getNominalSize(); if (right->getNominalSize() < size) size = right->getNominalSize(); if (size == 1) { 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())) return false; // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. // setType(TType(type, left->getPrecision(), EvqTemporary, left->getNominalSize(), left->isMatrix())); // The result gets promoted to the highest precision. TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); getTypePointer()->setPrecision(higherPrecision); // // Array operations. // if (left->isArray()) { switch (op) { // // Promote to conditional // case EOpEqual: case EOpNotEqual: setType(TType(EbtBool, EbpUndefined)); break; // // Set array information. // case EOpAssign: getType().setArraySize(left->getType().getArraySize()); getType().setArrayInformationType(left->getType().getArrayInformationType()); break; default: return false; } return true; } // // All scalars. Code after this test assumes this case is removed! // if (size == 1) { switch (op) { // // 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: if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) return false; setType(TType(EbtBool, EbpUndefined)); break; // // Check for integer only operands. // case EOpRightShift: case EOpLeftShift: case EOpAnd: case EOpInclusiveOr: case EOpExclusiveOr: if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) return false; break; case EOpModAssign: case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) return false; // fall through // // Everything else should have matching types // default: if (left->getBasicType() != right->getBasicType() || left->isMatrix() != right->isMatrix()) return false; } return true; } //determine if this is an assignment bool assignment = ( op >= EOpAssign && op <= EOpRightShiftAssign) ? true : false; // // Are the sizes compatible? // if ( (left->getNominalSize() != size && left->getNominalSize() != 1) || (right->getNominalSize() != size && right->getNominalSize() != 1)) { //Insert a constructor on the larger type to make the sizes match if ( left->getNominalSize() > right->getNominalSize() ) { if (assignment) return false; //can't promote the destination //down convert left to match right TOperator convert = EOpNull; if (left->getTypePointer()->isMatrix()) { switch (right->getNominalSize()) { case 2: convert = EOpConstructMat2FromMat; break; case 3: convert = EOpConstructMat3FromMat; break; case 4: convert = EOpConstructMat4; break; //should never need to down convert to mat4 } } else if (left->getTypePointer()->isVector()) { switch (left->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + right->getNominalSize() - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + right->getNominalSize() - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + right->getNominalSize() - 2); break; } } else { assert(0); //size 1 case should have been handled } TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(left->getLine()); node->setType(TType(left->getBasicType(), left->getPrecision(), EvqTemporary, right->getNominalSize(), left->isMatrix())); node->getNodes().push_back(left); left = node; //now reset this node's type setType(TType(left->getBasicType(), left->getPrecision(), EvqTemporary, right->getNominalSize(), left->isMatrix())); } else { //down convert right to match left TOperator convert = EOpNull; if (right->getTypePointer()->isMatrix()) { switch (left->getNominalSize()) { case 2: convert = EOpConstructMat2FromMat; break; case 3: convert = EOpConstructMat3FromMat; break; case 4: convert = EOpConstructMat4; break; //should never need to down convert to mat4 } } else if (right->getTypePointer()->isVector()) { switch (right->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + left->getNominalSize() - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + left->getNominalSize() - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + left->getNominalSize() - 2); break; } } else { assert(0); //size 1 case should have been handled } TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(right->getLine()); node->setType(TType(right->getBasicType(), right->getPrecision(), EvqTemporary, left->getNominalSize(), right->isMatrix())); node->getNodes().push_back(right); right = node; } } // // Can these two operands be combined? // switch (op) { case EOpMul: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrix; else { op = EOpMatrixTimesScalar; setType(TType(type, higherPrecision, EvqTemporary, size, true)); } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { op = EOpMatrixTimesVector; setType(TType(type, higherPrecision, EvqTemporary, size, false)); } else { op = EOpMatrixTimesScalar; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrix; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { op = EOpVectorTimesScalar; setType(TType(type, higherPrecision, EvqTemporary, size, false)); } } else { infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpMulAssign: if (!left->isMatrix() && right->isMatrix()) { if (left->isVector()) op = EOpVectorTimesMatrixAssign; else { return false; } } else if (left->isMatrix() && !right->isMatrix()) { if (right->isVector()) { return false; } else { op = EOpMatrixTimesScalarAssign; } } else if (left->isMatrix() && right->isMatrix()) { op = EOpMatrixTimesMatrixAssign; } else if (!left->isMatrix() && !right->isMatrix()) { if (left->isVector() && right->isVector()) { // leave as component product } else if (left->isVector() || right->isVector()) { if (! left->isVector()) return false; op = EOpVectorTimesScalarAssign; setType(TType(type, higherPrecision, EvqTemporary, size, false)); } } else { infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); return false; } break; case EOpAssign: if (left->getNominalSize() != right->getNominalSize()) { //right needs to be forced to match left TOperator convert = EOpNull; if (left->isMatrix() ) { //TODO: These might need to be changed to smears switch (left->getNominalSize()) { case 2: convert = EOpConstructMat2; break; case 3: convert = EOpConstructMat3; break; case 4: convert = EOpConstructMat4; break; } } else if (left->isVector() ) { switch (right->getTypePointer()->getBasicType()) { case EbtBool: convert = TOperator( EOpConstructBVec2 + left->getNominalSize() - 2); break; case EbtInt: convert = TOperator( EOpConstructIVec2 + left->getNominalSize() - 2); break; case EbtFloat: convert = TOperator( EOpConstructVec2 + left->getNominalSize() - 2); break; } } else { switch (right->getTypePointer()->getBasicType()) { case EbtBool: convert = EOpConstructBool; break; case EbtInt: convert = EOpConstructInt; break; case EbtFloat: convert = EOpConstructFloat; break; } } assert( convert != EOpNull); TIntermAggregate *node = new TIntermAggregate(convert); node->setLine(right->getLine()); node->setType(TType(left->getBasicType(), left->getPrecision(), right->getQualifier() == EvqConst ? EvqConst : EvqTemporary, left->getNominalSize(), left->isMatrix())); node->getNodes().push_back(right); right = node; size = right->getNominalSize(); } // fall through case EOpMod: case EOpAdd: case EOpSub: case EOpDiv: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: case EOpModAssign: if (op == EOpMod) type = EbtFloat; if (left->isMatrix() && right->isVector() || left->isVector() && right->isMatrix() || left->getBasicType() != right->getBasicType()) return false; setType(TType(type, left->getPrecision(), EvqTemporary, size, left->isMatrix() || right->isMatrix())); break; case EOpEqual: case EOpNotEqual: case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if (left->isMatrix() && right->isVector() || left->isVector() && right->isMatrix() || left->getBasicType() != right->getBasicType()) return false; setType(TType(EbtBool, higherPrecision, EvqTemporary, size, false)); break; default: return false; } // // One more check for assignment. The Resulting type has to match the left operand. // switch (op) { case EOpAssign: case EOpAddAssign: case EOpSubAssign: case EOpMulAssign: case EOpDivAssign: case EOpModAssign: case EOpAndAssign: case EOpInclusiveOrAssign: case EOpExclusiveOrAssign: case EOpLeftShiftAssign: case EOpRightShiftAssign: if (getType() != left->getType()) return false; break; default: break; } 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 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. // // 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; }