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