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