1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 9cb93a386Sopenharmony_ci#include "src/sksl/SkSLContext.h" 10cb93a386Sopenharmony_ci#include "src/sksl/SkSLOperators.h" 11cb93a386Sopenharmony_ci#include "src/sksl/SkSLProgramSettings.h" 12cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLType.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cinamespace SkSL { 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ciOperator::Precedence Operator::getBinaryPrecedence() const { 17cb93a386Sopenharmony_ci switch (this->kind()) { 18cb93a386Sopenharmony_ci case Kind::TK_STAR: // fall through 19cb93a386Sopenharmony_ci case Kind::TK_SLASH: // fall through 20cb93a386Sopenharmony_ci case Kind::TK_PERCENT: return Precedence::kMultiplicative; 21cb93a386Sopenharmony_ci case Kind::TK_PLUS: // fall through 22cb93a386Sopenharmony_ci case Kind::TK_MINUS: return Precedence::kAdditive; 23cb93a386Sopenharmony_ci case Kind::TK_SHL: // fall through 24cb93a386Sopenharmony_ci case Kind::TK_SHR: return Precedence::kShift; 25cb93a386Sopenharmony_ci case Kind::TK_LT: // fall through 26cb93a386Sopenharmony_ci case Kind::TK_GT: // fall through 27cb93a386Sopenharmony_ci case Kind::TK_LTEQ: // fall through 28cb93a386Sopenharmony_ci case Kind::TK_GTEQ: return Precedence::kRelational; 29cb93a386Sopenharmony_ci case Kind::TK_EQEQ: // fall through 30cb93a386Sopenharmony_ci case Kind::TK_NEQ: return Precedence::kEquality; 31cb93a386Sopenharmony_ci case Kind::TK_BITWISEAND: return Precedence::kBitwiseAnd; 32cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOR: return Precedence::kBitwiseXor; 33cb93a386Sopenharmony_ci case Kind::TK_BITWISEOR: return Precedence::kBitwiseOr; 34cb93a386Sopenharmony_ci case Kind::TK_LOGICALAND: return Precedence::kLogicalAnd; 35cb93a386Sopenharmony_ci case Kind::TK_LOGICALXOR: return Precedence::kLogicalXor; 36cb93a386Sopenharmony_ci case Kind::TK_LOGICALOR: return Precedence::kLogicalOr; 37cb93a386Sopenharmony_ci case Kind::TK_EQ: // fall through 38cb93a386Sopenharmony_ci case Kind::TK_PLUSEQ: // fall through 39cb93a386Sopenharmony_ci case Kind::TK_MINUSEQ: // fall through 40cb93a386Sopenharmony_ci case Kind::TK_STAREQ: // fall through 41cb93a386Sopenharmony_ci case Kind::TK_SLASHEQ: // fall through 42cb93a386Sopenharmony_ci case Kind::TK_PERCENTEQ: // fall through 43cb93a386Sopenharmony_ci case Kind::TK_SHLEQ: // fall through 44cb93a386Sopenharmony_ci case Kind::TK_SHREQ: // fall through 45cb93a386Sopenharmony_ci case Kind::TK_BITWISEANDEQ: // fall through 46cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOREQ: // fall through 47cb93a386Sopenharmony_ci case Kind::TK_BITWISEOREQ: return Precedence::kAssignment; 48cb93a386Sopenharmony_ci case Kind::TK_COMMA: return Precedence::kSequence; 49cb93a386Sopenharmony_ci default: SK_ABORT("unsupported binary operator"); 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci} 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_cibool Operator::isOperator() const { 54cb93a386Sopenharmony_ci switch (this->kind()) { 55cb93a386Sopenharmony_ci case Kind::TK_PLUS: 56cb93a386Sopenharmony_ci case Kind::TK_MINUS: 57cb93a386Sopenharmony_ci case Kind::TK_STAR: 58cb93a386Sopenharmony_ci case Kind::TK_SLASH: 59cb93a386Sopenharmony_ci case Kind::TK_PERCENT: 60cb93a386Sopenharmony_ci case Kind::TK_SHL: 61cb93a386Sopenharmony_ci case Kind::TK_SHR: 62cb93a386Sopenharmony_ci case Kind::TK_LOGICALNOT: 63cb93a386Sopenharmony_ci case Kind::TK_LOGICALAND: 64cb93a386Sopenharmony_ci case Kind::TK_LOGICALOR: 65cb93a386Sopenharmony_ci case Kind::TK_LOGICALXOR: 66cb93a386Sopenharmony_ci case Kind::TK_BITWISENOT: 67cb93a386Sopenharmony_ci case Kind::TK_BITWISEAND: 68cb93a386Sopenharmony_ci case Kind::TK_BITWISEOR: 69cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOR: 70cb93a386Sopenharmony_ci case Kind::TK_EQ: 71cb93a386Sopenharmony_ci case Kind::TK_EQEQ: 72cb93a386Sopenharmony_ci case Kind::TK_NEQ: 73cb93a386Sopenharmony_ci case Kind::TK_LT: 74cb93a386Sopenharmony_ci case Kind::TK_GT: 75cb93a386Sopenharmony_ci case Kind::TK_LTEQ: 76cb93a386Sopenharmony_ci case Kind::TK_GTEQ: 77cb93a386Sopenharmony_ci case Kind::TK_PLUSEQ: 78cb93a386Sopenharmony_ci case Kind::TK_MINUSEQ: 79cb93a386Sopenharmony_ci case Kind::TK_STAREQ: 80cb93a386Sopenharmony_ci case Kind::TK_SLASHEQ: 81cb93a386Sopenharmony_ci case Kind::TK_PERCENTEQ: 82cb93a386Sopenharmony_ci case Kind::TK_SHLEQ: 83cb93a386Sopenharmony_ci case Kind::TK_SHREQ: 84cb93a386Sopenharmony_ci case Kind::TK_BITWISEANDEQ: 85cb93a386Sopenharmony_ci case Kind::TK_BITWISEOREQ: 86cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOREQ: 87cb93a386Sopenharmony_ci case Kind::TK_PLUSPLUS: 88cb93a386Sopenharmony_ci case Kind::TK_MINUSMINUS: 89cb93a386Sopenharmony_ci case Kind::TK_COMMA: 90cb93a386Sopenharmony_ci return true; 91cb93a386Sopenharmony_ci default: 92cb93a386Sopenharmony_ci return false; 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci} 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ciconst char* Operator::operatorName() const { 97cb93a386Sopenharmony_ci switch (this->kind()) { 98cb93a386Sopenharmony_ci case Kind::TK_PLUS: return "+"; 99cb93a386Sopenharmony_ci case Kind::TK_MINUS: return "-"; 100cb93a386Sopenharmony_ci case Kind::TK_STAR: return "*"; 101cb93a386Sopenharmony_ci case Kind::TK_SLASH: return "/"; 102cb93a386Sopenharmony_ci case Kind::TK_PERCENT: return "%"; 103cb93a386Sopenharmony_ci case Kind::TK_SHL: return "<<"; 104cb93a386Sopenharmony_ci case Kind::TK_SHR: return ">>"; 105cb93a386Sopenharmony_ci case Kind::TK_LOGICALNOT: return "!"; 106cb93a386Sopenharmony_ci case Kind::TK_LOGICALAND: return "&&"; 107cb93a386Sopenharmony_ci case Kind::TK_LOGICALOR: return "||"; 108cb93a386Sopenharmony_ci case Kind::TK_LOGICALXOR: return "^^"; 109cb93a386Sopenharmony_ci case Kind::TK_BITWISENOT: return "~"; 110cb93a386Sopenharmony_ci case Kind::TK_BITWISEAND: return "&"; 111cb93a386Sopenharmony_ci case Kind::TK_BITWISEOR: return "|"; 112cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOR: return "^"; 113cb93a386Sopenharmony_ci case Kind::TK_EQ: return "="; 114cb93a386Sopenharmony_ci case Kind::TK_EQEQ: return "=="; 115cb93a386Sopenharmony_ci case Kind::TK_NEQ: return "!="; 116cb93a386Sopenharmony_ci case Kind::TK_LT: return "<"; 117cb93a386Sopenharmony_ci case Kind::TK_GT: return ">"; 118cb93a386Sopenharmony_ci case Kind::TK_LTEQ: return "<="; 119cb93a386Sopenharmony_ci case Kind::TK_GTEQ: return ">="; 120cb93a386Sopenharmony_ci case Kind::TK_PLUSEQ: return "+="; 121cb93a386Sopenharmony_ci case Kind::TK_MINUSEQ: return "-="; 122cb93a386Sopenharmony_ci case Kind::TK_STAREQ: return "*="; 123cb93a386Sopenharmony_ci case Kind::TK_SLASHEQ: return "/="; 124cb93a386Sopenharmony_ci case Kind::TK_PERCENTEQ: return "%="; 125cb93a386Sopenharmony_ci case Kind::TK_SHLEQ: return "<<="; 126cb93a386Sopenharmony_ci case Kind::TK_SHREQ: return ">>="; 127cb93a386Sopenharmony_ci case Kind::TK_BITWISEANDEQ: return "&="; 128cb93a386Sopenharmony_ci case Kind::TK_BITWISEOREQ: return "|="; 129cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOREQ: return "^="; 130cb93a386Sopenharmony_ci case Kind::TK_PLUSPLUS: return "++"; 131cb93a386Sopenharmony_ci case Kind::TK_MINUSMINUS: return "--"; 132cb93a386Sopenharmony_ci case Kind::TK_COMMA: return ","; 133cb93a386Sopenharmony_ci default: 134cb93a386Sopenharmony_ci SK_ABORT("unsupported operator: %d\n", (int) fKind); 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci} 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_cibool Operator::isAssignment() const { 139cb93a386Sopenharmony_ci switch (this->kind()) { 140cb93a386Sopenharmony_ci case Kind::TK_EQ: // fall through 141cb93a386Sopenharmony_ci case Kind::TK_PLUSEQ: // fall through 142cb93a386Sopenharmony_ci case Kind::TK_MINUSEQ: // fall through 143cb93a386Sopenharmony_ci case Kind::TK_STAREQ: // fall through 144cb93a386Sopenharmony_ci case Kind::TK_SLASHEQ: // fall through 145cb93a386Sopenharmony_ci case Kind::TK_PERCENTEQ: // fall through 146cb93a386Sopenharmony_ci case Kind::TK_SHLEQ: // fall through 147cb93a386Sopenharmony_ci case Kind::TK_SHREQ: // fall through 148cb93a386Sopenharmony_ci case Kind::TK_BITWISEOREQ: // fall through 149cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOREQ: // fall through 150cb93a386Sopenharmony_ci case Kind::TK_BITWISEANDEQ: 151cb93a386Sopenharmony_ci return true; 152cb93a386Sopenharmony_ci default: 153cb93a386Sopenharmony_ci return false; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci} 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ciOperator Operator::removeAssignment() const { 158cb93a386Sopenharmony_ci switch (this->kind()) { 159cb93a386Sopenharmony_ci case Kind::TK_PLUSEQ: return Operator{Kind::TK_PLUS}; 160cb93a386Sopenharmony_ci case Kind::TK_MINUSEQ: return Operator{Kind::TK_MINUS}; 161cb93a386Sopenharmony_ci case Kind::TK_STAREQ: return Operator{Kind::TK_STAR}; 162cb93a386Sopenharmony_ci case Kind::TK_SLASHEQ: return Operator{Kind::TK_SLASH}; 163cb93a386Sopenharmony_ci case Kind::TK_PERCENTEQ: return Operator{Kind::TK_PERCENT}; 164cb93a386Sopenharmony_ci case Kind::TK_SHLEQ: return Operator{Kind::TK_SHL}; 165cb93a386Sopenharmony_ci case Kind::TK_SHREQ: return Operator{Kind::TK_SHR}; 166cb93a386Sopenharmony_ci case Kind::TK_BITWISEOREQ: return Operator{Kind::TK_BITWISEOR}; 167cb93a386Sopenharmony_ci case Kind::TK_BITWISEXOREQ: return Operator{Kind::TK_BITWISEXOR}; 168cb93a386Sopenharmony_ci case Kind::TK_BITWISEANDEQ: return Operator{Kind::TK_BITWISEAND}; 169cb93a386Sopenharmony_ci default: return *this; 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci} 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_cibool Operator::isLogical() const { 174cb93a386Sopenharmony_ci switch (this->kind()) { 175cb93a386Sopenharmony_ci case Token::Kind::TK_LT: 176cb93a386Sopenharmony_ci case Token::Kind::TK_GT: 177cb93a386Sopenharmony_ci case Token::Kind::TK_LTEQ: 178cb93a386Sopenharmony_ci case Token::Kind::TK_GTEQ: 179cb93a386Sopenharmony_ci return true; 180cb93a386Sopenharmony_ci default: 181cb93a386Sopenharmony_ci return false; 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci} 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_cibool Operator::isOnlyValidForIntegralTypes() const { 186cb93a386Sopenharmony_ci switch (this->kind()) { 187cb93a386Sopenharmony_ci case Token::Kind::TK_SHL: 188cb93a386Sopenharmony_ci case Token::Kind::TK_SHR: 189cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEAND: 190cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEOR: 191cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEXOR: 192cb93a386Sopenharmony_ci case Token::Kind::TK_PERCENT: 193cb93a386Sopenharmony_ci case Token::Kind::TK_SHLEQ: 194cb93a386Sopenharmony_ci case Token::Kind::TK_SHREQ: 195cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEANDEQ: 196cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEOREQ: 197cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEXOREQ: 198cb93a386Sopenharmony_ci case Token::Kind::TK_PERCENTEQ: 199cb93a386Sopenharmony_ci return true; 200cb93a386Sopenharmony_ci default: 201cb93a386Sopenharmony_ci return false; 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci} 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_cibool Operator::isValidForMatrixOrVector() const { 206cb93a386Sopenharmony_ci switch (this->kind()) { 207cb93a386Sopenharmony_ci case Token::Kind::TK_PLUS: 208cb93a386Sopenharmony_ci case Token::Kind::TK_MINUS: 209cb93a386Sopenharmony_ci case Token::Kind::TK_STAR: 210cb93a386Sopenharmony_ci case Token::Kind::TK_SLASH: 211cb93a386Sopenharmony_ci case Token::Kind::TK_PERCENT: 212cb93a386Sopenharmony_ci case Token::Kind::TK_SHL: 213cb93a386Sopenharmony_ci case Token::Kind::TK_SHR: 214cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEAND: 215cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEOR: 216cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEXOR: 217cb93a386Sopenharmony_ci case Token::Kind::TK_PLUSEQ: 218cb93a386Sopenharmony_ci case Token::Kind::TK_MINUSEQ: 219cb93a386Sopenharmony_ci case Token::Kind::TK_STAREQ: 220cb93a386Sopenharmony_ci case Token::Kind::TK_SLASHEQ: 221cb93a386Sopenharmony_ci case Token::Kind::TK_PERCENTEQ: 222cb93a386Sopenharmony_ci case Token::Kind::TK_SHLEQ: 223cb93a386Sopenharmony_ci case Token::Kind::TK_SHREQ: 224cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEANDEQ: 225cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEOREQ: 226cb93a386Sopenharmony_ci case Token::Kind::TK_BITWISEXOREQ: 227cb93a386Sopenharmony_ci return true; 228cb93a386Sopenharmony_ci default: 229cb93a386Sopenharmony_ci return false; 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci} 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_cibool Operator::isMatrixMultiply(const Type& left, const Type& right) { 234cb93a386Sopenharmony_ci if (this->kind() != Token::Kind::TK_STAR && this->kind() != Token::Kind::TK_STAREQ) { 235cb93a386Sopenharmony_ci return false; 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci if (left.isMatrix()) { 238cb93a386Sopenharmony_ci return right.isMatrix() || right.isVector(); 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci return left.isVector() && right.isMatrix(); 241cb93a386Sopenharmony_ci} 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci/** 244cb93a386Sopenharmony_ci * Determines the operand and result types of a binary expression. Returns true if the expression is 245cb93a386Sopenharmony_ci * legal, false otherwise. If false, the values of the out parameters are undefined. 246cb93a386Sopenharmony_ci */ 247cb93a386Sopenharmony_cibool Operator::determineBinaryType(const Context& context, 248cb93a386Sopenharmony_ci const Type& left, 249cb93a386Sopenharmony_ci const Type& right, 250cb93a386Sopenharmony_ci const Type** outLeftType, 251cb93a386Sopenharmony_ci const Type** outRightType, 252cb93a386Sopenharmony_ci const Type** outResultType) { 253cb93a386Sopenharmony_ci const bool allowNarrowing = context.fConfig->fSettings.fAllowNarrowingConversions; 254cb93a386Sopenharmony_ci switch (this->kind()) { 255cb93a386Sopenharmony_ci case Token::Kind::TK_EQ: // left = right 256cb93a386Sopenharmony_ci *outLeftType = &left; 257cb93a386Sopenharmony_ci *outRightType = &left; 258cb93a386Sopenharmony_ci *outResultType = &left; 259cb93a386Sopenharmony_ci return right.canCoerceTo(left, allowNarrowing); 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci case Token::Kind::TK_EQEQ: // left == right 262cb93a386Sopenharmony_ci case Token::Kind::TK_NEQ: { // left != right 263cb93a386Sopenharmony_ci CoercionCost rightToLeft = right.coercionCost(left), 264cb93a386Sopenharmony_ci leftToRight = left.coercionCost(right); 265cb93a386Sopenharmony_ci if (rightToLeft < leftToRight) { 266cb93a386Sopenharmony_ci if (rightToLeft.isPossible(allowNarrowing)) { 267cb93a386Sopenharmony_ci *outLeftType = &left; 268cb93a386Sopenharmony_ci *outRightType = &left; 269cb93a386Sopenharmony_ci *outResultType = context.fTypes.fBool.get(); 270cb93a386Sopenharmony_ci return true; 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci } else { 273cb93a386Sopenharmony_ci if (leftToRight.isPossible(allowNarrowing)) { 274cb93a386Sopenharmony_ci *outLeftType = &right; 275cb93a386Sopenharmony_ci *outRightType = &right; 276cb93a386Sopenharmony_ci *outResultType = context.fTypes.fBool.get(); 277cb93a386Sopenharmony_ci return true; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci return false; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci case Token::Kind::TK_LOGICALOR: // left || right 283cb93a386Sopenharmony_ci case Token::Kind::TK_LOGICALAND: // left && right 284cb93a386Sopenharmony_ci case Token::Kind::TK_LOGICALXOR: // left ^^ right 285cb93a386Sopenharmony_ci *outLeftType = context.fTypes.fBool.get(); 286cb93a386Sopenharmony_ci *outRightType = context.fTypes.fBool.get(); 287cb93a386Sopenharmony_ci *outResultType = context.fTypes.fBool.get(); 288cb93a386Sopenharmony_ci return left.canCoerceTo(*context.fTypes.fBool, allowNarrowing) && 289cb93a386Sopenharmony_ci right.canCoerceTo(*context.fTypes.fBool, allowNarrowing); 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ci case Token::Kind::TK_COMMA: // left, right 292cb93a386Sopenharmony_ci *outLeftType = &left; 293cb93a386Sopenharmony_ci *outRightType = &right; 294cb93a386Sopenharmony_ci *outResultType = &right; 295cb93a386Sopenharmony_ci return true; 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci default: 298cb93a386Sopenharmony_ci break; 299cb93a386Sopenharmony_ci } 300cb93a386Sopenharmony_ci 301cb93a386Sopenharmony_ci // Boolean types only support the operators listed above (, = == != || && ^^). 302cb93a386Sopenharmony_ci // If we've gotten this far with a boolean, we have an unsupported operator. 303cb93a386Sopenharmony_ci const Type& leftComponentType = left.componentType(); 304cb93a386Sopenharmony_ci const Type& rightComponentType = right.componentType(); 305cb93a386Sopenharmony_ci if (leftComponentType.isBoolean() || rightComponentType.isBoolean()) { 306cb93a386Sopenharmony_ci return false; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci bool isAssignment = this->isAssignment(); 310cb93a386Sopenharmony_ci if (this->isMatrixMultiply(left, right)) { // left * right 311cb93a386Sopenharmony_ci // Determine final component type. 312cb93a386Sopenharmony_ci if (!this->determineBinaryType(context, left.componentType(), right.componentType(), 313cb93a386Sopenharmony_ci outLeftType, outRightType, outResultType)) { 314cb93a386Sopenharmony_ci return false; 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci // Convert component type to compound. 317cb93a386Sopenharmony_ci *outLeftType = &(*outResultType)->toCompound(context, left.columns(), left.rows()); 318cb93a386Sopenharmony_ci *outRightType = &(*outResultType)->toCompound(context, right.columns(), right.rows()); 319cb93a386Sopenharmony_ci int leftColumns = left.columns(), leftRows = left.rows(); 320cb93a386Sopenharmony_ci int rightColumns = right.columns(), rightRows = right.rows(); 321cb93a386Sopenharmony_ci if (right.isVector()) { 322cb93a386Sopenharmony_ci // `matrix * vector` treats the vector as a column vector; we need to transpose it. 323cb93a386Sopenharmony_ci std::swap(rightColumns, rightRows); 324cb93a386Sopenharmony_ci SkASSERT(rightColumns == 1); 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci if (rightColumns > 1) { 327cb93a386Sopenharmony_ci *outResultType = &(*outResultType)->toCompound(context, rightColumns, leftRows); 328cb93a386Sopenharmony_ci } else { 329cb93a386Sopenharmony_ci // The result was a column vector. Transpose it back to a row. 330cb93a386Sopenharmony_ci *outResultType = &(*outResultType)->toCompound(context, leftRows, rightColumns); 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci if (isAssignment && ((*outResultType)->columns() != leftColumns || 333cb93a386Sopenharmony_ci (*outResultType)->rows() != leftRows)) { 334cb93a386Sopenharmony_ci return false; 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci return leftColumns == rightRows; 337cb93a386Sopenharmony_ci } 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_ci bool leftIsVectorOrMatrix = left.isVector() || left.isMatrix(); 340cb93a386Sopenharmony_ci bool validMatrixOrVectorOp = this->isValidForMatrixOrVector(); 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci if (leftIsVectorOrMatrix && validMatrixOrVectorOp && right.isScalar()) { 343cb93a386Sopenharmony_ci // Determine final component type. 344cb93a386Sopenharmony_ci if (!this->determineBinaryType(context, left.componentType(), right, 345cb93a386Sopenharmony_ci outLeftType, outRightType, outResultType)) { 346cb93a386Sopenharmony_ci return false; 347cb93a386Sopenharmony_ci } 348cb93a386Sopenharmony_ci // Convert component type to compound. 349cb93a386Sopenharmony_ci *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows()); 350cb93a386Sopenharmony_ci if (!this->isLogical()) { 351cb93a386Sopenharmony_ci *outResultType = &(*outResultType)->toCompound(context, left.columns(), left.rows()); 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci return true; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci bool rightIsVectorOrMatrix = right.isVector() || right.isMatrix(); 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci if (!isAssignment && rightIsVectorOrMatrix && validMatrixOrVectorOp && left.isScalar()) { 359cb93a386Sopenharmony_ci // Determine final component type. 360cb93a386Sopenharmony_ci if (!this->determineBinaryType(context, left, right.componentType(), 361cb93a386Sopenharmony_ci outLeftType, outRightType, outResultType)) { 362cb93a386Sopenharmony_ci return false; 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci // Convert component type to compound. 365cb93a386Sopenharmony_ci *outRightType = &(*outRightType)->toCompound(context, right.columns(), right.rows()); 366cb93a386Sopenharmony_ci if (!this->isLogical()) { 367cb93a386Sopenharmony_ci *outResultType = &(*outResultType)->toCompound(context, right.columns(), right.rows()); 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci return true; 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci CoercionCost rightToLeftCost = right.coercionCost(left); 373cb93a386Sopenharmony_ci CoercionCost leftToRightCost = isAssignment ? CoercionCost::Impossible() 374cb93a386Sopenharmony_ci : left.coercionCost(right); 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci if ((left.isScalar() && right.isScalar()) || (leftIsVectorOrMatrix && validMatrixOrVectorOp)) { 377cb93a386Sopenharmony_ci if (this->isOnlyValidForIntegralTypes()) { 378cb93a386Sopenharmony_ci if (!leftComponentType.isInteger() || !rightComponentType.isInteger()) { 379cb93a386Sopenharmony_ci return false; 380cb93a386Sopenharmony_ci } 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci if (rightToLeftCost.isPossible(allowNarrowing) && rightToLeftCost < leftToRightCost) { 383cb93a386Sopenharmony_ci // Right-to-Left conversion is possible and cheaper 384cb93a386Sopenharmony_ci *outLeftType = &left; 385cb93a386Sopenharmony_ci *outRightType = &left; 386cb93a386Sopenharmony_ci *outResultType = &left; 387cb93a386Sopenharmony_ci } else if (leftToRightCost.isPossible(allowNarrowing)) { 388cb93a386Sopenharmony_ci // Left-to-Right conversion is possible (and at least as cheap as Right-to-Left) 389cb93a386Sopenharmony_ci *outLeftType = &right; 390cb93a386Sopenharmony_ci *outRightType = &right; 391cb93a386Sopenharmony_ci *outResultType = &right; 392cb93a386Sopenharmony_ci } else { 393cb93a386Sopenharmony_ci return false; 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci if (this->isLogical()) { 396cb93a386Sopenharmony_ci *outResultType = context.fTypes.fBool.get(); 397cb93a386Sopenharmony_ci } 398cb93a386Sopenharmony_ci return true; 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci return false; 401cb93a386Sopenharmony_ci} 402cb93a386Sopenharmony_ci 403cb93a386Sopenharmony_ci} // namespace SkSL 404