Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/sksl/SkSLInliner.h
Line
Count
Source
1
/*
2
 * Copyright 2020 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
#ifndef SKSL_INLINER
9
#define SKSL_INLINER
10
11
#ifndef SK_ENABLE_OPTIMIZE_SIZE
12
13
#include "src/core/SkTHash.h"
14
#include "src/sksl/SkSLContext.h"
15
#include "src/sksl/SkSLMangler.h"
16
#include "src/sksl/SkSLProgramSettings.h"
17
#include "src/sksl/ir/SkSLBlock.h"
18
#include "src/sksl/ir/SkSLExpression.h"
19
20
#include <memory>
21
#include <vector>
22
23
namespace SkSL {
24
25
class FunctionCall;
26
class FunctionDeclaration;
27
class FunctionDefinition;
28
class Position;
29
class ProgramElement;
30
class ProgramUsage;
31
class Statement;
32
class SymbolTable;
33
class Variable;
34
struct InlineCandidate;
35
struct InlineCandidateList;
36
namespace Analysis { enum class ReturnComplexity; }
37
38
/**
39
 * Converts a FunctionCall in the IR to a set of statements to be injected ahead of the function
40
 * call, and a replacement expression. Can also detect cases where inlining isn't cleanly possible
41
 * (e.g. return statements nested inside of a loop construct). The inliner isn't able to guarantee
42
 * identical-to-GLSL execution order if the inlined function has visible side effects.
43
 */
44
class Inliner {
45
public:
46
408
    Inliner(const Context* context) : fContext(context) {}
47
48
    /** Inlines any eligible functions that are found. Returns true if any changes are made. */
49
    bool analyze(const std::vector<std::unique_ptr<ProgramElement>>& elements,
50
                 SymbolTable* symbols,
51
                 ProgramUsage* usage);
52
53
private:
54
    using VariableRewriteMap = skia_private::THashMap<const Variable*, std::unique_ptr<Expression>>;
55
56
1.68k
    const ProgramSettings& settings() const { return fContext->fConfig->fSettings; }
57
58
    void buildCandidateList(const std::vector<std::unique_ptr<ProgramElement>>& elements,
59
                            SymbolTable* symbols,
60
                            ProgramUsage* usage,
61
                            InlineCandidateList* candidateList);
62
63
    std::unique_ptr<Expression> inlineExpression(Position pos,
64
                                                 VariableRewriteMap* varMap,
65
                                                 SymbolTable* symbolTableForExpression,
66
                                                 const Expression& expression);
67
    std::unique_ptr<Statement> inlineStatement(Position pos,
68
                                               VariableRewriteMap* varMap,
69
                                               SymbolTable* symbolTableForStatement,
70
                                               std::unique_ptr<Expression>* resultExpr,
71
                                               Analysis::ReturnComplexity returnComplexity,
72
                                               const Statement& statement,
73
                                               const ProgramUsage& usage,
74
                                               bool isBuiltinCode);
75
76
    /**
77
     * Searches the rewrite map for an rewritten Variable* for the passed-in one. Asserts if the
78
     * rewrite map doesn't contain the variable, or contains a different type of expression.
79
     */
80
    static const Variable* RemapVariable(const Variable* variable,
81
                                         const VariableRewriteMap* varMap);
82
83
    using InlinabilityCache = skia_private::THashMap<const FunctionDeclaration*, bool>;
84
    bool candidateCanBeInlined(const InlineCandidate& candidate,
85
                               const ProgramUsage& usage,
86
                               InlinabilityCache* cache);
87
88
    bool functionCanBeInlined(const FunctionDeclaration& funcDecl,
89
                              const ProgramUsage& usage,
90
                              InlinabilityCache* cache);
91
92
    using FunctionSizeCache = skia_private::THashMap<const FunctionDeclaration*, int>;
93
    int getFunctionSize(const FunctionDeclaration& fnDecl, FunctionSizeCache* cache);
94
95
    /**
96
     * Processes the passed-in FunctionCall expression. The FunctionCall expression should be
97
     * replaced with `fReplacementExpr`. If non-null, `fInlinedBody` should be inserted immediately
98
     * above the statement containing the inlined expression.
99
     */
100
    struct InlinedCall {
101
        std::unique_ptr<Block> fInlinedBody;
102
        std::unique_ptr<Expression> fReplacementExpr;
103
    };
104
    InlinedCall inlineCall(const FunctionCall&,
105
                           SymbolTable*,
106
                           const ProgramUsage&,
107
                           const FunctionDeclaration* caller);
108
109
    /** Adds a scope to inlined bodies returned by `inlineCall`, if one is required. */
110
    void ensureScopedBlocks(Statement* inlinedBody, Statement* parentStmt);
111
112
    /** Checks whether inlining is viable for a FunctionCall, modulo recursion and function size. */
113
    bool isSafeToInline(const FunctionDefinition* functionDef, const ProgramUsage& usage);
114
115
    const Context* fContext = nullptr;
116
    Mangler fMangler;
117
    int fInlinedStatementCounter = 0;
118
};
119
120
}  // namespace SkSL
121
122
#endif  // SK_ENABLE_OPTIMIZE_SIZE
123
124
#endif  // SKSL_INLINER