| /* |
| * 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 "src/sksl/ir/SkSLBoolLiteral.h" |
| #include "src/sksl/ir/SkSLConstructor.h" |
| #include "src/sksl/ir/SkSLFloatLiteral.h" |
| #include "src/sksl/ir/SkSLIntLiteral.h" |
| |
| namespace SkSL { |
| |
| static std::unique_ptr<Expression> negate_operand(const Expression& operand) { |
| switch (operand.kind()) { |
| case Expression::Kind::kFloatLiteral: |
| // Convert -floatLiteral(1) to floatLiteral(-1). |
| return std::make_unique<FloatLiteral>(operand.fOffset, |
| -operand.as<FloatLiteral>().value(), |
| &operand.type()); |
| |
| case Expression::Kind::kIntLiteral: |
| // Convert -intLiteral(1) to intLiteral(-1). |
| return std::make_unique<IntLiteral>(operand.fOffset, |
| -operand.as<IntLiteral>().value(), |
| &operand.type()); |
| |
| default: |
| // Convert Expr to Prefix(TK_MINUS, Expr). |
| return std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS, |
| operand.clone()); |
| } |
| } |
| |
| std::unique_ptr<Expression> PrefixExpression::constantPropagate(const IRGenerator& irGenerator, |
| const DefinitionMap& definitions) { |
| if (this->operand()->isCompileTimeConstant()) { |
| if (this->getOperator().kind() == Token::Kind::TK_MINUS) { |
| // Constant-propagate negation onto compile-time constants. |
| switch (this->operand()->kind()) { |
| case Expression::Kind::kFloatLiteral: |
| case Expression::Kind::kIntLiteral: |
| return negate_operand(*this->operand()); |
| |
| case Expression::Kind::kConstructor: { |
| // We've found a negated constant vector, e.g.: |
| // -float4(float3(floatLiteral(1)), floatLiteral(2)) |
| // To optimize this, the outer negation is removed and each argument is negated: |
| // float4(-float3(floatLiteral(1)), floatLiteral(-2)) |
| // Steady state is reached after another optimization pass: |
| // float4(float3(floatLiteral(-1)), floatLiteral(-2)) |
| const Constructor& constructor = this->operand()->as<Constructor>(); |
| ExpressionArray args; |
| args.reserve_back(constructor.arguments().size()); |
| for (const std::unique_ptr<Expression>& arg : constructor.arguments()) { |
| args.push_back(negate_operand(*arg)); |
| } |
| return Constructor::Make(irGenerator.fContext, constructor.fOffset, |
| constructor.type(), std::move(args)); |
| } |
| |
| default: |
| break; |
| } |
| } else if (this->getOperator().kind() == Token::Kind::TK_LOGICALNOT) { |
| if (this->operand()->is<BoolLiteral>()) { |
| // Convert !boolLiteral(true) to boolLiteral(false). |
| const BoolLiteral& b = this->operand()->as<BoolLiteral>(); |
| return std::make_unique<BoolLiteral>(b.fOffset, !b.value(), &b.type()); |
| } |
| } |
| } |
| return nullptr; |
| } |
| |
| } // namespace SkSL |