2020-08-31 17:16:04 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
#include "src/sksl/ir/SkSLProgram.h"
|
2020-09-22 16:05:16 +00:00
|
|
|
#include "src/sksl/ir/SkSLVariableReference.h"
|
2020-08-31 17:16:04 +00:00
|
|
|
|
|
|
|
namespace SkSL {
|
|
|
|
|
2020-09-25 18:31:59 +00:00
|
|
|
class Block;
|
2020-08-31 17:16:04 +00:00
|
|
|
class Context;
|
2020-10-08 09:28:32 +00:00
|
|
|
class Expression;
|
|
|
|
class FunctionCall;
|
2020-10-26 19:06:46 +00:00
|
|
|
class FunctionDefinition;
|
2020-10-02 19:01:03 +00:00
|
|
|
struct InlineCandidate;
|
|
|
|
struct InlineCandidateList;
|
2020-10-07 20:42:04 +00:00
|
|
|
class ModifiersPool;
|
2020-10-08 09:28:32 +00:00
|
|
|
class Statement;
|
2020-08-31 17:16:04 +00:00
|
|
|
class SymbolTable;
|
2020-10-07 20:42:04 +00:00
|
|
|
class Variable;
|
2020-08-31 17:16:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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:
|
2020-11-18 20:38:39 +00:00
|
|
|
Inliner(const Context* context, const ShaderCapsClass* caps) : fContext(context), fCaps(caps) {}
|
2020-08-31 17:16:04 +00:00
|
|
|
|
2020-11-18 20:38:39 +00:00
|
|
|
void reset(ModifiersPool* modifiers, const Program::Settings*);
|
2020-08-31 17:16:04 +00:00
|
|
|
|
2020-09-14 13:38:13 +00:00
|
|
|
/** Inlines any eligible functions that are found. Returns true if any changes are made. */
|
2020-11-18 20:38:39 +00:00
|
|
|
bool analyze(const std::vector<std::unique_ptr<ProgramElement>>& elements,
|
|
|
|
SymbolTable* symbols,
|
|
|
|
ProgramUsage* usage);
|
2020-09-11 16:11:27 +00:00
|
|
|
|
2020-08-31 17:16:04 +00:00
|
|
|
private:
|
2020-09-28 16:28:16 +00:00
|
|
|
using VariableRewriteMap = std::unordered_map<const Variable*, std::unique_ptr<Expression>>;
|
2020-08-31 17:16:04 +00:00
|
|
|
|
2020-09-14 22:24:12 +00:00
|
|
|
String uniqueNameForInlineVar(const String& baseName, SymbolTable* symbolTable);
|
|
|
|
|
2020-11-18 20:38:39 +00:00
|
|
|
void buildCandidateList(const std::vector<std::unique_ptr<ProgramElement>>& elements,
|
2020-11-23 19:48:06 +00:00
|
|
|
SymbolTable* symbols, ProgramUsage* usage,
|
2020-11-18 20:38:39 +00:00
|
|
|
InlineCandidateList* candidateList);
|
2020-10-02 19:01:03 +00:00
|
|
|
|
2020-08-31 17:16:04 +00:00
|
|
|
std::unique_ptr<Expression> inlineExpression(int offset,
|
|
|
|
VariableRewriteMap* varMap,
|
2020-11-30 17:24:27 +00:00
|
|
|
SymbolTable* symbolTableForExpression,
|
2020-08-31 17:16:04 +00:00
|
|
|
const Expression& expression);
|
|
|
|
std::unique_ptr<Statement> inlineStatement(int offset,
|
|
|
|
VariableRewriteMap* varMap,
|
|
|
|
SymbolTable* symbolTableForStatement,
|
2020-09-28 16:28:16 +00:00
|
|
|
const Expression* resultExpr,
|
2020-08-31 17:16:04 +00:00
|
|
|
bool haveEarlyReturns,
|
2020-09-30 17:22:27 +00:00
|
|
|
const Statement& statement,
|
|
|
|
bool isBuiltinCode);
|
2020-08-31 17:16:04 +00:00
|
|
|
|
2020-10-02 19:01:03 +00:00
|
|
|
using InlinabilityCache = std::unordered_map<const FunctionDeclaration*, bool>;
|
|
|
|
bool candidateCanBeInlined(const InlineCandidate& candidate, InlinabilityCache* cache);
|
|
|
|
|
2020-11-23 19:48:06 +00:00
|
|
|
using FunctionSizeCache = std::unordered_map<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(FunctionCall*, SymbolTable*, 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);
|
2020-10-02 19:01:03 +00:00
|
|
|
|
2020-08-31 17:16:04 +00:00
|
|
|
const Context* fContext = nullptr;
|
2020-10-07 20:42:04 +00:00
|
|
|
ModifiersPool* fModifiers = nullptr;
|
2020-08-31 17:16:04 +00:00
|
|
|
const Program::Settings* fSettings = nullptr;
|
2020-11-02 17:26:22 +00:00
|
|
|
const ShaderCapsClass* fCaps = nullptr;
|
2020-08-31 17:16:04 +00:00
|
|
|
int fInlineVarCounter = 0;
|
2020-11-13 21:13:18 +00:00
|
|
|
int fInlinedStatementCounter = 0;
|
2020-08-31 17:16:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace SkSL
|
|
|
|
|
|
|
|
#endif // SKSL_INLINER
|