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