Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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()) {
76 case Expression::Kind::kLiteral:
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`.
88 const PrefixExpression& prefix = value->as<PrefixExpression>();
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()) {
156 case Expression::Kind::kLiteral: {
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()) {
206 case Expression::Kind::kLiteral:
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()) {
239 case Operator::Kind::PLUS:
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.isNumber()) {
258 context.fErrors->error(pos,
259 "'" + std::string(op.tightOperatorName()) +
260 "' cannot operate on '" + baseType.displayName() + "'");
261 return nullptr;
262 }
263 if (!Analysis::UpdateVariableRefKind(base.get(), VariableReference::RefKind::kReadWrite,
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()) {
309 case Operator::Kind::PLUS:
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.isNumber());
328 break;
329
330 case Operator::Kind::BITWISENOT:
331 SkASSERT(!context.fConfig->strictES2Mode());
332 SkASSERT(!baseType.isArray());
333 SkASSERT(baseType.componentType().isInteger());
334 if (baseType.isLiteral()) {
335 // The expression `~123` is no longer a literal; coerce to the actual type.
336 base = baseType.scalarTypeForLiteral().coerceExpression(std::move(base), context);
337 SkASSERT(base);
338 }
339 return bitwise_not_operand(context, pos, std::move(base));
340
341 default:
342 SkDEBUGFAILF("unsupported prefix operator: %s", op.operatorName());
343 }
344
345 return std::make_unique<PrefixExpression>(pos, op, std::move(base));
346}
347
348std::string PrefixExpression::description(OperatorPrecedence parentPrecedence) const {
349 bool needsParens = (OperatorPrecedence::kPrefix >= parentPrecedence);
350 return std::string(needsParens ? "(" : "") +
351 std::string(this->getOperator().tightOperatorName()) +
352 this->operand()->description(OperatorPrecedence::kPrefix) +
353 std::string(needsParens ? ")" : "");
354}
355
356} // 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 const Type & type() const
virtual std::unique_ptr< Expression > clone(Position pos) const =0
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
Kind kind() const
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)
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:416
void reserve_exact(int n)
Definition SkTArray.h:176
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
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))