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/sksl/SkSLAnalysis.h"
9 #include "src/sksl/SkSLCompiler.h"
10 #include "src/sksl/analysis/SkSLProgramVisitor.h"
11 #include "src/sksl/ir/SkSLFunctionCall.h"
12 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
13 #include "src/sksl/ir/SkSLFunctionDefinition.h"
14 #include "src/sksl/ir/SkSLInterfaceBlock.h"
15 #include "src/sksl/ir/SkSLProgram.h"
16 #include "src/sksl/ir/SkSLVarDeclarations.h"
17 #include "src/sksl/ir/SkSLVariableReference.h"
18
19 namespace SkSL {
20 namespace {
21
22 class ProgramUsageVisitor : public ProgramVisitor {
23 public:
ProgramUsageVisitor(ProgramUsage * usage,int delta)24 ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
25
visitProgramElement(const ProgramElement & pe)26 bool visitProgramElement(const ProgramElement& pe) override {
27 if (pe.is<FunctionDefinition>()) {
28 for (const Variable* param : pe.as<FunctionDefinition>().declaration().parameters()) {
29 // Ensure function-parameter variables exist in the variable usage map. They aren't
30 // otherwise declared, but ProgramUsage::get() should be able to find them, even if
31 // they are unread and unwritten.
32 fUsage->fVariableCounts[param];
33 }
34 } else if (pe.is<InterfaceBlock>()) {
35 // Ensure interface-block variables exist in the variable usage map.
36 fUsage->fVariableCounts[&pe.as<InterfaceBlock>().variable()];
37 }
38 return INHERITED::visitProgramElement(pe);
39 }
40
visitStatement(const Statement & s)41 bool visitStatement(const Statement& s) override {
42 if (s.is<VarDeclaration>()) {
43 // Add all declared variables to the usage map (even if never otherwise accessed).
44 const VarDeclaration& vd = s.as<VarDeclaration>();
45 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[&vd.var()];
46 counts.fDeclared += fDelta;
47 SkASSERT(counts.fDeclared >= 0);
48 if (vd.value()) {
49 // The initial-value expression, when present, counts as a write.
50 counts.fWrite += fDelta;
51 }
52 }
53 return INHERITED::visitStatement(s);
54 }
55
visitExpression(const Expression & e)56 bool visitExpression(const Expression& e) override {
57 if (e.is<FunctionCall>()) {
58 const FunctionDeclaration* f = &e.as<FunctionCall>().function();
59 fUsage->fCallCounts[f] += fDelta;
60 SkASSERT(fUsage->fCallCounts[f] >= 0);
61 } else if (e.is<VariableReference>()) {
62 const VariableReference& ref = e.as<VariableReference>();
63 ProgramUsage::VariableCounts& counts = fUsage->fVariableCounts[ref.variable()];
64 switch (ref.refKind()) {
65 case VariableRefKind::kRead:
66 counts.fRead += fDelta;
67 break;
68 case VariableRefKind::kWrite:
69 counts.fWrite += fDelta;
70 break;
71 case VariableRefKind::kReadWrite:
72 case VariableRefKind::kPointer:
73 counts.fRead += fDelta;
74 counts.fWrite += fDelta;
75 break;
76 }
77 SkASSERT(counts.fRead >= 0 && counts.fWrite >= 0);
78 }
79 return INHERITED::visitExpression(e);
80 }
81
82 using ProgramVisitor::visitProgramElement;
83 using ProgramVisitor::visitStatement;
84
85 ProgramUsage* fUsage;
86 int fDelta;
87 using INHERITED = ProgramVisitor;
88 };
89
90 } // namespace
91
GetUsage(const Program & program)92 std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
93 auto usage = std::make_unique<ProgramUsage>();
94 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
95 addRefs.visit(program);
96 return usage;
97 }
98
GetUsage(const LoadedModule & module)99 std::unique_ptr<ProgramUsage> Analysis::GetUsage(const LoadedModule& module) {
100 auto usage = std::make_unique<ProgramUsage>();
101 ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
102 for (const auto& element : module.fElements) {
103 addRefs.visitProgramElement(*element);
104 }
105 return usage;
106 }
107
get(const Variable & v) const108 ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
109 const VariableCounts* counts = fVariableCounts.find(&v);
110 SkASSERT(counts);
111 return *counts;
112 }
113
isDead(const Variable & v) const114 bool ProgramUsage::isDead(const Variable& v) const {
115 const Modifiers& modifiers = v.modifiers();
116 VariableCounts counts = this->get(v);
117 if ((v.storage() != Variable::Storage::kLocal && counts.fRead) ||
118 (modifiers.fFlags &
119 (Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag))) {
120 return false;
121 }
122 // Consider the variable dead if it's never read and never written (besides the initial-value).
123 return !counts.fRead && (counts.fWrite <= (v.initialValue() ? 1 : 0));
124 }
125
get(const FunctionDeclaration & f) const126 int ProgramUsage::get(const FunctionDeclaration& f) const {
127 const int* count = fCallCounts.find(&f);
128 return count ? *count : 0;
129 }
130
add(const Expression * expr)131 void ProgramUsage::add(const Expression* expr) {
132 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
133 addRefs.visitExpression(*expr);
134 }
135
add(const Statement * stmt)136 void ProgramUsage::add(const Statement* stmt) {
137 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
138 addRefs.visitStatement(*stmt);
139 }
140
add(const ProgramElement & element)141 void ProgramUsage::add(const ProgramElement& element) {
142 ProgramUsageVisitor addRefs(this, /*delta=*/+1);
143 addRefs.visitProgramElement(element);
144 }
145
remove(const Expression * expr)146 void ProgramUsage::remove(const Expression* expr) {
147 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
148 subRefs.visitExpression(*expr);
149 }
150
remove(const Statement * stmt)151 void ProgramUsage::remove(const Statement* stmt) {
152 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
153 subRefs.visitStatement(*stmt);
154 }
155
remove(const ProgramElement & element)156 void ProgramUsage::remove(const ProgramElement& element) {
157 ProgramUsageVisitor subRefs(this, /*delta=*/-1);
158 subRefs.visitProgramElement(element);
159 }
160
161 } // namespace SkSL
162