diff options
Diffstat (limited to 'gfx/skia/skia/src/sksl/SkSLInliner.h')
-rw-r--r-- | gfx/skia/skia/src/sksl/SkSLInliner.h | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/sksl/SkSLInliner.h b/gfx/skia/skia/src/sksl/SkSLInliner.h new file mode 100644 index 0000000000..618365baf0 --- /dev/null +++ b/gfx/skia/skia/src/sksl/SkSLInliner.h @@ -0,0 +1,119 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SKSL_INLINER +#define SKSL_INLINER + +#ifndef SK_ENABLE_OPTIMIZE_SIZE + +#include "src/core/SkTHash.h" +#include "src/sksl/SkSLContext.h" +#include "src/sksl/SkSLMangler.h" +#include "src/sksl/SkSLProgramSettings.h" +#include "src/sksl/ir/SkSLBlock.h" +#include "src/sksl/ir/SkSLExpression.h" + +#include <memory> +#include <vector> + +namespace SkSL { + +class FunctionCall; +class FunctionDeclaration; +class FunctionDefinition; +class Position; +class ProgramElement; +class ProgramUsage; +class Statement; +class SymbolTable; +class Variable; +struct InlineCandidate; +struct InlineCandidateList; +namespace Analysis { enum class ReturnComplexity; } + +/** + * Converts a FunctionCall in the IR to a set of statements to be injected ahead of the function + * call, and a replacement expression. Can also detect cases where inlining isn't cleanly possible + * (e.g. return statements nested inside of a loop construct). The inliner isn't able to guarantee + * identical-to-GLSL execution order if the inlined function has visible side effects. + */ +class Inliner { +public: + Inliner(const Context* context) : fContext(context) {} + + /** Inlines any eligible functions that are found. Returns true if any changes are made. */ + bool analyze(const std::vector<std::unique_ptr<ProgramElement>>& elements, + std::shared_ptr<SymbolTable> symbols, + ProgramUsage* usage); + +private: + using VariableRewriteMap = SkTHashMap<const Variable*, std::unique_ptr<Expression>>; + + const ProgramSettings& settings() const { return fContext->fConfig->fSettings; } + + void buildCandidateList(const std::vector<std::unique_ptr<ProgramElement>>& elements, + std::shared_ptr<SymbolTable> symbols, ProgramUsage* usage, + InlineCandidateList* candidateList); + + std::unique_ptr<Expression> inlineExpression(Position pos, + VariableRewriteMap* varMap, + SymbolTable* symbolTableForExpression, + const Expression& expression); + std::unique_ptr<Statement> inlineStatement(Position pos, + VariableRewriteMap* varMap, + SymbolTable* symbolTableForStatement, + std::unique_ptr<Expression>* resultExpr, + Analysis::ReturnComplexity returnComplexity, + const Statement& statement, + const ProgramUsage& usage, + bool isBuiltinCode); + + /** + * Searches the rewrite map for an rewritten Variable* for the passed-in one. Asserts if the + * rewrite map doesn't contain the variable, or contains a different type of expression. + */ + static const Variable* RemapVariable(const Variable* variable, + const VariableRewriteMap* varMap); + + using InlinabilityCache = SkTHashMap<const FunctionDeclaration*, bool>; + bool candidateCanBeInlined(const InlineCandidate& candidate, + const ProgramUsage& usage, + InlinabilityCache* cache); + + using FunctionSizeCache = SkTHashMap<const FunctionDeclaration*, int>; + int getFunctionSize(const FunctionDeclaration& fnDecl, FunctionSizeCache* cache); + + /** + * Processes the passed-in FunctionCall expression. The FunctionCall expression should be + * replaced with `fReplacementExpr`. If non-null, `fInlinedBody` should be inserted immediately + * above the statement containing the inlined expression. + */ + struct InlinedCall { + std::unique_ptr<Block> fInlinedBody; + std::unique_ptr<Expression> fReplacementExpr; + }; + InlinedCall inlineCall(const FunctionCall&, + std::shared_ptr<SymbolTable>, + const ProgramUsage&, + const FunctionDeclaration* caller); + + /** Adds a scope to inlined bodies returned by `inlineCall`, if one is required. */ + void ensureScopedBlocks(Statement* inlinedBody, Statement* parentStmt); + + /** Checks whether inlining is viable for a FunctionCall, modulo recursion and function size. */ + bool isSafeToInline(const FunctionDefinition* functionDef, const ProgramUsage& usage); + + const Context* fContext = nullptr; + Mangler fMangler; + int fInlinedStatementCounter = 0; +}; + +} // namespace SkSL + +#endif // SK_ENABLE_OPTIMIZE_SIZE + +#endif // SKSL_INLINER |