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