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
8 #include "src/sksl/ir/SkSLPrefixExpression.h"
9
10 #include "include/core/SkTypes.h"
11 #include "src/sksl/SkSLAnalysis.h"
12 #include "src/sksl/SkSLConstantFolder.h"
13 #include "src/sksl/SkSLContext.h"
14 #include "src/sksl/SkSLDefines.h"
15 #include "src/sksl/SkSLErrorReporter.h"
16 #include "src/sksl/SkSLOperator.h"
17 #include "src/sksl/SkSLProgramSettings.h"
18 #include "src/sksl/ir/SkSLBinaryExpression.h"
19 #include "src/sksl/ir/SkSLConstructorArray.h"
20 #include "src/sksl/ir/SkSLConstructorCompound.h"
21 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
22 #include "src/sksl/ir/SkSLLiteral.h"
23 #include "src/sksl/ir/SkSLType.h"
24 #include "src/sksl/ir/SkSLVariableReference.h"
25
26 #include <cstddef>
27 #include <optional>
28
29 namespace SkSL {
30
31 static ExpressionArray negate_operands(const Context& context,
32 Position pos,
33 const ExpressionArray& operands);
34
negate_value(double value)35 static double negate_value(double value) {
36 return -value;
37 }
38
bitwise_not_value(double value)39 static double bitwise_not_value(double value) {
40 return ~static_cast<SKSL_INT>(value);
41 }
42
apply_to_elements(const Context & context,Position pos,const Expression & expr,double (* fn)(double))43 static std::unique_ptr<Expression> apply_to_elements(const Context& context,
44 Position pos,
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
simplify_negation(const Context & context,Position pos,const Expression & originalExpr)71 static std::unique_ptr<Expression> simplify_negation(const Context& context,
72 Position pos,
73 const Expression& originalExpr) {
74 const Expression* value = ConstantFolder::GetConstantValueForVariable(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, ...)`.
96 if (Analysis::IsCompileTimeConstant(*value)) {
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)`.
105 if (Analysis::IsCompileTimeConstant(*value)) {
106 const ConstructorDiagonalMatrix& ctor = value->as<ConstructorDiagonalMatrix>();
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
negate_operands(const Context & context,Position pos,const ExpressionArray & array)122 static ExpressionArray negate_operands(const Context& context,
123 Position pos,
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
negate_operand(const Context & context,Position pos,std::unique_ptr<Expression> value)139 static std::unique_ptr<Expression> negate_operand(const Context& context,
140 Position pos,
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
logical_not_operand(const Context & context,Position pos,std::unique_ptr<Expression> operand)151 static std::unique_ptr<Expression> logical_not_operand(const Context& context,
152 Position pos,
153 std::unique_ptr<Expression> operand) {
154 const Expression* value = ConstantFolder::GetConstantValueForVariable(*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
bitwise_not_operand(const Context & context,Position pos,std::unique_ptr<Expression> operand)198 static std::unique_ptr<Expression> bitwise_not_operand(const Context& context,
199 Position pos,
200 std::unique_ptr<Expression> operand) {
201 SkASSERT(operand->type().componentType().isInteger());
202
203 const Expression* value = ConstantFolder::GetConstantValueForVariable(*operand);
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,
211 bitwise_not_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
Convert(const Context & context,Position pos,Operator op,std::unique_ptr<Expression> base)233 std::unique_ptr<Expression> PrefixExpression::Convert(const Context& context,
234 Position pos,
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.isArray() || !baseType.componentType().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
Make(const Context & context,Position pos,Operator op,std::unique_ptr<Expression> base)303 std::unique_ptr<Expression> PrefixExpression::Make(const Context& context,
304 Position pos,
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.isArray());
327 SkASSERT(baseType.componentType().isNumber());
328 SkASSERT(Analysis::IsAssignable(*base));
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
description(OperatorPrecedence parentPrecedence) const349 std::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
358