static TOperator getDownConvertOp(const TIntermTyped& intermediate) { return getMatrixConstructOp(intermediate); /* implement EOpConstructMat?x?FromMat if support for glsl <1.20 is needed, switch (intermediate.getColsCount()) { case 2: switch (intermediate.getRowsCount()) { case 2: return EOpConstructMat2x2FromMat; case 3: return EOpConstructMat2x3FromMat; case 4: return EOpConstructMat2x4FromMat; } break; case 3: switch (intermediate.getRowsCount()) { case 2: return EOpConstructMat3x2FromMat; case 3: return EOpConstructMat3x3FromMat; case 4: return EOpConstructMat3x4FromMat; } break; case 4: switch (intermediate.getRowsCount()) { case 2: return EOpConstructMat4x2FromMat; case 3: return EOpConstructMat4x3FromMat; case 4: return EOpConstructMat4x4; //should never need to down convert to mat4 } break; } assert(false); return EOpNull; */ }
// // 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; }