Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | List of all members
SkSL::Operator Class Reference

#include <SkSLOperator.h>

Public Types

using Kind = OperatorKind
 

Public Member Functions

 Operator (Kind op)
 
Kind kind () const
 
bool isEquality () const
 
OperatorPrecedence getBinaryPrecedence () const
 
const char * operatorName () const
 
std::string_view tightOperatorName () const
 
bool isAssignment () const
 
bool isCompoundAssignment () const
 
Operator removeAssignment () const
 
bool isRelational () const
 
bool isOnlyValidForIntegralTypes () const
 
bool isValidForMatrixOrVector () const
 
bool isAllowedInStrictES2Mode () const
 
bool determineBinaryType (const Context &context, const Type &left, const Type &right, const Type **outLeftType, const Type **outRightType, const Type **outResultType) const
 

Detailed Description

Definition at line 79 of file SkSLOperator.h.

Member Typedef Documentation

◆ Kind

Definition at line 81 of file SkSLOperator.h.

Constructor & Destructor Documentation

◆ Operator()

SkSL::Operator::Operator ( Kind  op)
inline

Definition at line 83 of file SkSLOperator.h.

83: fKind(op) {}

Member Function Documentation

◆ determineBinaryType()

bool SkSL::Operator::determineBinaryType ( const Context context,
const Type left,
const Type right,
const Type **  outLeftType,
const Type **  outRightType,
const Type **  outResultType 
) const

Determines the operand and result types of a binary expression. Returns true if the expression is legal, false otherwise. If false, the values of the out parameters are undefined.

Definition at line 223 of file SkSLOperator.cpp.

