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 "include/private/SkSLProgramElement.h" 9cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLExpressionStatement.h" 10cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFunctionDefinition.h" 11cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLNop.h" 12cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLProgram.h" 13cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLVarDeclarations.h" 14cb93a386Sopenharmony_ci#include "src/sksl/transform/SkSLProgramWriter.h" 15cb93a386Sopenharmony_ci#include "src/sksl/transform/SkSLTransform.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_cinamespace SkSL { 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cibool Transform::EliminateDeadLocalVariables(Program& program, ProgramUsage* usage) { 20cb93a386Sopenharmony_ci class DeadLocalVariableEliminator : public ProgramWriter { 21cb93a386Sopenharmony_ci public: 22cb93a386Sopenharmony_ci DeadLocalVariableEliminator(const Context& context, ProgramUsage* usage) 23cb93a386Sopenharmony_ci : fContext(context) 24cb93a386Sopenharmony_ci , fUsage(usage) {} 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci using ProgramWriter::visitProgramElement; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override { 29cb93a386Sopenharmony_ci // We don't need to look inside expressions at all. 30cb93a386Sopenharmony_ci return false; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci bool visitStatementPtr(std::unique_ptr<Statement>& stmt) override { 34cb93a386Sopenharmony_ci if (stmt->is<VarDeclaration>()) { 35cb93a386Sopenharmony_ci VarDeclaration& varDecl = stmt->as<VarDeclaration>(); 36cb93a386Sopenharmony_ci const Variable* var = &varDecl.var(); 37cb93a386Sopenharmony_ci ProgramUsage::VariableCounts* counts = fUsage->fVariableCounts.find(var); 38cb93a386Sopenharmony_ci SkASSERT(counts); 39cb93a386Sopenharmony_ci SkASSERT(counts->fDeclared); 40cb93a386Sopenharmony_ci if (CanEliminate(var, *counts)) { 41cb93a386Sopenharmony_ci if (var->initialValue()) { 42cb93a386Sopenharmony_ci // The variable has an initial-value expression, which might have side 43cb93a386Sopenharmony_ci // effects. ExpressionStatement::Make will preserve side effects, but 44cb93a386Sopenharmony_ci // replaces pure expressions with Nop. 45cb93a386Sopenharmony_ci fUsage->remove(stmt.get()); 46cb93a386Sopenharmony_ci stmt = ExpressionStatement::Make(fContext, std::move(varDecl.value())); 47cb93a386Sopenharmony_ci fUsage->add(stmt.get()); 48cb93a386Sopenharmony_ci } else { 49cb93a386Sopenharmony_ci // The variable has no initial-value and can be cleanly eliminated. 50cb93a386Sopenharmony_ci fUsage->remove(stmt.get()); 51cb93a386Sopenharmony_ci stmt = Nop::Make(); 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci fMadeChanges = true; 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci return false; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci return INHERITED::visitStatementPtr(stmt); 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci static bool CanEliminate(const Variable* var, const ProgramUsage::VariableCounts& counts) { 61cb93a386Sopenharmony_ci if (!counts.fDeclared || counts.fRead || var->storage() != VariableStorage::kLocal) { 62cb93a386Sopenharmony_ci return false; 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci if (var->initialValue()) { 65cb93a386Sopenharmony_ci SkASSERT(counts.fWrite >= 1); 66cb93a386Sopenharmony_ci return counts.fWrite == 1; 67cb93a386Sopenharmony_ci } else { 68cb93a386Sopenharmony_ci return counts.fWrite == 0; 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci bool fMadeChanges = false; 73cb93a386Sopenharmony_ci const Context& fContext; 74cb93a386Sopenharmony_ci ProgramUsage* fUsage; 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci using INHERITED = ProgramWriter; 77cb93a386Sopenharmony_ci }; 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci DeadLocalVariableEliminator visitor{*program.fContext, usage}; 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci if (program.fConfig->fSettings.fRemoveDeadVariables) { 82cb93a386Sopenharmony_ci for (auto& [var, counts] : usage->fVariableCounts) { 83cb93a386Sopenharmony_ci if (DeadLocalVariableEliminator::CanEliminate(var, counts)) { 84cb93a386Sopenharmony_ci // This program contains at least one dead local variable. 85cb93a386Sopenharmony_ci // Scan the program for any dead local variables and eliminate them all. 86cb93a386Sopenharmony_ci for (std::unique_ptr<ProgramElement>& pe : program.fOwnedElements) { 87cb93a386Sopenharmony_ci if (pe->is<FunctionDefinition>()) { 88cb93a386Sopenharmony_ci visitor.visitProgramElement(*pe); 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci break; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci return visitor.fMadeChanges; 97cb93a386Sopenharmony_ci} 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci} // namespace SkSL 100