/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 |