AstNode* Parser::parseStatement() { if (isKeyword(currentTokenValue())) { if (currentTokenValue() == "function") { return parseFunction(); } else if (currentTokenValue() == "for") { return parseFor(); } else if (currentTokenValue() == "if") { return parseIf(); } else if (currentTokenValue() == "while") { return parseWhile(); } else if (currentTokenValue() == "print") { return parsePrint(); } else if (currentTokenValue() == "int") { return parseDeclaration(VT_INT); } else if (currentTokenValue() == "double") { return parseDeclaration(VT_DOUBLE); } else if (currentTokenValue() == "string") { return parseDeclaration(VT_STRING); } else if (currentTokenValue() == "return") { return parseReturn(); } else { cout << "unhandled keyword " << currentTokenValue() << endl; assert(false); return 0; } } if (currentToken() == tLBRACE) { return parseBlock(true); } if ((currentToken() == tIDENT) && isAssignment(lookaheadToken(1))) { return parseAssignment(); } return parseExpression(); }
QString CharacterClassSettings::toOperator(QString op) const { if(!isOperator(op))return QString(); if(!isAssignment(op))return op; if(d->assignmentChars.first!=0)op=op.mid(1); if(d->assignmentChars.second!=0)op=op.left(op.size()-1); return op; }
void SimdStringType::generateCode (const SyntaxNodePtr &node, LContext &lcontext) const { SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext); if (isAssignment (node)) { slcontext.addInst (new SimdAssignInst (alignedObjectSize(), node->lineNumber)); return; } if (UnaryOpNodePtr unOp = node.cast<UnaryOpNode>()) { switch (unOp->op) { default: MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << unOp->operand->type->asString() << "."); } return; } if (BinaryOpNodePtr binOp = node.cast<BinaryOpNode>()) { switch (binOp->op) { default: MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } return; } if (node.cast<CallNode>()) { // // Push a placeholder for the return value for a call to // a function that returns an int. // slcontext.addInst (new SimdPushPlaceholderInst (alignedObjectSize(), node->lineNumber)); return; } }
static bool isTrivialAssignment(FnSymbol* fn, FnSet& visited) { if (! isAssignment(fn)) return false; if (isTrivial(fn, visited)) return true; return false; }
void SimdArrayType::generateCode (const SyntaxNodePtr &node, LContext &lcontext) const { SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext); VariableNodePtr var = node.cast<VariableNode>(); if( var && var->initialValue.cast<ValueNode>()) { SizeVector sizes; SizeVector offsets; coreSizes(0, sizes, offsets); slcontext.addInst (new SimdInitializeInst(sizes, offsets, node->lineNumber)); return; } else if (isAssignment(node)) // return or assignment { slcontext.addInst (new SimdAssignArrayInst (size(), elementSize(), node->lineNumber)); return; } else if ( node.cast<ArrayIndexNode>() ) { if(unknownSize() || unknownElementSize()) { slcontext.addInst (new SimdIndexVSArrayInst(elementSize(), unknownElementSize(), size(), unknownSize(), node->lineNumber)); } else { slcontext.addInst (new SimdIndexArrayInst(elementSize(), node->lineNumber, size())); } return; } else if (node.cast<SizeNode>()) { assert(size() == 0); slcontext.addInst (new SimdPushRefInst (unknownSize(), node->lineNumber)); } else if (node.cast<CallNode>()) { slcontext.addInst (new SimdPushPlaceholderInst(objectSize(), node->lineNumber)); return; } }
void SetNonzerosSlice<Add>::simplifyMe(MX& ex) { // Simplify if addition if (isAssignment()) { MX t = this->dep(1); if (Add) { ex += t; } else { ex = t; } } }
void SimdStructType::generateCode (const SyntaxNodePtr &node, LContext &lcontext) const { SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext); VariableNodePtr var = node.cast<VariableNode>(); if( var && var->initialValue.cast<ValueNode>()) { SizeVector sizes; SizeVector offsets; coreSizes(0, sizes, offsets); slcontext.addInst (new SimdInitializeInst(sizes, offsets, node->lineNumber)); return; } if( MemberNodePtr mem = node.cast<MemberNode>() ) { slcontext.addInst (new SimdAccessMemberInst(mem->offset, (node->lineNumber))); return; } if (isAssignment (node)) { slcontext.addInst (new SimdAssignInst (alignedObjectSize(), node->lineNumber)); return; } if (node.cast<CallNode>()) { // Push a placeholder for the return value for a call to // a function that returns a struct slcontext.addInst (new SimdPushPlaceholderInst (alignedObjectSize(), node->lineNumber)); return; } }
bool BinaryOpNode::ContainLvalueRecourse(VarSymbol *id) const { return isAssignment(token->value) && ( left->isIdent() && dynamic_cast<IdentifierNode*>(left)->token->str == id->name || left->ContainLvalueRecourse(id) || right->ContainLvalueRecourse(id)); }
void MibParser::doTrapTypes(ifstream* ifile) { skipImports(ifile); // now lets do trap types while (!ifile->eof()) { try { // read each line of file char lineBuffer[4096]; char* lineBuf = lineBuffer; memset(lineBuffer, 0, 4096); ifile->getline(lineBuffer, 4096); int count = ifile->gcount(); if (isComment(lineBuf)) continue; if (strstr(lineBuf, "DESCRIPTION")) skipDescription(lineBuf, ifile); if (isTrapType(lineBuf)) { node* n = new node; n->trap = true; while (*lineBuf == ' ' || *lineBuf == '\t') lineBuf++; char* spec = strstr(lineBuf, "TRAP-TYPE"); if (spec != NULL) { spec--; while (*spec == ' ' || *spec == '\t') spec--; } *++spec = 0; strncpy(n->name, lineBuf, 256); while (1) { memset(lineBuffer, 0, 4096); lineBuf = lineBuffer; ifile->getline(lineBuffer, 4096); count = ifile->gcount(); if (isEnterprise(lineBuf)) { char* ent = strstr(lineBuf, "ENTERPRISE"); ent += 10; // while (*ent == ' ' || *ent == '\t') while (*ent == ' ' || *ent == '\t' || *ent == '{') ent++; // int len = strlen(lineBuf); int len = strlen(ent); char* entEnd = ent + (len - 1); // while (*entEnd == ' ' || *entEnd == '\r' || *entEnd == '\t') while (*entEnd == ' ' || *entEnd == '\r' || *entEnd == '\t' || *entEnd == '}') entEnd--; *++entEnd = 0; strncpy(n->oid, ent, 256); } if (isAssignment(lineBuf)) { char* assign = strstr(lineBuf, "::="); assign += 3; while (*assign == ' ' || *assign == '\t') assign++; ////////////////////// char* commentSpec = strstr(assign, "--"); if (commentSpec != NULL) *commentSpec = 0; ////////////////////// char* assignEnd = assign + (strlen(assign) - 1); while (*assignEnd == ' ' || *assignEnd == '\r' || *assignEnd == '\t') assignEnd--; *++assignEnd = 0; strcat(n->oid, "."); strcat(n->oid, assign); n->insert(n); break; } if (isVariableClause(lineBuf)) { BOOL done = FALSE; char* firstPosition; char* lastPosition; int currentCount; int state = OPENCURLY; int nextState; while (!done) { switch (state) { case GETLINE: { memset(lineBuffer, 0, 4096); lineBuf = lineBuffer; ifile->getline(lineBuffer, 4096); count = ifile->gcount(); currentCount = 1; state = nextState; firstPosition = lineBuf; break; } case OPENCURLY: { firstPosition = lineBuf; // find the opening curly brace for (currentCount = 1; currentCount < count; currentCount++) { if (*firstPosition != '{') firstPosition++; else break; } if (currentCount == count) { // look on next line nextState = state; state = GETLINE; } else { firstPosition++; currentCount++; state = FINDVARBIND; } break; } case FINDVARBIND: { // now skip white space to first varbind for (; currentCount < count; currentCount++) { if (*firstPosition == ' ' || *firstPosition == '\t') firstPosition++; else break; } if (currentCount == count) { nextState = state; state = GETLINE; } else { // now find end of first varbind lastPosition = firstPosition; for (; currentCount < count; currentCount++) { if (*lastPosition != ' ' && *lastPosition != '\t' && *lastPosition != ',' && *lastPosition != '}') lastPosition++; else break; } if (currentCount == count) // error { state = DONE; break; } char saveChar = *lastPosition; *lastPosition = 0; markInUse(firstPosition); *lastPosition = saveChar; if (saveChar == ',') { lastPosition++; currentCount++; } else if (strchr(lastPosition, '}')) state = DONE; firstPosition = lastPosition; } break; } case DONE: done = TRUE; break; } // switch (state) } // while (!done) } // if (isVariableClause(lineBuf)) } // while (1) } // if (isTrapType(lineBuf)) } catch(...) { } } ifile->clear(); ifile->seekg(0); }
void SimdHalfType::generateCode (const SyntaxNodePtr &node, LContext &lcontext) const { SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext); if (isAssignment (node)) { slcontext.addInst (new SimdAssignInst (alignedObjectSize(), node->lineNumber)); return; } if (UnaryOpNodePtr unOp = node.cast<UnaryOpNode>()) { switch (unOp->op) { case TK_MINUS: slcontext.addInst (new SimdUnaryOpInst <half, half, UnaryMinusOp> (node->lineNumber)); break; default: MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << unOp->operand->type->asString() << "."); } return; } if (BinaryOpNodePtr binOp = node.cast<BinaryOpNode>()) { switch (binOp->op) { case TK_DIV: slcontext.addInst (new SimdBinaryOpInst <half, half, half, DivOp> (node->lineNumber)); break; case TK_EQUAL: slcontext.addInst (new SimdBinaryOpInst <half, half, bool, EqualOp> (node->lineNumber)); break; case TK_GREATER: slcontext.addInst (new SimdBinaryOpInst <half, half, bool, GreaterOp> (node->lineNumber)); break; case TK_GREATEREQUAL: slcontext.addInst (new SimdBinaryOpInst <half, half, bool, GreaterEqualOp> (node->lineNumber)); break; case TK_LESS: slcontext.addInst (new SimdBinaryOpInst <half, half, bool, LessOp> (node->lineNumber)); break; case TK_LESSEQUAL: slcontext.addInst (new SimdBinaryOpInst <half, half, bool, LessEqualOp> (node->lineNumber)); break; case TK_MINUS: slcontext.addInst (new SimdBinaryOpInst <half, half, half, BinaryMinusOp> (node->lineNumber)); break; case TK_NOTEQUAL: slcontext.addInst (new SimdBinaryOpInst <half, half, bool, NotEqualOp> (node->lineNumber)); break; case TK_PLUS: slcontext.addInst (new SimdBinaryOpInst <half, half, half, PlusOp> (node->lineNumber)); break; case TK_TIMES: slcontext.addInst (new SimdBinaryOpInst <half, half, half, TimesOp> (node->lineNumber)); break; default: MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } return; } if (node.cast<CallNode>()) { // // Push a placeholder for the return value for a call to // a function that returns an int. // slcontext.addInst (new SimdPushPlaceholderInst (alignedObjectSize(), node->lineNumber)); return; } }
void SimdBoolType::generateCode (const SyntaxNodePtr &node, LContext &lcontext) const { SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext); if (isAssignment (node)) { slcontext.addInst (new SimdAssignInst (alignedObjectSize(), node->lineNumber)); return; } if (UnaryOpNodePtr unOp = node.cast<UnaryOpNode>()) { switch (unOp->op) { case TK_BITNOT: // // We use the C++ ! operation to evaluate the CTL expression ~x, // where x is of type bool. This ensures that ~true == false // and ~false == true. // slcontext.addInst (new SimdUnaryOpInst <bool, bool, NotOp>(node->lineNumber)); break; case TK_NOT: slcontext.addInst (new SimdUnaryOpInst <bool, bool, NotOp>(node->lineNumber)); break; default: MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << unOp->operand->type->asString() << "."); } return; } if (BinaryOpNodePtr binOp = node.cast<BinaryOpNode>()) { switch (binOp->op) { case TK_BITAND: // // For the bit-wise &, | and ^ operators, we normalize bool // operands before applying the operators. This avoids // surprises, for example, true^true == true. // slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, BoolBitAndOp> (node->lineNumber)); break; case TK_BITOR: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, BoolBitOrOp> (node->lineNumber)); break; case TK_BITXOR: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, BoolBitXorOp> (node->lineNumber)); break; case TK_EQUAL: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, EqualOp> (node->lineNumber)); break; case TK_GREATER: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, GreaterOp> (node->lineNumber)); break; case TK_GREATEREQUAL: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, GreaterEqualOp> (node->lineNumber)); break; case TK_LESS: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, LessOp> (node->lineNumber)); break; case TK_LESSEQUAL: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, LessEqualOp> (node->lineNumber)); break; case TK_NOTEQUAL: slcontext.addInst (new SimdBinaryOpInst <bool, bool, bool, NotEqualOp> (node->lineNumber)); break; default: MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } return; } if (node.cast<CallNode>()) { // // Push a placeholder for the return value for a call to // a function that returns an int. // slcontext.addInst (new SimdPushPlaceholderInst(alignedObjectSize(), node->lineNumber)); return; } }
// The argument is assumed to be an assignment function. // It is deemed to be simple if it contains only 'move', 'addr of', '=', // 'return' primitives and calls only simple assignments (recursively). // We also require that it return void (for now). // The FLAG_TRIVIAL_ASSIGNMENT is used to ensure that we visit each such // function only once. static bool isTrivial(FnSymbol* fn, FnSet& visited) { // Visit each function only once. if (visited.find(fn) != visited.end()) { // Found it. if (fn->hasFlag(FLAG_TRIVIAL_ASSIGNMENT)) return true; else return false; } visited.insert(fn); // We assume that compiler-generated assignments are field-by-field copies. // Note that this overloads the meaning of this flag with: // "Assignment operations flagged as 'compiler generated' shall contain only // field assignments and assignment primitives." // We can then assume that all nested calls are field extractions or // assignments, and we only have to check the latter. if (! fn->hasFlag(FLAG_COMPILER_GENERATED)) return false; // After all compiler-supplied assignments use the new signature, this can // become an assert. if (fn->retType != dtVoid) return false; // The base argument types must match. ArgSymbol* lhs = fn->getFormal(1); ArgSymbol* rhs = fn->getFormal(2); if (lhs->type->getValType() != rhs->type->getValType()) return false; // Assume this is a field-by-field copy. // If none of the fields of this record (or tuple) has a user-defined // assignment (recursively), then it can be replaced by a bulk copy. // Traverse the call expressions in the body of the function. // These should all be one of the allowed primitives or calls to simple // assignments. If anything else, the assignment is "interesting", and // cannot be replaced. std::vector<BaseAST*> asts; collect_asts_STL(fn->body, asts); for_vector(BaseAST, ast, asts) { if (CallExpr* call = toCallExpr(ast)) { if (FnSymbol* fieldAsgn = call->isResolved()) { if (isAssignment(fieldAsgn)) if (! isTrivial(fieldAsgn, visited)) return false; } else { // This is a primitive. switch(call->primitive->tag) { default: return false; // These are the allowable primitives. case PRIM_MOVE: case PRIM_ASSIGN: case PRIM_ADDR_OF: case PRIM_DEREF: case PRIM_GET_MEMBER: case PRIM_GET_MEMBER_VALUE: case PRIM_SET_MEMBER: case PRIM_RETURN: // We expect return _void. break; } } } } fn->addFlag(FLAG_TRIVIAL_ASSIGNMENT); return true; }
sExpression *eval(sExpression *exp, sEnvironment *env){ /* ------------------atom-----------------------*/ /* 1, 10, false, null, "abc" */ if(isSelfEval(exp)) { return exp; } /* a symbol */ else if(isVariable(exp, env)) { return lookupVariable(toSymb(exp), env); } /* ------------------list-----------------------*/ /* (quote blur blur) */ else if(isQuoted(exp)) { return textOfQuoted(exp); } /* (set! name value) */ else if(isAssignment(exp)) { return evalAssignment(exp, env); } /* (define name value) */ else if(isDefinition(exp)) { return evalDefine(exp, env); } /* (define-syntax name ...) */ else if(isDefinitionSyntax(exp)) { return evalDefineSyntax(exp, env); } /* (if blur blur blur) */ else if(isIf(exp)) { return evalIf(toList(exp), env); } /* (lambda (args) (body)) */ else if(isLambdaConst(exp)) { sList *body; sList *param = toList( cadr(toList(exp))); sExpression *temp = cdr(toList( cdr(toList(exp)))); if(isList(temp)){ body = toList(temp); }else{ body = toList(cons(temp, &sNull)); } return newLambda(param, body, env); } /* (syntax blur blur) syntax rule */ else if(isSymbol(car(toList(exp))) && isSyntaxRule(eval(car(toList(exp)), env))) { sExpression *exp2 = evalSyntaxRule(toSyntax(eval(car(toList(exp)), env)), exp); return eval(exp2, env); } /* the other list (x . y) */ else if(isApplication(exp)) { if(LAZY_EVAL){ sExpression *proexp = actualValue(operator(toList(exp)), env); if(isLambdaType(proexp) || isPrimitiveProc(proexp)){ sExpression *operand = operands(toList(exp)); return applyLazly(proexp, operand, env); } }else{ sExpression *proexp = eval(operator(toList(exp)), env); if(isLambdaType(proexp) || isPrimitiveProc(proexp)){ sExpression *operand = operands(toList(exp)); sExpression *arguments = listOfValues(operand, env); return apply(proexp, arguments, env); } } } return &sError; }
// // 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; }