1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2021 Google LLC 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 9*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h" 10*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLConstantFolder.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLModule.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/analysis/SkSLProgramUsage.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLExpression.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLFunctionDefinition.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLModifierFlags.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLProgramElement.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLVariable.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLVariableReference.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/transform/SkSLProgramWriter.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/transform/SkSLTransform.h" 21*c8dee2aaSAndroid Build Coastguard Worker 22*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 23*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 24*c8dee2aaSAndroid Build Coastguard Worker #include <string> 25*c8dee2aaSAndroid Build Coastguard Worker #include <string_view> 26*c8dee2aaSAndroid Build Coastguard Worker #include <vector> 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private; 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL { 31*c8dee2aaSAndroid Build Coastguard Worker ReplaceConstVarsWithLiterals(Module & module,ProgramUsage * usage)32*c8dee2aaSAndroid Build Coastguard Workervoid Transform::ReplaceConstVarsWithLiterals(Module& module, ProgramUsage* usage) { 33*c8dee2aaSAndroid Build Coastguard Worker class ConstVarReplacer : public ProgramWriter { 34*c8dee2aaSAndroid Build Coastguard Worker public: 35*c8dee2aaSAndroid Build Coastguard Worker ConstVarReplacer(ProgramUsage* usage) : fUsage(usage) {} 36*c8dee2aaSAndroid Build Coastguard Worker 37*c8dee2aaSAndroid Build Coastguard Worker using ProgramWriter::visitProgramElement; 38*c8dee2aaSAndroid Build Coastguard Worker 39*c8dee2aaSAndroid Build Coastguard Worker bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override { 40*c8dee2aaSAndroid Build Coastguard Worker // If this is a variable... 41*c8dee2aaSAndroid Build Coastguard Worker if (expr->is<VariableReference>()) { 42*c8dee2aaSAndroid Build Coastguard Worker VariableReference& var = expr->as<VariableReference>(); 43*c8dee2aaSAndroid Build Coastguard Worker // ... and it's a candidate for size reduction... 44*c8dee2aaSAndroid Build Coastguard Worker if (fCandidates.contains(var.variable())) { 45*c8dee2aaSAndroid Build Coastguard Worker // ... get its constant value... 46*c8dee2aaSAndroid Build Coastguard Worker if (const Expression* value = ConstantFolder::GetConstantValueOrNull(var)) { 47*c8dee2aaSAndroid Build Coastguard Worker // ... and replace it with that value. 48*c8dee2aaSAndroid Build Coastguard Worker fUsage->remove(expr.get()); 49*c8dee2aaSAndroid Build Coastguard Worker expr = value->clone(); 50*c8dee2aaSAndroid Build Coastguard Worker fUsage->add(expr.get()); 51*c8dee2aaSAndroid Build Coastguard Worker return false; 52*c8dee2aaSAndroid Build Coastguard Worker } 53*c8dee2aaSAndroid Build Coastguard Worker } 54*c8dee2aaSAndroid Build Coastguard Worker } 55*c8dee2aaSAndroid Build Coastguard Worker return INHERITED::visitExpressionPtr(expr); 56*c8dee2aaSAndroid Build Coastguard Worker } 57*c8dee2aaSAndroid Build Coastguard Worker 58*c8dee2aaSAndroid Build Coastguard Worker ProgramUsage* fUsage; 59*c8dee2aaSAndroid Build Coastguard Worker THashSet<const Variable*> fCandidates; 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = ProgramWriter; 62*c8dee2aaSAndroid Build Coastguard Worker }; 63*c8dee2aaSAndroid Build Coastguard Worker 64*c8dee2aaSAndroid Build Coastguard Worker ConstVarReplacer visitor{usage}; 65*c8dee2aaSAndroid Build Coastguard Worker 66*c8dee2aaSAndroid Build Coastguard Worker for (const auto& [var, count] : usage->fVariableCounts) { 67*c8dee2aaSAndroid Build Coastguard Worker // We can only replace const variables that still exist, and that have initial values. 68*c8dee2aaSAndroid Build Coastguard Worker if (!count.fVarExists || count.fWrite != 1) { 69*c8dee2aaSAndroid Build Coastguard Worker continue; 70*c8dee2aaSAndroid Build Coastguard Worker } 71*c8dee2aaSAndroid Build Coastguard Worker if (!var->modifierFlags().isConst()) { 72*c8dee2aaSAndroid Build Coastguard Worker continue; 73*c8dee2aaSAndroid Build Coastguard Worker } 74*c8dee2aaSAndroid Build Coastguard Worker if (!var->initialValue()) { 75*c8dee2aaSAndroid Build Coastguard Worker continue; 76*c8dee2aaSAndroid Build Coastguard Worker } 77*c8dee2aaSAndroid Build Coastguard Worker // The current size is: 78*c8dee2aaSAndroid Build Coastguard Worker // strlen("const type varname=initialvalue;`") + count*strlen("varname"). 79*c8dee2aaSAndroid Build Coastguard Worker size_t initialvalueSize = ConstantFolder::GetConstantValueForVariable(*var->initialValue()) 80*c8dee2aaSAndroid Build Coastguard Worker ->description() 81*c8dee2aaSAndroid Build Coastguard Worker .size(); 82*c8dee2aaSAndroid Build Coastguard Worker size_t totalOldSize = var->description().size() + // const type varname 83*c8dee2aaSAndroid Build Coastguard Worker 1 + // = 84*c8dee2aaSAndroid Build Coastguard Worker initialvalueSize + // initialvalue 85*c8dee2aaSAndroid Build Coastguard Worker 1 + // ; 86*c8dee2aaSAndroid Build Coastguard Worker count.fRead * var->name().size(); // count * varname 87*c8dee2aaSAndroid Build Coastguard Worker // If we replace varname with initialvalue everywhere, the new size would be: 88*c8dee2aaSAndroid Build Coastguard Worker // count*strlen("initialvalue") 89*c8dee2aaSAndroid Build Coastguard Worker size_t totalNewSize = count.fRead * initialvalueSize; // count * initialvalue 90*c8dee2aaSAndroid Build Coastguard Worker 91*c8dee2aaSAndroid Build Coastguard Worker if (totalNewSize <= totalOldSize) { 92*c8dee2aaSAndroid Build Coastguard Worker visitor.fCandidates.add(var); 93*c8dee2aaSAndroid Build Coastguard Worker } 94*c8dee2aaSAndroid Build Coastguard Worker } 95*c8dee2aaSAndroid Build Coastguard Worker 96*c8dee2aaSAndroid Build Coastguard Worker if (!visitor.fCandidates.empty()) { 97*c8dee2aaSAndroid Build Coastguard Worker for (std::unique_ptr<ProgramElement>& pe : module.fElements) { 98*c8dee2aaSAndroid Build Coastguard Worker if (pe->is<FunctionDefinition>()) { 99*c8dee2aaSAndroid Build Coastguard Worker visitor.visitProgramElement(*pe); 100*c8dee2aaSAndroid Build Coastguard Worker } 101*c8dee2aaSAndroid Build Coastguard Worker } 102*c8dee2aaSAndroid Build Coastguard Worker } 103*c8dee2aaSAndroid Build Coastguard Worker } 104*c8dee2aaSAndroid Build Coastguard Worker 105*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkSL 106