• 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/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