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