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