228 {
229 const bool allowNarrowing = context.fConfig->fSettings.fAllowNarrowingConversions;
230 switch (this->kind()) {
231 case Kind::EQ: // left = right
232 if (left.isVoid()) {
233 return false;
234 }
235 *outLeftType = &left;
236 *outRightType = &left;
237 *outResultType = &left;
238 return right.canCoerceTo(left, allowNarrowing);
239
240 case Kind::EQEQ: // left == right
241 case Kind::NEQ: { // left != right
242 if (left.isVoid() || left.isOpaque()) {
243 return false;
244 }
245 CoercionCost rightToLeft = right.coercionCost(left),
246 leftToRight = left.coercionCost(right);
247 if (rightToLeft < leftToRight) {
248 if (rightToLeft.isPossible(allowNarrowing)) {
249 *outLeftType = &left;
250 *outRightType = &left;
251 *outResultType = context.fTypes.fBool.get();
252 return true;
253 }
254 } else {
255 if (leftToRight.isPossible(allowNarrowing)) {
256 *outLeftType = &right;
257 *outRightType = &right;
258 *outResultType = context.fTypes.fBool.get();
259 return true;
260 }
261 }
262 return false;
263 }
264 case Kind::LOGICALOR: // left || right
265 case Kind::LOGICALAND: // left && right
266 case Kind::LOGICALXOR: // left ^^ right
267 *outLeftType = context.fTypes.fBool.get();
268 *outRightType = context.fTypes.fBool.get();
269 *outResultType = context.fTypes.fBool.get();
270 return left.canCoerceTo(*context.fTypes.fBool, allowNarrowing) &&
271 right.canCoerceTo(*context.fTypes.fBool, allowNarrowing);
272
273 case Operator::Kind::COMMA: // left, right
274 if (left.isOpaque() || right.isOpaque()) {
275 return false;
276 }
277 *outLeftType = &left;
278 *outRightType = &right;
279 *outResultType = &right;
280 return true;
281
282 default:
283 break;
284 }
285
286 // Boolean types only support the operators listed above (, = == != || && ^^).
287 // If we've gotten this far with a boolean, we have an unsupported operator.
288 const Type& leftComponentType = left.componentType();
289 const Type& rightComponentType = right.componentType();
290 if (leftComponentType.isBoolean() || rightComponentType.isBoolean()) {
291 return false;
292 }
293
294 bool isAssignment = this->isAssignment();
295 if (this->isMatrixMultiply(left, right)) { // left * right
296 // Determine final component type.
297 if (!this->determineBinaryType(context, left.componentType(), right.componentType(),
298 outLeftType, outRightType, outResultType)) {
299 return false;
300 }
301 // Convert component type to compound.
302 *outLeftType = &(*outResultType)->toCompound(context, left.columns(), left.rows());
303 *outRightType = &(*outResultType)->toCompound(context, right.columns(), right.rows());
304 int leftColumns = left.columns(), leftRows = left.rows();
305 int rightColumns = right.columns(), rightRows = right.rows();
306 if (right.isVector()) {
307 // `matrix * vector` treats the vector as a column vector; we need to transpose it.
308 std::swap(rightColumns, rightRows);
309 SkASSERT(rightColumns == 1);
310 }
311 if (rightColumns > 1) {
312 *outResultType = &(*outResultType)->toCompound(context, rightColumns, leftRows);
313 } else {
314 // The result was a column vector. Transpose it back to a row.
315 *outResultType = &(*outResultType)->toCompound(context, leftRows, rightColumns);
316 }
317 if (isAssignment && ((*outResultType)->columns() != leftColumns ||
318 (*outResultType)->rows() != leftRows)) {
319 return false;
320 }
321 return leftColumns == rightRows;
322 }
323
324 bool leftIsVectorOrMatrix = left.isVector() || left.isMatrix();
325 bool validMatrixOrVectorOp = this->isValidForMatrixOrVector();
326
327 if (leftIsVectorOrMatrix && validMatrixOrVectorOp && right.isScalar()) {
328 // Determine final component type.
329 if (!this->determineBinaryType(context, left.componentType(), right,
330 outLeftType, outRightType, outResultType)) {
331 return false;
332 }
333 // Convert component type to compound.
334 *outLeftType = &(*outLeftType)->toCompound(context, left.columns(), left.rows());
335 if (!this->isRelational()) {
336 *outResultType = &(*outResultType)->toCompound(context, left.columns(), left.rows());
337 }
338 return true;
339 }
340
341 bool rightIsVectorOrMatrix = right.isVector() || right.isMatrix();
342
343 if (!isAssignment && rightIsVectorOrMatrix && validMatrixOrVectorOp && left.isScalar()) {
344 // Determine final component type.
345 if (!this->determineBinaryType(context, left, right.componentType(),
346 outLeftType, outRightType, outResultType)) {
347 return false;
348 }
349 // Convert component type to compound.
350 *outRightType = &(*outRightType)->toCompound(context, right.columns(), right.rows());
351 if (!this->isRelational()) {
352 *outResultType = &(*outResultType)->toCompound(context, right.columns(), right.rows());
353 }
354 return true;
355 }
356
357 CoercionCost rightToLeftCost = right.coercionCost(left);
358 CoercionCost leftToRightCost = isAssignment ? CoercionCost::Impossible()
359 : left.coercionCost(right);
360
361 if ((left.isScalar() && right.isScalar()) || (leftIsVectorOrMatrix && validMatrixOrVectorOp)) {
362 if (this->isOnlyValidForIntegralTypes()) {
363 if (!leftComponentType.isInteger() || !rightComponentType.isInteger()) {
364 return false;
365 }
366 }
367 if (rightToLeftCost.isPossible(allowNarrowing) && rightToLeftCost < leftToRightCost) {
368 // Right-to-Left conversion is possible and cheaper
369 *outLeftType = &left;
370 *outRightType = &left;
371 *outResultType = &left;
372 } else if (leftToRightCost.isPossible(allowNarrowing)) {
373 // Left-to-Right conversion is possible (and at least as cheap as Right-to-Left)
374 *outLeftType = &right;
375 *outRightType = &right;
376 *outResultType = &right;
377 } else {
378 return false;
379 }
380 if (this->isRelational()) {
381 *outResultType = context.fTypes.fBool.get();
382 }
383 return true;
384 }
385 return false;
386}
#define COMMA
#define SkASSERT(cond)
Definition: SkAssert.h:116
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
Kind kind() const
Definition: SkSLOperator.h:85
bool isRelational() const
bool isOnlyValidForIntegralTypes() const
bool determineBinaryType(const Context &context, const Type &left, const Type &right, const Type **outLeftType, const Type **outRightType, const Type **outResultType) const
bool isValidForMatrixOrVector() const
bool isAssignment() const
static CoercionCost Impossible()
Definition: SkSLType.h:42

◆ getBinaryPrecedence()

OperatorPrecedence SkSL::Operator::getBinaryPrecedence ( ) const

Definition at line 21 of file SkSLOperator.cpp.

