Flutter Engine
The Flutter Engine
SkSLPrefixExpression.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
9
25
26#include <cstddef>
27#include <optional>
28
29namespace SkSL {
30
31static ExpressionArray negate_operands(const Context& context,
32 Position pos,
33 const ExpressionArray& operands);
34
35static double negate_value(double value) {
36 return -value;
37}
38
39static double bitwise_not_value(double value) {
40 return ~static_cast<SKSL_INT>(value);
41}
42
43static std::unique_ptr<Expression> apply_to_elements(const Context& context,
45 const Expression& expr,
46 double (*fn)(double)) {
47 const Type& elementType = expr.type().componentType();
48
49 double values[16];
50 size_t numSlots = expr.type().slotCount();
51 if (numSlots > std::size(values)) {
52 // The expression has more slots than we expected.
53 return nullptr;
54 }
55
56 for (size_t index = 0; index < numSlots; ++index) {
57 if (std::optional<double> slotValue = expr.getConstantValue(index)) {
58 values[index] = fn(*slotValue);
59 if (elementType.checkForOutOfRangeLiteral(context, values[index], pos)) {
60 // We can't simplify the expression if the new value is out-of-range for the type.
61 return nullptr;
62 }
63 } else {
64 // There's a non-constant element; we can't simplify this expression.
65 return nullptr;
66 }
67 }
68 return ConstructorCompound::MakeFromConstants(context, pos, expr.type(), values);
69}
70
71static std::unique_ptr<Expression> simplify_negation(const Context& context,
73 const Expression& originalExpr) {
75 switch (value->kind()) {
77 case Expression::Kind::kConstructorSplat:
78 case Expression::Kind::kConstructorCompound: {
79 // Convert `-vecN(literal, ...)` into `vecN(-literal, ...)`.
80 if (std::unique_ptr<Expression> expr = apply_to_elements(context, pos, *value,
81 negate_value)) {
82 return expr;
83 }
84 break;
85 }
86 case Expression::Kind::kPrefix: {
87 // Convert `-(-expression)` into `expression`.
89 if (prefix.getOperator().kind() == Operator::Kind::MINUS) {
90 return prefix.operand()->clone(pos);
91 }
92 break;
93 }
94 case Expression::Kind::kConstructorArray:
95 // Convert `-array[N](literal, ...)` into `array[N](-literal, ...)`.
97 const ConstructorArray& ctor = value->as<ConstructorArray>();
98 return ConstructorArray::Make(context, pos, ctor.type(),
99 negate_operands(context, pos, ctor.arguments()));
100 }
101 break;
102
103 case Expression::Kind::kConstructorDiagonalMatrix:
104 // Convert `-matrix(literal)` into `matrix(-literal)`.
107 if (std::unique_ptr<Expression> simplified = simplify_negation(context,
108 pos,
109 *ctor.argument())) {
110 return ConstructorDiagonalMatrix::Make(context, pos, ctor.type(),
111 std::move(simplified));
112 }
113 }
114 break;
115
116 default:
117 break;
118 }
119 return nullptr;
120}
121
124 const ExpressionArray& array) {
125 ExpressionArray replacement;
126 replacement.reserve_exact(array.size());
127 for (const std::unique_ptr<Expression>& expr : array) {
128 // The logic below is very similar to `negate_operand`, but with different ownership rules.
129 if (std::unique_ptr<Expression> simplified = simplify_negation(context, pos, *expr)) {
130 replacement.push_back(std::move(simplified));
131 } else {
132 replacement.push_back(std::make_unique<PrefixExpression>(pos, Operator::Kind::MINUS,
133 expr->clone()));
134 }
135 }
136 return replacement;
137}
138
139static std::unique_ptr<Expression> negate_operand(const Context& context,
141 std::unique_ptr<Expression> value) {
142 // Attempt to simplify this negation (e.g. eliminate double negation, literal values)
143 if (std::unique_ptr<Expression> simplified = simplify_negation(context, pos, *value)) {
144 return simplified;
145 }
146
147 // No simplified form; convert expression to Prefix(MINUS, expression).
148 return std::make_unique<PrefixExpression>(pos, Operator::Kind::MINUS, std::move(value));
149}
150
151static std::unique_ptr<Expression> logical_not_operand(const Context& context,
153 std::unique_ptr<Expression> operand) {
155 switch (value->kind()) {
157 // Convert !boolLiteral(true) to boolLiteral(false).
158 SkASSERT(value->type().isBoolean());
159 const Literal& b = value->as<Literal>();
160 return Literal::MakeBool(pos, !b.boolValue(), &operand->type());
161 }
162 case Expression::Kind::kPrefix: {
163 // Convert `!(!expression)` into `expression`.
164 PrefixExpression& prefix = operand->as<PrefixExpression>();
165 if (prefix.getOperator().kind() == Operator::Kind::LOGICALNOT) {
166 prefix.operand()->fPosition = pos;
167 return std::move(prefix.operand());
168 }
169 break;
170 }
171 case Expression::Kind::kBinary: {
172 BinaryExpression& binary = operand->as<BinaryExpression>();
173 std::optional<Operator> replacement;
174 switch (binary.getOperator().kind()) {
175 case OperatorKind::EQEQ: replacement = OperatorKind::NEQ; break;
176 case OperatorKind::NEQ: replacement = OperatorKind::EQEQ; break;
177 case OperatorKind::LT: replacement = OperatorKind::GTEQ; break;
178 case OperatorKind::LTEQ: replacement = OperatorKind::GT; break;
179 case OperatorKind::GT: replacement = OperatorKind::LTEQ; break;
180 case OperatorKind::GTEQ: replacement = OperatorKind::LT; break;
181 default: break;
182 }
183 if (replacement.has_value()) {
184 return BinaryExpression::Make(context, pos, std::move(binary.left()),
185 *replacement, std::move(binary.right()),
186 &binary.type());
187 }
188 break;
189 }
190 default:
191 break;
192 }
193
194 // No simplified form; convert expression to Prefix(LOGICALNOT, expression).
195 return std::make_unique<PrefixExpression>(pos, Operator::Kind::LOGICALNOT, std::move(operand));
196}
197
198static std::unique_ptr<Expression> bitwise_not_operand(const Context& context,
200 std::unique_ptr<Expression> operand) {
201 SkASSERT(operand->type().componentType().isInteger());
202
204
205 switch (value->kind()) {
207 case Expression::Kind::kConstructorSplat:
208 case Expression::Kind::kConstructorCompound: {
209 // Convert ~vecN(1, 2, ...) to vecN(~1, ~2, ...).
210 if (std::unique_ptr<Expression> expr = apply_to_elements(context, pos, *value,
212 return expr;
213 }
214 break;
215 }
216 case Expression::Kind::kPrefix: {
217 // Convert `~(~expression)` into `expression`.
218 PrefixExpression& prefix = operand->as<PrefixExpression>();
219 if (prefix.getOperator().kind() == Operator::Kind::BITWISENOT) {
220 prefix.operand()->fPosition = pos;
221 return std::move(prefix.operand());
222 }
223 break;
224 }
225 default:
226 break;
227 }
228
229 // No simplified form; convert expression to Prefix(BITWISENOT, expression).
230 return std::make_unique<PrefixExpression>(pos, Operator::Kind::BITWISENOT, std::move(operand));
231}
232
233std::unique_ptr<Expression> PrefixExpression::Convert(const Context& context,
235 Operator op,
236 std::unique_ptr<Expression> base) {
237 const Type& baseType = base->type();
238 switch (op.kind()) {
240 if (baseType.isArray() || !baseType.componentType().isNumber()) {
241 context.fErrors->error(pos,
242 "'+' cannot operate on '" + baseType.displayName() + "'");
243 return nullptr;
244 }
245 break;
246
247 case Operator::Kind::MINUS:
248 if (baseType.isArray() || !baseType.componentType().isNumber()) {
249 context.fErrors->error(pos,
250 "'-' cannot operate on '" + baseType.displayName() + "'");
251 return nullptr;
252 }
253 break;
254
255 case Operator::Kind::PLUSPLUS:
256 case Operator::Kind::MINUSMINUS:
257 if (baseType.isArray() || !baseType.componentType().isNumber()) {
258 context.fErrors->error(pos,
259 "'" + std::string(op.tightOperatorName()) +
260 "' cannot operate on '" + baseType.displayName() + "'");
261 return nullptr;
262 }
264 context.fErrors)) {
265 return nullptr;
266 }
267 break;
268
269 case Operator::Kind::LOGICALNOT:
270 if (!baseType.isBoolean()) {
271 context.fErrors->error(pos,
272 "'" + std::string(op.tightOperatorName()) +
273 "' cannot operate on '" + baseType.displayName() + "'");
274 return nullptr;
275 }
276 break;
277
278 case Operator::Kind::BITWISENOT:
279 if (context.fConfig->strictES2Mode()) {
280 // GLSL ES 1.00, Section 5.1
281 context.fErrors->error(
282 pos,
283 "operator '" + std::string(op.tightOperatorName()) + "' is not allowed");
284 return nullptr;
285 }
286 if (baseType.isArray() || !baseType.componentType().isInteger()) {
287 context.fErrors->error(pos,
288 "'" + std::string(op.tightOperatorName()) +
289 "' cannot operate on '" + baseType.displayName() + "'");
290 return nullptr;
291 }
292 break;
293
294 default:
295 SK_ABORT("unsupported prefix operator");
296 }
297
298 std::unique_ptr<Expression> result = PrefixExpression::Make(context, pos, op, std::move(base));
299 SkASSERT(result->fPosition == pos);
300 return result;
301}
302
303std::unique_ptr<Expression> PrefixExpression::Make(const Context& context,
305 Operator op,
306 std::unique_ptr<Expression> base) {
307 const Type& baseType = base->type();
308 switch (op.kind()) {
310 SkASSERT(!baseType.isArray());
311 SkASSERT(baseType.componentType().isNumber());
312 base->fPosition = pos;
313 return base;
314
315 case Operator::Kind::MINUS:
316 SkASSERT(!baseType.isArray());
317 SkASSERT(baseType.componentType().isNumber());
318 return negate_operand(context, pos, std::move(base));
319
320 case Operator::Kind::LOGICALNOT:
321 SkASSERT(baseType.isBoolean());
322 return logical_not_operand(context, pos, std::move(base));
323
324 case Operator::Kind::PLUSPLUS:
325 case Operator::Kind::MINUSMINUS:
326 SkASSERT(!baseType.isArray());
327 SkASSERT(baseType.componentType().isNumber());
329 break;
330
331 case Operator::Kind::BITWISENOT:
332 SkASSERT(!context.fConfig->strictES2Mode());
333 SkASSERT(!baseType.isArray());
334 SkASSERT(baseType.componentType().isInteger());
335 if (baseType.isLiteral()) {
336 // The expression `~123` is no longer a literal; coerce to the actual type.
337 base = baseType.scalarTypeForLiteral().coerceExpression(std::move(base), context);
338 SkASSERT(base);
339 }
340 return bitwise_not_operand(context, pos, std::move(base));
341
342 default:
343 SkDEBUGFAILF("unsupported prefix operator: %s", op.operatorName());
344 }
345
346 return std::make_unique<PrefixExpression>(pos, op, std::move(base));
347}
348
349std::string PrefixExpression::description(OperatorPrecedence parentPrecedence) const {
350 bool needsParens = (OperatorPrecedence::kPrefix >= parentPrecedence);
351 return std::string(needsParens ? "(" : "") +
352 std::string(this->getOperator().tightOperatorName()) +
353 this->operand()->description(OperatorPrecedence::kPrefix) +
354 std::string(needsParens ? ")" : "");
355}
356
357} // namespace SkSL
SkPoint pos
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkDEBUGFAILF(fmt,...)
Definition: SkAssert.h:119
#define SkASSERT(cond)
Definition: SkAssert.h:116
static std::unique_ptr< Expression > Make(const Context &context, Position pos, std::unique_ptr< Expression > left, Operator op, std::unique_ptr< Expression > right)
static const Expression * GetConstantValueForVariable(const Expression &value)
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, ExpressionArray args)
static std::unique_ptr< Expression > MakeFromConstants(const Context &context, Position pos, const Type &type, const double values[])
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, std::unique_ptr< Expression > arg)
ErrorReporter * fErrors
Definition: SkSLContext.h:36
ProgramConfig * fConfig
Definition: SkSLContext.h:33
void error(Position position, std::string_view msg)
virtual std::unique_ptr< Expression > clone(Position pos) const =0
const Type & type() const
virtual std::optional< double > getConstantValue(int n) const
std::string description() const final
static std::unique_ptr< Literal > MakeBool(const Context &context, Position pos, bool value)
Definition: SkSLLiteral.h:69
ExpressionArray & arguments()
Kind kind() const
Definition: SkSLOperator.h:85
std::string_view tightOperatorName() const
const char * operatorName() const
static std::unique_ptr< Expression > Make(const Context &context, Position pos, Operator op, std::unique_ptr< Expression > base)
Operator getOperator() const
static std::unique_ptr< Expression > Convert(const Context &context, Position pos, Operator op, std::unique_ptr< Expression > base)
std::unique_ptr< Expression > & operand()
std::unique_ptr< Expression > & argument()
virtual bool isArray() const
Definition: SkSLType.h:532
std::unique_ptr< Expression > coerceExpression(std::unique_ptr< Expression > expr, const Context &context) const
bool isBoolean() const
Definition: SkSLType.h:297
virtual const Type & componentType() const
Definition: SkSLType.h:404
bool isNumber() const
Definition: SkSLType.h:304
virtual bool isLiteral() const
Definition: SkSLType.h:516
virtual size_t slotCount() const
Definition: SkSLType.h:457
virtual const Type & scalarTypeForLiteral() const
Definition: SkSLType.h:520
bool checkForOutOfRangeLiteral(const Context &context, const Expression &expr) const
std::string displayName() const
Definition: SkSLType.h:234
bool isInteger() const
Definition: SkSLType.h:339
int size() const
Definition: SkTArray.h:421
void reserve_exact(int n)
Definition: SkTArray.h:181
static bool b
uint8_t value
GAsyncResult * result
bool IsCompileTimeConstant(const Expression &expr)
bool UpdateVariableRefKind(Expression *expr, VariableRefKind kind, ErrorReporter *errors=nullptr)
bool IsAssignable(Expression &expr, AssignmentInfo *info=nullptr, ErrorReporter *errors=nullptr)
static std::unique_ptr< Expression > negate_operand(const Context &context, Position pos, std::unique_ptr< Expression > value)
static std::unique_ptr< Expression > bitwise_not_operand(const Context &context, Position pos, std::unique_ptr< Expression > operand)
static std::unique_ptr< Expression > simplify_negation(const Context &context, Position pos, const Expression &originalExpr)
static std::unique_ptr< Expression > logical_not_operand(const Context &context, Position pos, std::unique_ptr< Expression > operand)
static ExpressionArray negate_operands(const Context &context, Position pos, const ExpressionArray &operands)
static double negate_value(double value)
OperatorPrecedence
Definition: SkSLOperator.h:57
static double bitwise_not_value(double value)
static std::unique_ptr< Expression > apply_to_elements(const Context &context, Position pos, const Expression &expr, double(*fn)(double))
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259