• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/sksl/SkSLErrorReporter.h"
11 #include "src/sksl/SkSLAnalysis.h"
12 #include "src/sksl/SkSLConstantFolder.h"
13 #include "src/sksl/SkSLProgramSettings.h"
14 #include "src/sksl/ir/SkSLConstructor.h"
15 #include "src/sksl/ir/SkSLConstructorArray.h"
16 #include "src/sksl/ir/SkSLConstructorCompound.h"
17 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
18 #include "src/sksl/ir/SkSLConstructorSplat.h"
19 #include "src/sksl/ir/SkSLLiteral.h"
20 #include "src/sksl/ir/SkSLVariableReference.h"
21 
22 namespace SkSL {
23 
24 static ExpressionArray negate_operands(const Context& context, const ExpressionArray& operands);
25 
simplify_negation(const Context & context,const Expression & originalExpr)26 static std::unique_ptr<Expression> simplify_negation(const Context& context,
27                                                      const Expression& originalExpr) {
28     const Expression* value = ConstantFolder::GetConstantValueForVariable(originalExpr);
29     switch (value->kind()) {
30         case Expression::Kind::kLiteral: {
31             // Convert -literal(1) to literal(-1).
32             double negated = -value->as<Literal>().value();
33             // Don't simplify the expression if the type can't hold the negated value.
34             const Type& type = value->type();
35             if (type.checkForOutOfRangeLiteral(context, negated, value->fLine)) {
36                 return nullptr;
37             }
38             return Literal::Make(originalExpr.fLine, negated, &type);
39         }
40         case Expression::Kind::kPrefix: {
41             // Convert `-(-expression)` into `expression`.
42             const PrefixExpression& prefix = value->as<PrefixExpression>();
43             if (prefix.getOperator().kind() == Token::Kind::TK_MINUS) {
44                 return prefix.operand()->clone();
45             }
46             break;
47         }
48         case Expression::Kind::kConstructorArray:
49             // Convert `-array[N](literal, ...)` into `array[N](-literal, ...)`.
50             if (value->isCompileTimeConstant()) {
51                 const ConstructorArray& ctor = value->as<ConstructorArray>();
52                 return ConstructorArray::Make(context, originalExpr.fLine, ctor.type(),
53                                               negate_operands(context, ctor.arguments()));
54             }
55             break;
56 
57         case Expression::Kind::kConstructorDiagonalMatrix:
58             // Convert `-matrix(literal)` into `matrix(-literal)`.
59             if (value->isCompileTimeConstant()) {
60                 const ConstructorDiagonalMatrix& ctor = value->as<ConstructorDiagonalMatrix>();
61                 if (std::unique_ptr<Expression> simplified = simplify_negation(context,
62                                                                                *ctor.argument())) {
63                     return ConstructorDiagonalMatrix::Make(context, originalExpr.fLine, ctor.type(),
64                                                            std::move(simplified));
65                 }
66             }
67             break;
68 
69         case Expression::Kind::kConstructorSplat:
70             // Convert `-vector(literal)` into `vector(-literal)`.
71             if (value->isCompileTimeConstant()) {
72                 const ConstructorSplat& ctor = value->as<ConstructorSplat>();
73                 if (std::unique_ptr<Expression> simplified = simplify_negation(context,
74                                                                                *ctor.argument())) {
75                     return ConstructorSplat::Make(context, originalExpr.fLine, ctor.type(),
76                                                   std::move(simplified));
77                 }
78             }
79             break;
80 
81         case Expression::Kind::kConstructorCompound:
82             // Convert `-vecN(literal, ...)` into `vecN(-literal, ...)`.
83             if (value->isCompileTimeConstant()) {
84                 const ConstructorCompound& ctor = value->as<ConstructorCompound>();
85                 return ConstructorCompound::Make(context, originalExpr.fLine, ctor.type(),
86                                                  negate_operands(context, ctor.arguments()));
87             }
88             break;
89 
90         default:
91             break;
92     }
93     return nullptr;
94 }
95 
negate_operands(const Context & context,const ExpressionArray & array)96 static ExpressionArray negate_operands(const Context& context, const ExpressionArray& array) {
97     ExpressionArray replacement;
98     replacement.reserve_back(array.size());
99     for (const std::unique_ptr<Expression>& expr : array) {
100         // The logic below is very similar to `negate_operand`, but with different ownership rules.
101         if (std::unique_ptr<Expression> simplified = simplify_negation(context, *expr)) {
102             replacement.push_back(std::move(simplified));
103         } else {
104             replacement.push_back(std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS,
105                                                                      expr->clone()));
106         }
107     }
108     return replacement;
109 }
110 
negate_operand(const Context & context,std::unique_ptr<Expression> value)111 static std::unique_ptr<Expression> negate_operand(const Context& context,
112                                                   std::unique_ptr<Expression> value) {
113     // Attempt to simplify this negation (e.g. eliminate double negation, literal values)
114     if (std::unique_ptr<Expression> simplified = simplify_negation(context, *value)) {
115         return simplified;
116     }
117 
118     // No simplified form; convert expression to Prefix(TK_MINUS, expression).
119     return std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS, std::move(value));
120 }
121 
logical_not_operand(const Context & context,std::unique_ptr<Expression> operand)122 static std::unique_ptr<Expression> logical_not_operand(const Context& context,
123                                                        std::unique_ptr<Expression> operand) {
124     const Expression* value = ConstantFolder::GetConstantValueForVariable(*operand);
125     switch (value->kind()) {
126         case Expression::Kind::kLiteral: {
127             // Convert !boolLiteral(true) to boolLiteral(false).
128             SkASSERT(value->type().isBoolean());
129             const Literal& b = value->as<Literal>();
130             return Literal::MakeBool(operand->fLine, !b.boolValue(), &operand->type());
131         }
132         case Expression::Kind::kPrefix: {
133             // Convert `!(!expression)` into `expression`.
134             PrefixExpression& prefix = operand->as<PrefixExpression>();
135             if (prefix.getOperator().kind() == Token::Kind::TK_LOGICALNOT) {
136                 return std::move(prefix.operand());
137             }
138             break;
139         }
140         default:
141             break;
142     }
143 
144     // No simplified form; convert expression to Prefix(TK_LOGICALNOT, expression).
145     return std::make_unique<PrefixExpression>(Token::Kind::TK_LOGICALNOT, std::move(operand));
146 }
147 
Convert(const Context & context,Operator op,std::unique_ptr<Expression> base)148 std::unique_ptr<Expression> PrefixExpression::Convert(const Context& context,
149                                                       Operator op,
150                                                       std::unique_ptr<Expression> base) {
151     const Type& baseType = base->type();
152     switch (op.kind()) {
153         case Token::Kind::TK_PLUS:
154             if (baseType.isArray() || !baseType.componentType().isNumber()) {
155                 context.fErrors->error(base->fLine,
156                                        "'+' cannot operate on '" + baseType.displayName() + "'");
157                 return nullptr;
158             }
159             break;
160 
161         case Token::Kind::TK_MINUS:
162             if (baseType.isArray() || !baseType.componentType().isNumber()) {
163                 context.fErrors->error(base->fLine,
164                                        "'-' cannot operate on '" + baseType.displayName() + "'");
165                 return nullptr;
166             }
167             break;
168 
169         case Token::Kind::TK_PLUSPLUS:
170         case Token::Kind::TK_MINUSMINUS:
171             if (!baseType.isNumber()) {
172                 context.fErrors->error(base->fLine,
173                                        String("'") + op.operatorName() + "' cannot operate on '" +
174                                        baseType.displayName() + "'");
175                 return nullptr;
176             }
177             if (!Analysis::UpdateVariableRefKind(base.get(), VariableReference::RefKind::kReadWrite,
178                                                  context.fErrors)) {
179                 return nullptr;
180             }
181             break;
182 
183         case Token::Kind::TK_LOGICALNOT:
184             if (!baseType.isBoolean()) {
185                 context.fErrors->error(base->fLine,
186                                        String("'") + op.operatorName() + "' cannot operate on '" +
187                                        baseType.displayName() + "'");
188                 return nullptr;
189             }
190             break;
191 
192         case Token::Kind::TK_BITWISENOT:
193             if (context.fConfig->strictES2Mode()) {
194                 // GLSL ES 1.00, Section 5.1
195                 context.fErrors->error(
196                         base->fLine,
197                         String("operator '") + op.operatorName() + "' is not allowed");
198                 return nullptr;
199             }
200             if (baseType.isArray() || !baseType.componentType().isInteger()) {
201                 context.fErrors->error(base->fLine,
202                                        String("'") + op.operatorName() + "' cannot operate on '" +
203                                        baseType.displayName() + "'");
204                 return nullptr;
205             }
206             if (baseType.isLiteral()) {
207                 // The expression `~123` is no longer a literal; coerce to the actual type.
208                 base = baseType.scalarTypeForLiteral().coerceExpression(std::move(base), context);
209                 if (!base) {
210                     return nullptr;
211                 }
212             }
213             break;
214 
215         default:
216             SK_ABORT("unsupported prefix operator");
217     }
218 
219     return PrefixExpression::Make(context, op, std::move(base));
220 }
221 
Make(const Context & context,Operator op,std::unique_ptr<Expression> base)222 std::unique_ptr<Expression> PrefixExpression::Make(const Context& context, Operator op,
223                                                    std::unique_ptr<Expression> base) {
224     switch (op.kind()) {
225         case Token::Kind::TK_PLUS:
226             SkASSERT(!base->type().isArray());
227             SkASSERT(base->type().componentType().isNumber());
228             return base;
229 
230         case Token::Kind::TK_MINUS:
231             SkASSERT(!base->type().isArray());
232             SkASSERT(base->type().componentType().isNumber());
233             return negate_operand(context, std::move(base));
234 
235         case Token::Kind::TK_LOGICALNOT:
236             SkASSERT(base->type().isBoolean());
237             return logical_not_operand(context, std::move(base));
238 
239         case Token::Kind::TK_PLUSPLUS:
240         case Token::Kind::TK_MINUSMINUS:
241             SkASSERT(base->type().isNumber());
242             SkASSERT(Analysis::IsAssignable(*base));
243             break;
244 
245         case Token::Kind::TK_BITWISENOT:
246             SkASSERT(!context.fConfig->strictES2Mode());
247             SkASSERT(!base->type().isArray());
248             SkASSERT(base->type().componentType().isInteger());
249             SkASSERT(!base->type().isLiteral());
250             break;
251 
252         default:
253             SkDEBUGFAILF("unsupported prefix operator: %s", op.operatorName());
254     }
255 
256     return std::make_unique<PrefixExpression>(op, std::move(base));
257 }
258 
259 }  // namespace SkSL
260