xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLPrefixExpression.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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