summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.cpp')
-rw-r--r--gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.cpp b/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.cpp
new file mode 100644
index 0000000000..a5ea728de2
--- /dev/null
+++ b/gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/sksl/ir/SkSLPrefixExpression.h"
+
+#include "include/core/SkTypes.h"
+#include "include/private/SkSLDefines.h"
+#include "include/sksl/SkSLErrorReporter.h"
+#include "include/sksl/SkSLOperator.h"
+#include "src/sksl/SkSLAnalysis.h"
+#include "src/sksl/SkSLConstantFolder.h"
+#include "src/sksl/SkSLContext.h"
+#include "src/sksl/SkSLProgramSettings.h"
+#include "src/sksl/ir/SkSLConstructorArray.h"
+#include "src/sksl/ir/SkSLConstructorCompound.h"
+#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
+#include "src/sksl/ir/SkSLConstructorSplat.h"
+#include "src/sksl/ir/SkSLLiteral.h"
+#include "src/sksl/ir/SkSLType.h"
+#include "src/sksl/ir/SkSLVariableReference.h"
+
+namespace SkSL {
+
+static ExpressionArray negate_operands(const Context& context,
+ Position pos,
+ const ExpressionArray& operands);
+
+static std::unique_ptr<Expression> simplify_negation(const Context& context,
+ Position pos,
+ const Expression& originalExpr) {
+ const Expression* value = ConstantFolder::GetConstantValueForVariable(originalExpr);
+ switch (value->kind()) {
+ case Expression::Kind::kLiteral: {
+ // Convert -literal(1) to literal(-1).
+ double negated = -value->as<Literal>().value();
+ // Don't simplify the expression if the type can't hold the negated value.
+ const Type& type = value->type();
+ if (type.checkForOutOfRangeLiteral(context, negated, pos)) {
+ return nullptr;
+ }
+ return Literal::Make(pos, negated, &type);
+ }
+ case Expression::Kind::kPrefix: {
+ // Convert `-(-expression)` into `expression`.
+ const PrefixExpression& prefix = value->as<PrefixExpression>();
+ if (prefix.getOperator().kind() == Operator::Kind::MINUS) {
+ return prefix.operand()->clone(pos);
+ }
+ break;
+ }
+ case Expression::Kind::kConstructorArray:
+ // Convert `-array[N](literal, ...)` into `array[N](-literal, ...)`.
+ if (Analysis::IsCompileTimeConstant(*value)) {
+ const ConstructorArray& ctor = value->as<ConstructorArray>();
+ return ConstructorArray::Make(context, pos, ctor.type(),
+ negate_operands(context, pos, ctor.arguments()));
+ }
+ break;
+
+ case Expression::Kind::kConstructorDiagonalMatrix:
+ // Convert `-matrix(literal)` into `matrix(-literal)`.
+ if (Analysis::IsCompileTimeConstant(*value)) {
+ const ConstructorDiagonalMatrix& ctor = value->as<ConstructorDiagonalMatrix>();
+ if (std::unique_ptr<Expression> simplified = simplify_negation(context,
+ pos,
+ *ctor.argument())) {
+ return ConstructorDiagonalMatrix::Make(context, pos, ctor.type(),
+ std::move(simplified));
+ }
+ }
+ break;
+
+ case Expression::Kind::kConstructorSplat:
+ // Convert `-vector(literal)` into `vector(-literal)`.
+ if (Analysis::IsCompileTimeConstant(*value)) {
+ const ConstructorSplat& ctor = value->as<ConstructorSplat>();
+ if (std::unique_ptr<Expression> simplified = simplify_negation(context,
+ pos,
+ *ctor.argument())) {
+ return ConstructorSplat::Make(context, pos, ctor.type(), std::move(simplified));
+ }
+ }
+ break;
+
+ case Expression::Kind::kConstructorCompound:
+ // Convert `-vecN(literal, ...)` into `vecN(-literal, ...)`.
+ if (Analysis::IsCompileTimeConstant(*value)) {
+ const ConstructorCompound& ctor = value->as<ConstructorCompound>();
+ return ConstructorCompound::Make(context, pos, ctor.type(),
+ negate_operands(context, pos, ctor.arguments()));
+ }
+ break;
+
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+static ExpressionArray negate_operands(const Context& context,
+ Position pos,
+ const ExpressionArray& array) {
+ ExpressionArray replacement;
+ replacement.reserve_back(array.size());
+ for (const std::unique_ptr<Expression>& expr : array) {
+ // The logic below is very similar to `negate_operand`, but with different ownership rules.
+ if (std::unique_ptr<Expression> simplified = simplify_negation(context, pos, *expr)) {
+ replacement.push_back(std::move(simplified));
+ } else {
+ replacement.push_back(std::make_unique<PrefixExpression>(pos, Operator::Kind::MINUS,
+ expr->clone()));
+ }
+ }
+ return replacement;
+}
+
+static std::unique_ptr<Expression> negate_operand(const Context& context,
+ Position pos,
+ std::unique_ptr<Expression> value) {
+ // Attempt to simplify this negation (e.g. eliminate double negation, literal values)
+ if (std::unique_ptr<Expression> simplified = simplify_negation(context, pos, *value)) {
+ return simplified;
+ }
+
+ // No simplified form; convert expression to Prefix(TK_MINUS, expression).
+ return std::make_unique<PrefixExpression>(pos, Operator::Kind::MINUS, std::move(value));
+}
+
+static std::unique_ptr<Expression> logical_not_operand(const Context& context,
+ Position pos,
+ std::unique_ptr<Expression> operand) {
+ const Expression* value = ConstantFolder::GetConstantValueForVariable(*operand);
+ switch (value->kind()) {
+ case Expression::Kind::kLiteral: {
+ // Convert !boolLiteral(true) to boolLiteral(false).
+ SkASSERT(value->type().isBoolean());
+ const Literal& b = value->as<Literal>();
+ return Literal::MakeBool(pos, !b.boolValue(), &operand->type());
+ }
+ case Expression::Kind::kPrefix: {
+ // Convert `!(!expression)` into `expression`.
+ PrefixExpression& prefix = operand->as<PrefixExpression>();
+ if (prefix.getOperator().kind() == Operator::Kind::LOGICALNOT) {
+ prefix.operand()->fPosition = pos;
+ return std::move(prefix.operand());
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ // No simplified form; convert expression to Prefix(TK_LOGICALNOT, expression).
+ return std::make_unique<PrefixExpression>(pos, Operator::Kind::LOGICALNOT, std::move(operand));
+}
+
+std::unique_ptr<Expression> PrefixExpression::Convert(const Context& context, Position pos,
+ Operator op, std::unique_ptr<Expression> base) {
+ const Type& baseType = base->type();
+ switch (op.kind()) {
+ case Operator::Kind::PLUS:
+ if (baseType.isArray() || !baseType.componentType().isNumber()) {
+ context.fErrors->error(pos,
+ "'+' cannot operate on '" + baseType.displayName() + "'");
+ return nullptr;
+ }
+ break;
+
+ case Operator::Kind::MINUS:
+ if (baseType.isArray() || !baseType.componentType().isNumber()) {
+ context.fErrors->error(pos,
+ "'-' cannot operate on '" + baseType.displayName() + "'");
+ return nullptr;
+ }
+ break;
+
+ case Operator::Kind::PLUSPLUS:
+ case Operator::Kind::MINUSMINUS:
+ if (!baseType.isNumber()) {
+ context.fErrors->error(pos,
+ "'" + std::string(op.tightOperatorName()) +
+ "' cannot operate on '" + baseType.displayName() + "'");
+ return nullptr;
+ }
+ if (!Analysis::UpdateVariableRefKind(base.get(), VariableReference::RefKind::kReadWrite,
+ context.fErrors)) {
+ return nullptr;
+ }
+ break;
+
+ case Operator::Kind::LOGICALNOT:
+ if (!baseType.isBoolean()) {
+ context.fErrors->error(pos,
+ "'" + std::string(op.tightOperatorName()) +
+ "' cannot operate on '" + baseType.displayName() + "'");
+ return nullptr;
+ }
+ break;
+
+ case Operator::Kind::BITWISENOT:
+ if (context.fConfig->strictES2Mode()) {
+ // GLSL ES 1.00, Section 5.1
+ context.fErrors->error(
+ pos,
+ "operator '" + std::string(op.tightOperatorName()) + "' is not allowed");
+ return nullptr;
+ }
+ if (baseType.isArray() || !baseType.componentType().isInteger()) {
+ context.fErrors->error(pos,
+ "'" + std::string(op.tightOperatorName()) +
+ "' cannot operate on '" + baseType.displayName() + "'");
+ return nullptr;
+ }
+ if (baseType.isLiteral()) {
+ // The expression `~123` is no longer a literal; coerce to the actual type.
+ base = baseType.scalarTypeForLiteral().coerceExpression(std::move(base), context);
+ if (!base) {
+ return nullptr;
+ }
+ }
+ break;
+
+ default:
+ SK_ABORT("unsupported prefix operator");
+ }
+
+ std::unique_ptr<Expression> result = PrefixExpression::Make(context, pos, op, std::move(base));
+ SkASSERT(result->fPosition == pos);
+ return result;
+}
+
+std::unique_ptr<Expression> PrefixExpression::Make(const Context& context, Position pos,
+ Operator op, std::unique_ptr<Expression> base) {
+ switch (op.kind()) {
+ case Operator::Kind::PLUS:
+ SkASSERT(!base->type().isArray());
+ SkASSERT(base->type().componentType().isNumber());
+ base->fPosition = pos;
+ return base;
+
+ case Operator::Kind::MINUS:
+ SkASSERT(!base->type().isArray());
+ SkASSERT(base->type().componentType().isNumber());
+ return negate_operand(context, pos, std::move(base));
+
+ case Operator::Kind::LOGICALNOT:
+ SkASSERT(base->type().isBoolean());
+ return logical_not_operand(context, pos, std::move(base));
+
+ case Operator::Kind::PLUSPLUS:
+ case Operator::Kind::MINUSMINUS:
+ SkASSERT(base->type().isNumber());
+ SkASSERT(Analysis::IsAssignable(*base));
+ break;
+
+ case Operator::Kind::BITWISENOT:
+ SkASSERT(!context.fConfig->strictES2Mode());
+ SkASSERT(!base->type().isArray());
+ SkASSERT(base->type().componentType().isInteger());
+ SkASSERT(!base->type().isLiteral());
+ break;
+
+ default:
+ SkDEBUGFAILF("unsupported prefix operator: %s", op.operatorName());
+ }
+
+ return std::make_unique<PrefixExpression>(pos, op, std::move(base));
+}
+
+std::string PrefixExpression::description(OperatorPrecedence parentPrecedence) const {
+ bool needsParens = (OperatorPrecedence::kPrefix >= parentPrecedence);
+ return std::string(needsParens ? "(" : "") +
+ std::string(this->getOperator().tightOperatorName()) +
+ this->operand()->description(OperatorPrecedence::kPrefix) +
+ std::string(needsParens ? ")" : "");
+}
+
+} // namespace SkSL