/src/skia/src/sksl/transform/SkSLReplaceConstVarsWithLiterals.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
32 | 0 | void Transform::ReplaceConstVarsWithLiterals(Module& module, ProgramUsage* usage) { |
33 | 0 | class ConstVarReplacer : public ProgramWriter { |
34 | 0 | public: |
35 | 0 | ConstVarReplacer(ProgramUsage* usage) : fUsage(usage) {} |
36 | |
|
37 | 0 | using ProgramWriter::visitProgramElement; |
38 | |
|
39 | 0 | bool visitExpressionPtr(std::unique_ptr<Expression>& expr) override { |
40 | | // If this is a variable... |
41 | 0 | if (expr->is<VariableReference>()) { |
42 | 0 | VariableReference& var = expr->as<VariableReference>(); |
43 | | // ... and it's a candidate for size reduction... |
44 | 0 | if (fCandidates.contains(var.variable())) { |
45 | | // ... get its constant value... |
46 | 0 | if (const Expression* value = ConstantFolder::GetConstantValueOrNull(var)) { |
47 | | // ... and replace it with that value. |
48 | 0 | fUsage->remove(expr.get()); |
49 | 0 | expr = value->clone(); |
50 | 0 | fUsage->add(expr.get()); |
51 | 0 | return false; |
52 | 0 | } |
53 | 0 | } |
54 | 0 | } |
55 | 0 | return INHERITED::visitExpressionPtr(expr); |
56 | 0 | } |
57 | |
|
58 | 0 | ProgramUsage* fUsage; |
59 | 0 | THashSet<const Variable*> fCandidates; |
60 | |
|
61 | 0 | using INHERITED = ProgramWriter; |
62 | 0 | }; |
63 | |
|
64 | 0 | ConstVarReplacer visitor{usage}; |
65 | |
|
66 | 0 | for (const auto& [var, count] : usage->fVariableCounts) { |
67 | | // We can only replace const variables that still exist, and that have initial values. |
68 | 0 | if (!count.fVarExists || count.fWrite != 1) { |
69 | 0 | continue; |
70 | 0 | } |
71 | 0 | if (!var->modifierFlags().isConst()) { |
72 | 0 | continue; |
73 | 0 | } |
74 | 0 | if (!var->initialValue()) { |
75 | 0 | continue; |
76 | 0 | } |
77 | | // The current size is: |
78 | | // strlen("const type varname=initialvalue;`") + count*strlen("varname"). |
79 | 0 | size_t initialvalueSize = ConstantFolder::GetConstantValueForVariable(*var->initialValue()) |
80 | 0 | ->description() |
81 | 0 | .size(); |
82 | 0 | size_t totalOldSize = var->description().size() + // const type varname |
83 | 0 | 1 + // = |
84 | 0 | initialvalueSize + // initialvalue |
85 | 0 | 1 + // ; |
86 | 0 | 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 | 0 | size_t totalNewSize = count.fRead * initialvalueSize; // count * initialvalue |
90 | |
|
91 | 0 | if (totalNewSize <= totalOldSize) { |
92 | 0 | visitor.fCandidates.add(var); |
93 | 0 | } |
94 | 0 | } |
95 | |
|
96 | 0 | if (!visitor.fCandidates.empty()) { |
97 | 0 | for (std::unique_ptr<ProgramElement>& pe : module.fElements) { |
98 | 0 | if (pe->is<FunctionDefinition>()) { |
99 | 0 | visitor.visitProgramElement(*pe); |
100 | 0 | } |
101 | 0 | } |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | | } // namespace SkSL |