• 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 "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