xref: /third_party/skia/src/sksl/SkSLOperators.cpp (revision cb93a386)
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