Coverage Report

Created: 2024-09-14 07:19

/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