21 {
22 switch (this->kind()) {
23 case Kind::STAR: // fall through
24 case Kind::SLASH: // fall through
25 case Kind::PERCENT: return OperatorPrecedence::kMultiplicative;
26 case Kind::PLUS: // fall through
27 case Kind::MINUS: return OperatorPrecedence::kAdditive;
28 case Kind::SHL: // fall through
29 case Kind::SHR: return OperatorPrecedence::kShift;
30 case Kind::LT: // fall through
31 case Kind::GT: // fall through
32 case Kind::LTEQ: // fall through
33 case Kind::GTEQ: return OperatorPrecedence::kRelational;
34 case Kind::EQEQ: // fall through
35 case Kind::NEQ: return OperatorPrecedence::kEquality;
36 case Kind::BITWISEAND: return OperatorPrecedence::kBitwiseAnd;
37 case Kind::BITWISEXOR: return OperatorPrecedence::kBitwiseXor;
38 case Kind::BITWISEOR: return OperatorPrecedence::kBitwiseOr;
39 case Kind::LOGICALAND: return OperatorPrecedence::kLogicalAnd;
40 case Kind::LOGICALXOR: return OperatorPrecedence::kLogicalXor;
41 case Kind::LOGICALOR: return OperatorPrecedence::kLogicalOr;
42 case Kind::EQ: // fall through
43 case Kind::PLUSEQ: // fall through
44 case Kind::MINUSEQ: // fall through
45 case Kind::STAREQ: // fall through
46 case Kind::SLASHEQ: // fall through
47 case Kind::PERCENTEQ: // fall through
48 case Kind::SHLEQ: // fall through
49 case Kind::SHREQ: // fall through
50 case Kind::BITWISEANDEQ: // fall through
51 case Kind::BITWISEXOREQ: // fall through
52 case Kind::BITWISEOREQ: return OperatorPrecedence::kAssignment;
54 default: SK_ABORT("unsupported binary operator");
55 }
56}
#define SK_ABORT(message,...)
Definition: SkAssert.h:70

◆ isAllowedInStrictES2Mode()

bool SkSL::Operator::isAllowedInStrictES2Mode ( ) const
inline

Definition at line 133 of file SkSLOperator.h.

133 {
134 return !this->isOnlyValidForIntegralTypes();
135 }

◆ isAssignment()

bool SkSL::Operator::isAssignment ( ) const

Definition at line 110 of file SkSLOperator.cpp.

110 {
111 switch (this->kind()) {
112 case Kind::EQ: // fall through
113 case Kind::PLUSEQ: // fall through
114 case Kind::MINUSEQ: // fall through
115 case Kind::STAREQ: // fall through
116 case Kind::SLASHEQ: // fall through
117 case Kind::PERCENTEQ: // fall through
118 case Kind::SHLEQ: // fall through
119 case Kind::SHREQ: // fall through
120 case Kind::BITWISEOREQ: // fall through
121 case Kind::BITWISEXOREQ: // fall through
122 case Kind::BITWISEANDEQ:
123 return true;
124 default:
125 return false;
126 }
127}

◆ isCompoundAssignment()

bool SkSL::Operator::isCompoundAssignment ( ) const

Definition at line 129 of file SkSLOperator.cpp.

129 {
130 return this->isAssignment() && this->kind() != Kind::EQ;
131}

◆ isEquality()

bool SkSL::Operator::isEquality ( ) const
inline

Definition at line 87 of file SkSLOperator.h.

87 {
88 return fKind == Kind::EQEQ || fKind == Kind::NEQ;
89 }

◆ isOnlyValidForIntegralTypes()

bool SkSL::Operator::isOnlyValidForIntegralTypes ( ) const

Defines the set of operators which are only valid on integral types: << <<= >> >>= & &= | |= ^ ^= % %=

Definition at line 161 of file SkSLOperator.cpp.

161 {
162 switch (this->kind()) {
163 case Kind::SHL:
164 case Kind::SHR:
165 case Kind::BITWISEAND:
166 case Kind::BITWISEOR:
167 case Kind::BITWISEXOR:
168 case Kind::PERCENT:
169 case Kind::SHLEQ:
170 case Kind::SHREQ:
171 case Kind::BITWISEANDEQ:
172 case Kind::BITWISEOREQ:
173 case Kind::BITWISEXOREQ:
174 case Kind::PERCENTEQ:
175 return true;
176 default:
177 return false;
178 }
179}

◆ isRelational()

bool SkSL::Operator::isRelational ( ) const

Defines the set of relational (comparison) operators: < <= > >=

Definition at line 149 of file SkSLOperator.cpp.

149 {
150 switch (this->kind()) {
151 case Kind::LT:
152 case Kind::GT:
153 case Kind::LTEQ:
154 case Kind::GTEQ:
155 return true;
156 default:
157 return false;
158 }
159}

◆ isValidForMatrixOrVector()

bool SkSL::Operator::isValidForMatrixOrVector ( ) const

Defines the set of operators which perform vector/matrix math.

  • += - -= * *= / /= % %= << <<= >> >>= & &= | |= ^ ^=

Definition at line 181 of file SkSLOperator.cpp.

