1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 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/SkSLAnalysis.h" 9cb93a386Sopenharmony_ci#include "src/sksl/SkSLConstantFolder.h" 10cb93a386Sopenharmony_ci#include "src/sksl/SkSLContext.h" 11cb93a386Sopenharmony_ci#include "src/sksl/SkSLProgramSettings.h" 12cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLExpressionStatement.h" 13cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLIfStatement.h" 14cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLLiteral.h" 15cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLNop.h" 16cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLType.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_cinamespace SkSL { 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_cistd::unique_ptr<Statement> IfStatement::clone() const { 21cb93a386Sopenharmony_ci return std::make_unique<IfStatement>(fLine, this->isStatic(), this->test()->clone(), 22cb93a386Sopenharmony_ci this->ifTrue()->clone(), 23cb93a386Sopenharmony_ci this->ifFalse() ? this->ifFalse()->clone() : nullptr); 24cb93a386Sopenharmony_ci} 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciString IfStatement::description() const { 27cb93a386Sopenharmony_ci String result; 28cb93a386Sopenharmony_ci if (this->isStatic()) { 29cb93a386Sopenharmony_ci result += "@"; 30cb93a386Sopenharmony_ci } 31cb93a386Sopenharmony_ci result += "if (" + this->test()->description() + ") " + this->ifTrue()->description(); 32cb93a386Sopenharmony_ci if (this->ifFalse()) { 33cb93a386Sopenharmony_ci result += " else " + this->ifFalse()->description(); 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci return result; 36cb93a386Sopenharmony_ci} 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_cistd::unique_ptr<Statement> IfStatement::Convert(const Context& context, int line, bool isStatic, 39cb93a386Sopenharmony_ci std::unique_ptr<Expression> test, 40cb93a386Sopenharmony_ci std::unique_ptr<Statement> ifTrue, 41cb93a386Sopenharmony_ci std::unique_ptr<Statement> ifFalse) { 42cb93a386Sopenharmony_ci test = context.fTypes.fBool->coerceExpression(std::move(test), context); 43cb93a386Sopenharmony_ci if (!test) { 44cb93a386Sopenharmony_ci return nullptr; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci SkASSERT(ifTrue); 47cb93a386Sopenharmony_ci if (Analysis::DetectVarDeclarationWithoutScope(*ifTrue, context.fErrors)) { 48cb93a386Sopenharmony_ci return nullptr; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci if (ifFalse && Analysis::DetectVarDeclarationWithoutScope(*ifFalse, context.fErrors)) { 51cb93a386Sopenharmony_ci return nullptr; 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci return IfStatement::Make(context, line, isStatic, std::move(test), 54cb93a386Sopenharmony_ci std::move(ifTrue), std::move(ifFalse)); 55cb93a386Sopenharmony_ci} 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_cistatic std::unique_ptr<Statement> replace_empty_with_nop(std::unique_ptr<Statement> stmt, 58cb93a386Sopenharmony_ci bool isEmpty) { 59cb93a386Sopenharmony_ci return (stmt && (!isEmpty || stmt->is<Nop>())) ? std::move(stmt) 60cb93a386Sopenharmony_ci : Nop::Make(); 61cb93a386Sopenharmony_ci} 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_cistd::unique_ptr<Statement> IfStatement::Make(const Context& context, int line, bool isStatic, 64cb93a386Sopenharmony_ci std::unique_ptr<Expression> test, 65cb93a386Sopenharmony_ci std::unique_ptr<Statement> ifTrue, 66cb93a386Sopenharmony_ci std::unique_ptr<Statement> ifFalse) { 67cb93a386Sopenharmony_ci SkASSERT(test->type() == *context.fTypes.fBool); 68cb93a386Sopenharmony_ci SkASSERT(!Analysis::DetectVarDeclarationWithoutScope(*ifTrue)); 69cb93a386Sopenharmony_ci SkASSERT(!ifFalse || !Analysis::DetectVarDeclarationWithoutScope(*ifFalse)); 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci const bool optimize = context.fConfig->fSettings.fOptimize; 72cb93a386Sopenharmony_ci bool trueIsEmpty = false; 73cb93a386Sopenharmony_ci bool falseIsEmpty = false; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci if (optimize) { 76cb93a386Sopenharmony_ci // If both sides are empty, the if statement can be reduced to its test expression. 77cb93a386Sopenharmony_ci trueIsEmpty = ifTrue->isEmpty(); 78cb93a386Sopenharmony_ci falseIsEmpty = !ifFalse || ifFalse->isEmpty(); 79cb93a386Sopenharmony_ci if (trueIsEmpty && falseIsEmpty) { 80cb93a386Sopenharmony_ci return ExpressionStatement::Make(context, std::move(test)); 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci if (isStatic || optimize) { 85cb93a386Sopenharmony_ci // Static Boolean values can fold down to a single branch. 86cb93a386Sopenharmony_ci const Expression* testValue = ConstantFolder::GetConstantValueForVariable(*test); 87cb93a386Sopenharmony_ci if (testValue->isBoolLiteral()) { 88cb93a386Sopenharmony_ci if (testValue->as<Literal>().boolValue()) { 89cb93a386Sopenharmony_ci return replace_empty_with_nop(std::move(ifTrue), trueIsEmpty); 90cb93a386Sopenharmony_ci } else { 91cb93a386Sopenharmony_ci return replace_empty_with_nop(std::move(ifFalse), falseIsEmpty); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci if (optimize) { 97cb93a386Sopenharmony_ci // Replace an empty if-true branches with Nop; eliminate empty if-false branches entirely. 98cb93a386Sopenharmony_ci ifTrue = replace_empty_with_nop(std::move(ifTrue), trueIsEmpty); 99cb93a386Sopenharmony_ci if (falseIsEmpty) { 100cb93a386Sopenharmony_ci ifFalse = nullptr; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci return std::make_unique<IfStatement>(line, isStatic, std::move(test), 105cb93a386Sopenharmony_ci std::move(ifTrue), std::move(ifFalse)); 106cb93a386Sopenharmony_ci} 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci} // namespace SkSL 109