Flutter Engine
The Flutter Engine
SkSLAnalysis.h
Go to the documentation of this file.
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 SkSLAnalysis_DEFINED
9#define SkSLAnalysis_DEFINED
10
13
14#include <cstdint>
15#include <memory>
16#include <vector>
17
18namespace SkSL {
19
20class Context;
21class ErrorReporter;
22class Expression;
23class FunctionDeclaration;
24class FunctionDefinition;
25class Position;
26class ProgramElement;
27class ProgramUsage;
28class Statement;
29class SymbolTable;
30class Variable;
31class VariableReference;
32enum class VariableRefKind : int8_t;
33struct ForLoopPositions;
34struct LoopUnrollInfo;
35struct Module;
36struct Program;
37
38/**
39 * Provides utilities for analyzing SkSL statically before it's composed into a full program.
40 */
41namespace Analysis {
42
43/**
44 * Determines how `program` samples `child`. By default, assumes that the sample coords might be
45 * modified, so `child.eval(sampleCoords)` is treated as Explicit. If writesToSampleCoords is false,
46 * treats that as PassThrough, instead. If elidedSampleCoordCount is provided, the pointed to value
47 * will be incremented by the number of sample calls where the above rewrite was performed.
48 */
49SampleUsage GetSampleUsage(const Program& program,
50 const Variable& child,
51 bool writesToSampleCoords = true,
52 int* elidedSampleCoordCount = nullptr);
53
54bool ReferencesBuiltin(const Program& program, int builtin);
55
56bool ReferencesSampleCoords(const Program& program);
57bool ReferencesFragCoords(const Program& program);
58
59bool CallsSampleOutsideMain(const Program& program);
60
61bool CallsColorTransformIntrinsics(const Program& program);
62
63/**
64 * Determines if `function` always returns an opaque color (a vec4 where the last component is known
65 * to be 1). This is conservative, and based on constant expression analysis.
66 */
67bool ReturnsOpaqueColor(const FunctionDefinition& function);
68
69/**
70 * Determines if `function` is a color filter which returns the alpha component of the input color
71 * unchanged. This is a very conservative analysis, and only supports returning a swizzle of the
72 * input color, or returning a constructor that ends with `input.a`.
73 */
74bool ReturnsInputAlpha(const FunctionDefinition& function, const ProgramUsage& usage);
75
76/**
77 * Checks for recursion or overly-deep function-call chains, and rejects programs which have them.
78 * Also, computes the size of the program in a completely flattened state--loops fully unrolled,
79 * function calls inlined--and rejects programs that exceed an arbitrary upper bound.
80 */
81bool CheckProgramStructure(const Program& program, bool enforceSizeLimit);
82
83/** Determines if `expr` contains a reference to the variable sk_RTAdjust. */
84bool ContainsRTAdjust(const Expression& expr);
85
86/** Determines if `expr` contains a reference to variable `var`. */
87bool ContainsVariable(const Expression& expr, const Variable& var);
88
89/** Determines if `expr` has any side effects. (Is the expression state-altering or pure?) */
90bool HasSideEffects(const Expression& expr);
91
92/** Determines if `expr` is a compile-time constant (composed of just constructors and literals). */
93bool IsCompileTimeConstant(const Expression& expr);
94
95/**
96 * Determines if `expr` is a dynamically-uniform expression; this returns true if the expression
97 * could be evaluated at compile time if uniform values were known.
98 */
99bool IsDynamicallyUniformExpression(const Expression& expr);
100
101/**
102 * Detect an orphaned variable declaration outside of a scope, e.g. if (true) int a;. Returns
103 * true if an error was reported.
104 */
105bool DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors = nullptr);
106
107int NodeCountUpToLimit(const FunctionDefinition& function, int limit);
108
109/**
110 * Finds unconditional exits from a switch-case. Returns true if this statement unconditionally
111 * causes an exit from this switch (via continue, break or return).
112 */
113bool SwitchCaseContainsUnconditionalExit(const Statement& stmt);
114
115/**
116 * Finds conditional exits from a switch-case. Returns true if this statement contains a
117 * conditional that wraps a potential exit from the switch (via continue, break or return).
118 */
119bool SwitchCaseContainsConditionalExit(const Statement& stmt);
120
121std::unique_ptr<ProgramUsage> GetUsage(const Program& program);
122std::unique_ptr<ProgramUsage> GetUsage(const Module& module);
123
124/** Returns true if the passed-in statement might alter `var`. */
125bool StatementWritesToVariable(const Statement& stmt, const Variable& var);
126
127/**
128 * Detects if the passed-in block contains a `continue`, `break` or `return` that could directly
129 * affect its control flow. (A `continue` or `break` nested inside an inner loop/switch will not
130 * affect the loop, but a `return` will.)
131 */
133 bool fHasContinue = false;
134 bool fHasBreak = false;
135 bool fHasReturn = false;
136};
138
139/**
140 * Returns true if the expression can be assigned-into. Pass `info` if you want to know the
141 * VariableReference that will be written to. Pass `errors` to report an error for expressions that
142 * are not actually writable.
143 */
146};
147bool IsAssignable(Expression& expr, AssignmentInfo* info = nullptr,
148 ErrorReporter* errors = nullptr);
149
150/**
151 * Updates the `refKind` field of the VariableReference at the top level of `expr`.
152 * If `expr` can be assigned to (`IsAssignable`), true is returned and no errors are reported.
153 * If not, false is returned. and an error is reported if `errors` is non-null.
154 */
156
157/**
158 * A "trivial" expression is one where we'd feel comfortable cloning it multiple times in
159 * the code, without worrying about incurring a performance penalty. Examples:
160 * - true
161 * - 3.14159265
162 * - myIntVariable
163 * - myColor.rgb
164 * - myArray[123]
165 * - myStruct.myField
166 * - half4(0)
167 * - !myBoolean
168 * - +myValue
169 * - -myValue
170 * - ~myInteger
171 *
172 * Trivial-ness is stackable. Somewhat large expressions can occasionally make the cut:
173 * - half4(myColor.a)
174 * - myStruct.myArrayField[7].xzy
175 */
176bool IsTrivialExpression(const Expression& expr);
177
178/**
179 * Returns true if both expression trees are the same. Used by the optimizer to look for self-
180 * assignment or self-comparison; won't necessarily catch complex cases. Rejects expressions
181 * that may cause side effects.
182 */
183bool IsSameExpressionTree(const Expression& left, const Expression& right);
184
185/**
186 * Returns true if expr is a constant-expression, as defined by GLSL 1.0, section 5.10.
187 * A constant expression is one of:
188 * - A literal value
189 * - A global or local variable qualified as 'const', excluding function parameters
190 * - An expression formed by an operator on operands that are constant expressions, including
191 * getting an element of a constant vector or a constant matrix, or a field of a constant
192 * structure
193 * - A constructor whose arguments are all constant expressions
194 * - A built-in function call whose arguments are all constant expressions, with the exception
195 * of the texture lookup functions
196 */
197bool IsConstantExpression(const Expression& expr);
198
199/**
200 * Ensures that any index-expressions inside of for-loops qualify as 'constant-index-expressions' as
201 * defined by GLSL 1.0, Appendix A, Section 5. A constant-index-expression is:
202 * - A constant-expression
203 * - Loop indices (as defined in Appendix A, Section 4)
204 * - Expressions composed of both of the above
205 */
207
208/**
209 * Emits an internal error if a VarDeclaration exists without a matching entry in the nearest
210 * SymbolTable.
211 */
212void CheckSymbolTableCorrectness(const Program& program);
213
214/**
215 * Ensures that a for-loop meets the strict requirements of The OpenGL ES Shading Language 1.00,
216 * Appendix A, Section 4.
217 * If the requirements are met, information about the loop's structure is returned.
218 * If the requirements are not met, the problem is reported via `errors` (if not nullptr), and
219 * null is returned.
220 * The loop test-expression may be altered by this check. For example, a loop like this:
221 * for (float x = 1.0; x != 0.0; x -= 0.01) {...}
222 * appears to be ES2-safe, but due to floating-point rounding error, it may not actually terminate.
223 * We rewrite the test condition to `x > 0.0` in order to ensure loop termination.
224 */
225std::unique_ptr<LoopUnrollInfo> GetLoopUnrollInfo(const Context& context,
227 const ForLoopPositions& positions,
228 const Statement* loopInitializer,
229 std::unique_ptr<Expression>* loopTestPtr,
230 const Expression* loopNext,
231 const Statement* loopStatement,
233
234/** Detects functions that fail to return a value on at least one path. */
235bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl, const Statement& body);
236
237/** Determines if a given function has multiple and/or early returns. */
242};
244
245/**
246 * Runs at finalization time to perform any last-minute correctness checks:
247 * - Reports dangling FunctionReference or TypeReference expressions
248 * - Reports function `out` params which are never written to (structs are currently exempt)
249 */
250void DoFinalizationChecks(const Program& program);
251
252/**
253 * Error checks compute shader in/outs and returns a vector containing them ordered by location.
254 */
256 const Program& program);
257
258/**
259 * Tracks the symbol table stack, in conjunction with a ProgramVisitor. Inside `visitStatement`,
260 * pass the current statement and a symbol-table vector to a SymbolTableStackBuilder and the symbol
261 * table stack will be maintained automatically.
262 */
264public:
265 // If the passed-in statement holds a symbol table, adds it to the stack.
266 SymbolTableStackBuilder(const Statement* stmt, std::vector<SymbolTable*>* stack);
267
268 // If a symbol table was added to the stack earlier, removes it from the stack.
270
271 // Returns true if an entry was added to the symbol-table stack.
273 return fStackToPop != nullptr;
274 }
275
276private:
277 std::vector<SymbolTable*>* fStackToPop = nullptr;
278};
279
280} // namespace Analysis
281} // namespace SkSL
282
283#endif
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkPoint pos
SymbolTableStackBuilder(const Statement *stmt, std::vector< SymbolTable * > *stack)
Dart_NativeFunction function
Definition: fuchsia.cc:51
bool IsCompileTimeConstant(const Expression &expr)
ReturnComplexity GetReturnComplexity(const FunctionDefinition &funcDef)
bool ContainsVariable(const Expression &expr, const Variable &var)
std::unique_ptr< LoopUnrollInfo > GetLoopUnrollInfo(const Context &context, Position pos, const ForLoopPositions &positions, const Statement *loopInitializer, std::unique_ptr< Expression > *loopTestPtr, const Expression *loopNext, const Statement *loopStatement, ErrorReporter *errors)
bool ContainsRTAdjust(const Expression &expr)
bool ReturnsOpaqueColor(const FunctionDefinition &function)
bool ReferencesBuiltin(const Program &program, int builtin)
bool IsConstantExpression(const Expression &expr)
bool ReferencesFragCoords(const Program &program)
void ValidateIndexingForES2(const ProgramElement &pe, ErrorReporter &errors)
SampleUsage GetSampleUsage(const Program &program, const Variable &child, bool writesToSampleCoords=true, int *elidedSampleCoordCount=nullptr)
LoopControlFlowInfo GetLoopControlFlowInfo(const Statement &stmt)
bool ReturnsInputAlpha(const FunctionDefinition &function, const ProgramUsage &usage)
int NodeCountUpToLimit(const FunctionDefinition &function, int limit)
bool IsSameExpressionTree(const Expression &left, const Expression &right)
bool CanExitWithoutReturningValue(const FunctionDeclaration &funcDecl, const Statement &body)
bool SwitchCaseContainsUnconditionalExit(const Statement &stmt)
bool IsTrivialExpression(const Expression &expr)
bool HasSideEffects(const Expression &expr)
skia_private::TArray< const SkSL::Variable * > GetComputeShaderMainParams(const Context &context, const Program &program)
bool ReferencesSampleCoords(const Program &program)
std::unique_ptr< ProgramUsage > GetUsage(const Program &program)
void CheckSymbolTableCorrectness(const Program &program)
bool DetectVarDeclarationWithoutScope(const Statement &stmt, ErrorReporter *errors=nullptr)
bool CallsColorTransformIntrinsics(const Program &program)
bool UpdateVariableRefKind(Expression *expr, VariableRefKind kind, ErrorReporter *errors=nullptr)
bool CheckProgramStructure(const Program &program, bool enforceSizeLimit)
void DoFinalizationChecks(const Program &program)
bool CallsSampleOutsideMain(const Program &program)
bool StatementWritesToVariable(const Statement &stmt, const Variable &var)
bool SwitchCaseContainsConditionalExit(const Statement &stmt)
bool IsAssignable(Expression &expr, AssignmentInfo *info=nullptr, ErrorReporter *errors=nullptr)
bool IsDynamicallyUniformExpression(const Expression &expr)
static void usage(char *argv0)
VariableReference * fAssignedVar
Definition: SkSLAnalysis.h:145