181 {
182 switch (this->kind()) {
183 case Kind::PLUS:
184 case Kind::MINUS:
185 case Kind::STAR:
186 case Kind::SLASH:
187 case Kind::PERCENT:
188 case Kind::SHL:
189 case Kind::SHR:
190 case Kind::BITWISEAND:
191 case Kind::BITWISEOR:
192 case Kind::BITWISEXOR:
193 case Kind::PLUSEQ:
194 case Kind::MINUSEQ:
195 case Kind::STAREQ:
196 case Kind::SLASHEQ:
197 case Kind::PERCENTEQ:
198 case Kind::SHLEQ:
199 case Kind::SHREQ:
200 case Kind::BITWISEANDEQ:
201 case Kind::BITWISEOREQ:
202 case Kind::BITWISEXOREQ:
203 return true;
204 default:
205 return false;
206 }
207}

◆ kind()

Kind SkSL::Operator::kind ( ) const
inline

Definition at line 85 of file SkSLOperator.h.

85{ return fKind; }

◆ operatorName()

const char * SkSL::Operator::operatorName ( ) const

Definition at line 58 of file SkSLOperator.cpp.

58 {
59 switch (this->kind()) {
60 case Kind::PLUS: return " + ";
61 case Kind::MINUS: return " - ";
62 case Kind::STAR: return " * ";
63 case Kind::SLASH: return " / ";
64 case Kind::PERCENT: return " % ";
65 case Kind::SHL: return " << ";
66 case Kind::SHR: return " >> ";
67 case Kind::LOGICALNOT: return "!";
68 case Kind::LOGICALAND: return " && ";
69 case Kind::LOGICALOR: return " || ";
70 case Kind::LOGICALXOR: return " ^^ ";
71 case Kind::BITWISENOT: return "~";
72 case Kind::BITWISEAND: return " & ";
73 case Kind::BITWISEOR: return " | ";
74 case Kind::BITWISEXOR: return " ^ ";
75 case Kind::EQ: return " = ";
76 case Kind::EQEQ: return " == ";
77 case Kind::NEQ: return " != ";
78 case Kind::LT: return " < ";
79 case Kind::GT: return " > ";
80 case Kind::LTEQ: return " <= ";
81 case Kind::GTEQ: return " >= ";
82 case Kind::PLUSEQ: return " += ";
83 case Kind::MINUSEQ: return " -= ";
84 case Kind::STAREQ: return " *= ";
85 case Kind::SLASHEQ: return " /= ";
86 case Kind::PERCENTEQ: return " %= ";
87 case Kind::SHLEQ: return " <<= ";
88 case Kind::SHREQ: return " >>= ";
89 case Kind::BITWISEANDEQ: return " &= ";
90 case Kind::BITWISEOREQ: return " |= ";
91 case Kind::BITWISEXOREQ: return " ^= ";
92 case Kind::PLUSPLUS: return "++";
93 case Kind::MINUSMINUS: return "--";
94 case Kind::COMMA: return ", ";
95 default: SkUNREACHABLE;
96 }
97}
#define SkUNREACHABLE
Definition: SkAssert.h:135

◆ removeAssignment()

Operator SkSL::Operator::removeAssignment ( ) const

Definition at line 133 of file SkSLOperator.cpp.

133 {
134 switch (this->kind()) {
135 case Kind::PLUSEQ: return Kind::PLUS;
136 case Kind::MINUSEQ: return Kind::MINUS;
137 case Kind::STAREQ: return Kind::STAR;
138 case Kind::SLASHEQ: return Kind::SLASH;
139 case Kind::PERCENTEQ: return Kind::PERCENT;
140 case Kind::SHLEQ: return Kind::SHL;
141 case Kind::SHREQ: return Kind::SHR;
142 case Kind::BITWISEOREQ: return Kind::BITWISEOR;
143 case Kind::BITWISEXOREQ: return Kind::BITWISEXOR;
144 case Kind::BITWISEANDEQ: return Kind::BITWISEAND;
145 default: return *this;
146 }
147}

◆ tightOperatorName()

std::string_view SkSL::Operator::tightOperatorName ( ) const

Definition at line 99 of file SkSLOperator.cpp.

99 {
100 std::string_view name = this->operatorName();
101 if (skstd::starts_with(name, ' ')) {
102 name.remove_prefix(1);
103 }
104 if (skstd::ends_with(name, ' ')) {
105 name.remove_suffix(1);
106 }
107 return name;
108}
const char * operatorName() const
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
constexpr bool starts_with(std::string_view str, std::string_view prefix)
Definition: SkStringView.h:17
constexpr bool ends_with(std::string_view str, std::string_view suffix)
Definition: SkStringView.h:28

The documentation for this class was generated from the following files: