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