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