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
19namespace SkSL {
20namespace {
21
22class ProgramUsageVisitor : public ProgramVisitor {
23public:
24    ProgramUsageVisitor(ProgramUsage* usage, int delta) : fUsage(usage), fDelta(delta) {}
25
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
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
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
92std::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
99std::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
108ProgramUsage::VariableCounts ProgramUsage::get(const Variable& v) const {
109    const VariableCounts* counts = fVariableCounts.find(&v);
110    SkASSERT(counts);
111    return *counts;
112}
113
114bool 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
126int ProgramUsage::get(const FunctionDeclaration& f) const {
127    const int* count = fCallCounts.find(&f);
128    return count ? *count : 0;
129}
130
131void ProgramUsage::add(const Expression* expr) {
132    ProgramUsageVisitor addRefs(this, /*delta=*/+1);
133    addRefs.visitExpression(*expr);
134}
135
136void ProgramUsage::add(const Statement* stmt) {
137    ProgramUsageVisitor addRefs(this, /*delta=*/+1);
138    addRefs.visitStatement(*stmt);
139}
140
141void ProgramUsage::add(const ProgramElement& element) {
142    ProgramUsageVisitor addRefs(this, /*delta=*/+1);
143    addRefs.visitProgramElement(element);
144}
145
146void ProgramUsage::remove(const Expression* expr) {
147    ProgramUsageVisitor subRefs(this, /*delta=*/-1);
148    subRefs.visitExpression(*expr);
149}
150
151void ProgramUsage::remove(const Statement* stmt) {
152    ProgramUsageVisitor subRefs(this, /*delta=*/-1);
153    subRefs.visitStatement(*stmt);
154}
155
156void ProgramUsage::remove(const ProgramElement& element) {
157    ProgramUsageVisitor subRefs(this, /*delta=*/-1);
158    subRefs.visitProgramElement(element);
159}
160
161}  // namespace SkSL
162