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 "src/base/SkStringView.h"
9 #include "src/sksl/SkSLContext.h"
10 #include "src/sksl/SkSLModule.h"
11 #include "src/sksl/SkSLProgramSettings.h"
12 #include "src/sksl/analysis/SkSLProgramUsage.h"
13 #include "src/sksl/ir/SkSLProgram.h"
14 #include "src/sksl/ir/SkSLProgramElement.h"
15 #include "src/sksl/ir/SkSLVarDeclarations.h"
16 #include "src/sksl/ir/SkSLVariable.h"
17 #include "src/sksl/transform/SkSLTransform.h"
18
19 #include <algorithm>
20 #include <cstddef>
21 #include <memory>
22 #include <vector>
23
24 namespace SkSL {
25
is_dead_variable(const ProgramElement & element,ProgramUsage * usage,bool onlyPrivateGlobals)26 static bool is_dead_variable(const ProgramElement& element,
27 ProgramUsage* usage,
28 bool onlyPrivateGlobals) {
29 if (!element.is<GlobalVarDeclaration>()) {
30 return false;
31 }
32 const GlobalVarDeclaration& global = element.as<GlobalVarDeclaration>();
33 const VarDeclaration& varDecl = global.varDeclaration();
34 if (onlyPrivateGlobals && !skstd::starts_with(varDecl.var()->name(), '$')) {
35 return false;
36 }
37 if (!usage->isDead(*varDecl.var())) {
38 return false;
39 }
40 // This declaration is about to be eliminated by remove_if; update ProgramUsage accordingly.
41 usage->remove(&varDecl);
42 return true;
43 }
44
EliminateDeadGlobalVariables(const Context & context,Module & module,ProgramUsage * usage,bool onlyPrivateGlobals)45 bool Transform::EliminateDeadGlobalVariables(const Context& context,
46 Module& module,
47 ProgramUsage* usage,
48 bool onlyPrivateGlobals) {
49 auto isDeadVariable = [&](const ProgramElement& element) {
50 return is_dead_variable(element, usage, onlyPrivateGlobals);
51 };
52
53 size_t numElements = module.fElements.size();
54 if (context.fConfig->fSettings.fRemoveDeadVariables) {
55 module.fElements.erase(std::remove_if(module.fElements.begin(),
56 module.fElements.end(),
57 [&](const std::unique_ptr<ProgramElement>& pe) {
58 return isDeadVariable(*pe);
59 }),
60 module.fElements.end());
61 }
62 return module.fElements.size() < numElements;
63 }
64
EliminateDeadGlobalVariables(Program & program)65 bool Transform::EliminateDeadGlobalVariables(Program& program) {
66 auto isDeadVariable = [&](const ProgramElement& element) {
67 return is_dead_variable(element, program.fUsage.get(), /*onlyPrivateGlobals=*/false);
68 };
69
70 size_t numOwnedElements = program.fOwnedElements.size();
71 size_t numSharedElements = program.fSharedElements.size();
72 if (program.fConfig->fSettings.fRemoveDeadVariables) {
73 program.fOwnedElements.erase(std::remove_if(program.fOwnedElements.begin(),
74 program.fOwnedElements.end(),
75 [&](const std::unique_ptr<ProgramElement>& pe) {
76 return isDeadVariable(*pe);
77 }),
78 program.fOwnedElements.end());
79 program.fSharedElements.erase(std::remove_if(program.fSharedElements.begin(),
80 program.fSharedElements.end(),
81 [&](const ProgramElement* pe) {
82 return isDeadVariable(*pe);
83 }),
84 program.fSharedElements.end());
85 }
86 return program.fOwnedElements.size() < numOwnedElements ||
87 program.fSharedElements.size() < numSharedElements;
88 }
89
90 } // namespace SkSL
91