TIntermTyped* ir_add_vector_swizzle(TVectorFields& fields, TIntermTyped* arg, TSourceLoc lineDot, TSourceLoc lineIndex) { // swizzle on a constant -> fold it if (arg->getType().getQualifier() == EvqConst) { TIntermTyped* res = ir_add_const_vector_swizzle(fields, arg, lineIndex); if (res) return res; } TIntermTyped* res = NULL; if (fields.num == 1) { TIntermConstant* index = ir_add_constant(TType(EbtInt, EbpUndefined, EvqConst), lineIndex); index->setValue(fields.offsets[0]); res = ir_add_index(EOpIndexDirect, arg, index, lineDot); res->setType(TType(arg->getBasicType(), arg->getPrecision())); } else { TIntermTyped* index = ir_add_swizzle(fields, lineIndex); res = ir_add_index(EOpVectorSwizzle, arg, index, lineDot); res->setType(TType(arg->getBasicType(), arg->getPrecision(), EvqTemporary, 1, fields.num)); } return res; }
// // See if this qualifier can be an array. // // Returns true if there is an error. // bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type) { if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) { error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), ""); return true; } return false; }
void TCompiler::initializeGLPosition(TIntermNode* root) { InitializeVariables::InitVariableInfoList variables; InitializeVariables::InitVariableInfo var( "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4)); variables.push_back(var); InitializeVariables initializer(variables); root->traverse(&initializer); }
// // See if this type can be an array. // // Returns true if there is an error. // bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type) { // // Can the type be an array? // if (type.array) { error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str(), ""); return true; } return false; }
// // See if this qualifier can be an array. // // Returns true if there is an error. // bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type) { if (type.qualifier == EvqAttribute) { error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), ""); return true; } if (type.qualifier == EvqConst && extensionErrorCheck(line, "GL_3DL_array_objects")) return true; return false; }
// The function_call identifier was already recognized, and passed in as idToken. // // function_call // : [idToken] arguments // bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node) { // arguments TFunction* function = new TFunction(idToken.string, TType(EbtVoid)); TIntermTyped* arguments = nullptr; if (! acceptArguments(function, arguments)) return false; node = parseContext.handleFunctionCall(idToken.loc, function, arguments); return true; }
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; }
// For "if" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are in the // nodePair. TIntermNode* ir_add_selection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line, TInfoSink& infoSink) { // Convert float/int to bool if ( cond->getBasicType() != EbtBool) { cond = ir_add_conversion (EOpConstructBool, TType (EbtBool, cond->getPrecision(), cond->getQualifier(), cond->getColsCount(), cond->getRowsCount(), cond->isMatrix(), cond->isArray()), cond, infoSink); } TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); node->setLine(line); return node; }
TIntermTyped* ir_add_swizzle(TVectorFields& fields, TSourceLoc line) { TIntermAggregate* node = new TIntermAggregate(EOpSequence); node->setLine(line); TNodeArray& nodes = node->getNodes(); for (int i = 0; i < fields.num; i++) { TIntermConstant* constant = ir_add_constant(TType(EbtInt, EbpUndefined, EvqConst), line); constant->setValue(fields.offsets[i]); nodes.push_back(constant); } return node; }
// // Make a constant vector node or constant scalar node, representing a given // constant vector and constant swizzle into it. // TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc& loc) { const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray(); TConstUnionArray constArray(fields.num); for (int i = 0; i < fields.num; i++) constArray[i] = unionArray[fields.offsets[i]]; TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc); if (result == 0) result = node; else result->setType(TType(node->getBasicType(), EvqConst, fields.num)); return result; }
// // Do semantic checking for a variable declaration that has no initializer, // and update the symbol table. // // Returns true if there was an error. // bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type) { if (reservedErrorCheck(line, identifier)) recover(); TVariable* variable = new TVariable(&identifier, TType(type)); if (! symbolTable.insert(*variable)) { error(line, "redefinition", variable->getName().c_str(), ""); delete variable; return true; } if (voidErrorCheck(line, identifier, type)) return true; return false; }
// This function returns the tree representation for the vector field(s) being accessed from contant vector. // If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is // returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol // node or it could be the intermediate tree representation of accessing fields in a constant structure or column of // a constant matrix. TIntermTyped* ir_add_const_vector_swizzle(const TVectorFields& fields, TIntermTyped* node, TSourceLoc line) { TIntermConstant* constNode = node->getAsConstant(); if (!constNode) return NULL; TIntermConstant* res = ir_add_constant(node->getType(), line); for (int i = 0; i < fields.num; ++i) { int index = fields.offsets[i]; assert(index >= 0 && index < constNode->getCount()); res->setValue(i, constNode->getValue (index)); } res->setType(TType(node->getBasicType(), node->getPrecision(), EvqConst, fields.num)); return res; }
TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line) { TIntermAggregate* node = new TIntermAggregate(EOpSequence); node->setLine(line); TIntermConstantUnion* constIntNode; TIntermSequence &sequenceVector = node->getSequence(); ConstantUnion* unionArray; for (int i = 0; i < fields.num; i++) { unionArray = new ConstantUnion[1]; unionArray->setIConst(fields.offsets[i]); constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); sequenceVector.push_back(constIntNode); } return node; }
// For "if" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are in the // nodePair. TIntermNode* ir_add_selection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line, TInfoSink& infoSink) { // Convert float/int to bool switch ( cond->getBasicType() ) { case EbtFloat: case EbtInt: cond = ir_add_conversion (EOpConstructBool, TType (EbtBool, cond->getPrecision(), cond->getQualifier(), cond->getNominalSize(), cond->isMatrix(), cond->isArray()), cond, infoSink); break; default: // Do nothing break; } TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); node->setLine(line); return node; }
// For "?:" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are specified // as separate parameters. TIntermTyped* ir_add_selection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line, TInfoSink& infoSink) { bool bPromoteFromTrueBlockType = true; if (cond->getBasicType() != EbtBool) { cond = ir_add_conversion (EOpConstructBool, TType (EbtBool, cond->getPrecision(), cond->getQualifier(), cond->getColsCount(), cond->getRowsCount(), cond->isMatrix(), cond->isArray()), cond, infoSink); } // Choose which one to try to promote to based on which has more precision // By default, it will promote from the falseBlock type to the trueBlock type. However, // what we want to do is promote to the type with the most precision of the two. So here, // check whether the false block has more precision than the true block, and if so use // its type instead. if ( trueBlock->getBasicType() == EbtBool ) { if ( falseBlock->getBasicType() == EbtInt || falseBlock->getBasicType() == EbtFloat ) { bPromoteFromTrueBlockType = false; } } else if ( trueBlock->getBasicType() == EbtInt ) { if ( falseBlock->getBasicType() == EbtFloat ) { bPromoteFromTrueBlockType = false; } } // // Get compatible types. // if ( bPromoteFromTrueBlockType ) { TIntermTyped* child = ir_add_conversion(EOpSequence, trueBlock->getType(), falseBlock, infoSink); if (child) falseBlock = child; else { child = ir_add_conversion(EOpSequence, falseBlock->getType(), trueBlock, infoSink); if (child) trueBlock = child; else return 0; } } else { TIntermTyped* child = ir_add_conversion(EOpSequence, falseBlock->getType(), trueBlock, infoSink); if (child) trueBlock = child; else { child = ir_add_conversion(EOpSequence, trueBlock->getType(), falseBlock, infoSink); if (child) falseBlock = child; else return 0; } } // // Make a selection node. // TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); node->setLine(line); if (!node->promoteTernary(infoSink)) return 0; return node; }
TType atomic_inc( TType * p ) { return TType(); }
// Connect two nodes with a new parent that does a binary operation on the nodes. TIntermTyped* ir_add_binary_math(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TParseContext& ctx) { if (!left || !right) return 0; switch (op) { case EOpLessThan: case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: if (left->getType().isMatrix() || left->getType().isArray() || left->getType().getBasicType() == EbtStruct) { return 0; } break; case EOpLogicalOr: case EOpLogicalXor: case EOpLogicalAnd: if (left->getType().isMatrix() || left->getType().isArray()) return 0; if ( left->getBasicType() != EbtBool ) { if ( left->getType().getBasicType() != EbtInt && left->getType().getBasicType() != EbtFloat ) return 0; else { // If the left is a float or int, convert to a bool. This is the conversion that HLSL // does left = ir_add_conversion(EOpConstructBool, TType ( EbtBool, left->getPrecision(), left->getQualifier(), left->getColsCount(), left->getRowsCount(), left->isMatrix(), left->isArray()), left, ctx.infoSink); if ( left == 0 ) return 0; } } if (right->getType().isMatrix() || right->getType().isArray() || right->getType().isVector()) return 0; if ( right->getBasicType() != EbtBool ) { if ( right->getType().getBasicType() != EbtInt && right->getType().getBasicType() != EbtFloat ) return 0; else { // If the right is a float or int, convert to a bool. This is the conversion that HLSL // does right = ir_add_conversion(EOpConstructBool, TType ( EbtBool, right->getPrecision(), right->getQualifier(), right->getColsCount(), right->getRowsCount(), right->isMatrix(), right->isArray()), right, ctx.infoSink); if ( right == 0 ) return 0; } } break; case EOpAdd: case EOpSub: case EOpDiv: case EOpMul: case EOpMod: { TBasicType ltype = left->getType().getBasicType(); TBasicType rtype = right->getType().getBasicType(); if (ltype == EbtStruct) return 0; // If left or right type is a bool, convert to float. bool leftToFloat = (ltype == EbtBool); bool rightToFloat = (rtype == EbtBool); // For modulus, if either is an integer, convert to float as well. if (op == EOpMod) { leftToFloat |= (ltype == EbtInt); rightToFloat |= (rtype == EbtInt); } if (leftToFloat) { left = ir_add_conversion (EOpConstructFloat, TType (EbtFloat, left->getPrecision(), left->getQualifier(), left->getColsCount(), left->getRowsCount(), left->isMatrix(), left->isArray()), left, ctx.infoSink); if (left == 0) return 0; } if (rightToFloat) { right = ir_add_conversion (EOpConstructFloat, TType (EbtFloat, right->getPrecision(), right->getQualifier(), right->getColsCount(), right->getRowsCount(), right->isMatrix(), right->isArray()), right, ctx.infoSink); if (right == 0) return 0; } } break; default: break; } // // First try converting the children to compatible types. // if (!(left->getType().getStruct() && right->getType().getStruct())) { TIntermTyped* child = 0; bool useLeft = true; //default to using the left child as the type to promote to //need to always convert up if ( left->getType().getBasicType() != EbtFloat) { if ( right->getType().getBasicType() == EbtFloat) { useLeft = false; } else { if ( left->getType().getBasicType() != EbtInt) { if ( right->getType().getBasicType() == EbtInt) useLeft = false; } } } if (useLeft) { child = ir_add_conversion(op, left->getType(), right, ctx.infoSink); if (child) right = child; else { child = ir_add_conversion(op, right->getType(), left, ctx.infoSink); if (child) left = child; else return 0; } } else { child = ir_add_conversion(op, right->getType(), left, ctx.infoSink); if (child) left = child; else { child = ir_add_conversion(op, left->getType(), right, ctx.infoSink); if (child) right = child; else return 0; } } } else { if (left->getType() != right->getType()) return 0; } // // Need a new node holding things together then. Make // one and promote it to the right type. // TIntermBinary* node = new TIntermBinary(op); if (line.line == 0) line = right->getLine(); node->setLine(line); node->setLeft(left); node->setRight(right); if (! node->promote(ctx)) return 0; // // See if we can fold constants TIntermConstant* constA = left->getAsConstant(); TIntermConstant* constB = right->getAsConstant(); if (constA && constB) { TIntermConstant* FoldBinaryConstantExpression(TOperator op, TIntermConstant* nodeA, TIntermConstant* nodeB); TIntermConstant* res = FoldBinaryConstantExpression(node->getOp(), constA, constB); if (res) { delete node; return res; } } return node; }
// Add one node as the parent of another that it operates on. TIntermTyped* ir_add_unary_math(TOperator op, TIntermNode* childNode, TSourceLoc line, TParseContext& ctx) { TIntermUnary* node; TIntermTyped* child = childNode->getAsTyped(); if (child == 0) { ctx.infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); return 0; } switch (op) { case EOpLogicalNot: if (!child->isScalar()) return 0; break; case EOpPostIncrement: case EOpPreIncrement: case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) return 0; default: break; } // // Do we need to promote the operand? // // Note: Implicit promotions were removed from the language. // TBasicType newType = EbtVoid; switch (op) { case EOpConstructInt: newType = EbtInt; break; case EOpConstructBool: newType = EbtBool; break; case EOpConstructFloat: newType = EbtFloat; break; case EOpLogicalNot: newType = EbtBool; break; default: break; } if (newType != EbtVoid) { child = ir_add_conversion(op, TType(newType, child->getPrecision(), EvqTemporary, child->getColsCount(), child->getRowsCount(), child->isMatrix(), child->isArray()), child, ctx.infoSink); if (child == 0) return 0; } // // For constructors, we are now done, it's all in the conversion. // switch (op) { case EOpConstructInt: case EOpConstructBool: case EOpConstructFloat: return child; default: break; } TIntermConstant* childConst = child->getAsConstant(); // // Make a new node for the operator. // node = new TIntermUnary(op); if (line.line == 0) line = child->getLine(); node->setLine(line); node->setOperand(child); if (! node->promote(ctx)) return 0; // // See if we can fold constants if (childConst) { TIntermConstant* FoldUnaryConstantExpression(TOperator op, TIntermConstant* node); TIntermConstant* res = FoldUnaryConstantExpression(node->getOp(), childConst); if (res) { delete node; return res; } } return node; }
TIntermTyped* ir_promote_constant(TBasicType promoteTo, TIntermConstant* right, TInfoSink& infoSink) { unsigned size = right->getCount(); const TType& t = right->getType(); TIntermConstant* left = ir_add_constant(TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getColsCount(), t.getRowsCount(), t.isMatrix(), t.isArray()), right->getLine()); for (unsigned i = 0; i != size; ++i) { TIntermConstant::Value& value = right->getValue(i); switch (promoteTo) { case EbtFloat: switch (value.type) { case EbtInt: left->setValue(i, (float)value.asInt); break; case EbtBool: left->setValue(i, (float)value.asBool); break; case EbtFloat: left->setValue(i, value.asFloat); break; default: infoSink.info.message(EPrefixInternalError, "Cannot promote", right->getLine()); return 0; } break; case EbtInt: switch (value.type) { case EbtInt: left->setValue(i, value.asInt); break; case EbtBool: left->setValue(i, (int)value.asBool); break; case EbtFloat: left->setValue(i, (int)value.asFloat); break; default: infoSink.info.message(EPrefixInternalError, "Cannot promote", right->getLine()); return 0; } break; case EbtBool: switch (value.type) { case EbtInt: left->setValue(i, value.asInt != 0); break; case EbtBool: left->setValue(i, value.asBool); break; case EbtFloat: left->setValue(i, value.asFloat != 0.0f); break; default: infoSink.info.message(EPrefixInternalError, "Cannot promote", right->getLine()); return 0; } break; default: infoSink.info.message(EPrefixInternalError, "Incorrect data type found", right->getLine()); return 0; } } return left; }
TType atomic_max( TType * p, TType v ) { return TType(); }
// // 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; }
// // Add one node as the parent of another that it operates on. // // Returns the added node. // TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable) { TIntermUnary* node; TIntermTyped* child = childNode->getAsTyped(); if (child == 0) { infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); return 0; } switch (op) { case EOpLogicalNot: if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { return 0; } break; case EOpPostIncrement: case EOpPreIncrement: case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) return 0; default: break; } // // Do we need to promote the operand? // // Note: Implicit promotions were removed from the language. // TBasicType newType = EbtVoid; switch (op) { case EOpConstructInt: newType = EbtInt; break; case EOpConstructBool: newType = EbtBool; break; case EOpConstructFloat: newType = EbtFloat; break; default: break; } if (newType != EbtVoid) { child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, child->getNominalSize(), child->isMatrix(), child->isArray()), child); if (child == 0) return 0; } // // For constructors, we are now done, it's all in the conversion. // switch (op) { case EOpConstructInt: case EOpConstructBool: case EOpConstructFloat: return child; default: break; } TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) childTempConstant = child->getAsConstantUnion(); // // Make a new node for the operator. // node = new TIntermUnary(op); if (line == 0) line = child->getLine(); node->setLine(line); node->setOperand(child); if (! node->promote(infoSink)) return 0; if (childTempConstant) { TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); if (newChild) return newChild; } return node; }
TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) { ConstantUnion *unionArray = getUnionArrayPointer(); int objectSize = getType().getObjectSize(); if (constantNode) { // binary operations TIntermConstantUnion *node = constantNode->getAsConstantUnion(); ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); TType returnType = getType(); // for a case like float f = 1.2 + vec4(2,3,4,5); if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { rightUnionArray = new ConstantUnion[objectSize]; for (int i = 0; i < objectSize; ++i) rightUnionArray[i] = *node->getUnionArrayPointer(); returnType = getType(); } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { // for a case like float f = vec4(2,3,4,5) + 1.2; unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) unionArray[i] = *getUnionArrayPointer(); returnType = node->getType(); objectSize = constantNode->getType().getObjectSize(); } ConstantUnion* tempConstArray = 0; TIntermConstantUnion *tempNode; bool boolNodeFlag = false; switch(op) { case EOpAdd: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] + rightUnionArray[i]; } break; case EOpSub: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] - rightUnionArray[i]; } break; case EOpMul: case EOpVectorTimesScalar: case EOpMatrixTimesScalar: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] * rightUnionArray[i]; } break; case EOpMatrixTimesMatrix: if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine()); return 0; } {// support MSVC++6.0 int size = getNominalSize(); tempConstArray = new ConstantUnion[size*size]; for (int row = 0; row < size; row++) { for (int column = 0; column < size; column++) { tempConstArray[size * column + row].setFConst(0.0f); for (int i = 0; i < size; i++) { tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); } } } } break; case EOpDiv: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) { switch (getType().getBasicType()) { case EbtFloat: if (rightUnionArray[i] == 0.0f) { infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); tempConstArray[i].setFConst(FLT_MAX); } else tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); break; case EbtInt: if (rightUnionArray[i] == 0) { infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); tempConstArray[i].setIConst(INT_MAX); } else tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); break; default: infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine()); return 0; } } } break; case EOpMatrixTimesVector: if (node->getBasicType() != EbtFloat) { infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine()); return 0; } tempConstArray = new ConstantUnion[getNominalSize()]; {// support MSVC++6.0 for (int size = getNominalSize(), i = 0; i < size; i++) { tempConstArray[i].setFConst(0.0f); for (int j = 0; j < size; j++) { tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); } } } tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); tempNode->setLine(getLine()); return tempNode; case EOpVectorTimesMatrix: if (getType().getBasicType() != EbtFloat) { infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine()); return 0; } tempConstArray = new ConstantUnion[getNominalSize()]; {// support MSVC++6.0 for (int size = getNominalSize(), i = 0; i < size; i++) { tempConstArray[i].setFConst(0.0f); for (int j = 0; j < size; j++) { tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); } } } break; case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] && rightUnionArray[i]; } break; case EOpLogicalOr: // this code is written for possible future use, will not get executed currently tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) tempConstArray[i] = unionArray[i] || rightUnionArray[i]; } break; case EOpLogicalXor: tempConstArray = new ConstantUnion[objectSize]; {// support MSVC++6.0 for (int i = 0; i < objectSize; i++) switch (getType().getBasicType()) { case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; default: assert(false && "Default missing"); } } break; case EOpLessThan: assert(objectSize == 1); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(*unionArray < *rightUnionArray); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; case EOpGreaterThan: assert(objectSize == 1); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(*unionArray > *rightUnionArray); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; case EOpLessThanEqual: { assert(objectSize == 1); ConstantUnion constant; constant.setBConst(*unionArray > *rightUnionArray); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; } case EOpGreaterThanEqual: { assert(objectSize == 1); ConstantUnion constant; constant.setBConst(*unionArray < *rightUnionArray); tempConstArray = new ConstantUnion[1]; tempConstArray->setBConst(!constant.getBConst()); returnType = TType(EbtBool, EbpUndefined, EvqConst); break; } case EOpEqual: if (getType().getBasicType() == EbtStruct) { if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) boolNodeFlag = true; } else { for (int i = 0; i < objectSize; i++) { if (unionArray[i] != rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } tempConstArray = new ConstantUnion[1]; if (!boolNodeFlag) { tempConstArray->setBConst(true); } else { tempConstArray->setBConst(false); } tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); tempNode->setLine(getLine()); return tempNode; case EOpNotEqual: if (getType().getBasicType() == EbtStruct) { if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) boolNodeFlag = true; } else { for (int i = 0; i < objectSize; i++) { if (unionArray[i] == rightUnionArray[i]) { boolNodeFlag = true; break; // break out of for loop } } } tempConstArray = new ConstantUnion[1]; if (!boolNodeFlag) { tempConstArray->setBConst(true); } else { tempConstArray->setBConst(false); } tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); tempNode->setLine(getLine()); return tempNode; default: infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine()); return 0; } tempNode = new TIntermConstantUnion(tempConstArray, returnType); tempNode->setLine(getLine()); return tempNode; } else { // // Do unary operations // TIntermConstantUnion *newNode = 0; ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; for (int i = 0; i < objectSize; i++) { switch(op) { case EOpNegative: switch (getType().getBasicType()) { case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; default: infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); return 0; } break; case EOpLogicalNot: // this code is written for possible future use, will not get executed currently switch (getType().getBasicType()) { case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; default: infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); return 0; } break; default: return 0; } } newNode = new TIntermConstantUnion(tempConstArray, getType()); newNode->setLine(getLine()); return newNode; } }
// // Initializers show up in several places in the grammar. Have one set of // code to handle them here. // bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) { TType type = TType(pType); if (variable == 0) { if (reservedErrorCheck(line, identifier)) return true; if (voidErrorCheck(line, identifier, pType)) return true; // // add variable to symbol table // variable = new TVariable(&identifier, type); if (! symbolTable.insert(*variable)) { error(line, "redefinition", variable->getName().c_str(), ""); return true; // don't delete variable, it's used by error recovery, and the pool // pop will take care of the memory } } // // identifier must be of type constant, a global, or a temporary // TQualifier qualifier = variable->getType().getQualifier(); if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) { error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), ""); return true; } // // test for and propagate constant // if (qualifier == EvqConst) { if (qualifier != initializer->getType().getQualifier()) { error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str()); variable->getType().setQualifier(EvqTemporary); return true; } if (type != initializer->getType()) { error(line, " non-matching types for const initializer ", variable->getType().getQualifierString(), ""); variable->getType().setQualifier(EvqTemporary); return true; } if (initializer->getAsConstantUnion()) { ConstantUnion* unionArray = variable->getConstPointer(); if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) { *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0]; } else { variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); } } else if (initializer->getAsSymbolNode()) { const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); const TVariable* tVar = static_cast<const TVariable*>(symbol); ConstantUnion* constArray = tVar->getConstPointer(); variable->shareConstPointer(constArray); } else { error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str()); variable->getType().setQualifier(EvqTemporary); return true; } } if (qualifier != EvqConst) { TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); if (intermNode == 0) { assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); return true; } } else intermNode = 0; return false; }
// // Do all the semantic checking for declaring an array, with and // without a size, and make the right changes to the symbol table. // // size == 0 means no specified size. // // Returns true if there was an error. // bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable) { // // Don't check for reserved word use until after we know it's not in the symbol table, // because reserved arrays can be redeclared. // bool builtIn = false; bool sameScope = false; TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope); if (symbol == 0 || !sameScope) { if (reservedErrorCheck(line, identifier)) return true; variable = new TVariable(&identifier, TType(type)); if (type.arraySize) variable->getType().setArraySize(type.arraySize); if (! symbolTable.insert(*variable)) { delete variable; error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str(), ""); return true; } } else { if (! symbol->isVariable()) { error(line, "variable expected", identifier.c_str(), ""); return true; } variable = static_cast<TVariable*>(symbol); if (! variable->getType().isArray()) { error(line, "redeclaring non-array as array", identifier.c_str(), ""); return true; } if (variable->getType().getArraySize() > 0) { error(line, "redeclaration of array with size", identifier.c_str(), ""); return true; } if (! variable->getType().sameElementType(TType(type))) { error(line, "redeclaration of array with a different type", identifier.c_str(), ""); return true; } TType* t = variable->getArrayInformationType(); while (t != 0) { if (t->getMaxArraySize() > type.arraySize) { error(line, "higher index value already used for the array", identifier.c_str(), ""); return true; } t->setArraySize(type.arraySize); t = t->getArrayInformationType(); } if (type.arraySize) variable->getType().setArraySize(type.arraySize); } if (voidErrorCheck(line, identifier, type)) return true; return false; }
void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) { // // Insert some special built-in variables that are not in // the built-in header files. // switch (type) { case GL_FRAGMENT_SHADER: symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); { symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); fragData.setArraySize(resources.MaxDrawBuffers); symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); if (resources.EXT_blend_func_extended) { symbolTable.insert( ESSL1_BUILTINS, "GL_EXT_blend_func_extended", new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"), TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4))); TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true); secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers); symbolTable.insert( ESSL1_BUILTINS, "GL_EXT_blend_func_extended", new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData)); } if (resources.EXT_frag_depth) { symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_frag_depth", new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); } if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch) { TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); lastFragData.setArraySize(resources.MaxDrawBuffers); if (resources.EXT_shader_framebuffer_fetch) { symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); } else if (resources.NV_shader_framebuffer_fetch) { symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragColor"), TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); } } else if (resources.ARM_shader_framebuffer_fetch) { symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", new TVariable(NewPoolTString("gl_LastFragColorARM"), TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); } } break; case GL_VERTEX_SHADER: symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1))); symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"), TType(EbtInt, EbpHigh, EvqInstanceID, 1))); break; default: assert(false && "Language not supported"); } }
// // 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; }
TType atomic_add( TType * p, TType v ) { return TType(); }
TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) { ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); int size = node->getType().getObjectSize(); ConstantUnion *leftUnionArray = new ConstantUnion[size]; for (int i=0; i < size; i++) { switch (promoteTo) { case EbtFloat: switch (node->getType().getBasicType()) { case EbtInt: leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst())); break; case EbtBool: leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst())); break; case EbtFloat: leftUnionArray[i] = rightUnionArray[i]; break; default: infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); return 0; } break; case EbtInt: switch (node->getType().getBasicType()) { case EbtInt: leftUnionArray[i] = rightUnionArray[i]; break; case EbtBool: leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst())); break; case EbtFloat: leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst())); break; default: infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); return 0; } break; case EbtBool: switch (node->getType().getBasicType()) { case EbtInt: leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0); break; case EbtBool: leftUnionArray[i] = rightUnionArray[i]; break; case EbtFloat: leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f); break; default: infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); return 0; } break; default: infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine()); return 0; } } const TType& t = node->getType(); return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); }
TType abs_diff( TType, TType ) { return TType(); }