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