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; }
// Turn an existing node into an aggregate. TIntermAggregate* ir_make_aggregate(TIntermNode* node, TSourceLoc line) { if (node == 0) return 0; TIntermAggregate* aggNode = new TIntermAggregate; if (node->getAsTyped()) aggNode->setType(*node->getAsTyped()->getTypePointer()); aggNode->getNodes().push_back(node); if (line.line != 0) aggNode->setLine(line); else aggNode->setLine(node->getLine()); return aggNode; }
// // 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) { 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; }