2 * Copyright 2020 Google LLC
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SkSLAnalysis_DEFINED
9 #define SkSLAnalysis_DEFINED
11 #include "include/private/SkSLSampleUsage.h"
21 class FunctionDeclaration;
22 class FunctionDefinition;
28 class VariableReference;
29 enum class VariableRefKind : int8_t;
30 struct ForLoopPositions;
32 struct LoopUnrollInfo;
37 * Provides utilities for analyzing SkSL statically before it's composed into a full program.
42 * Determines how `program` samples `child`. By default, assumes that the sample coords
43 * (SK_MAIN_COORDS_BUILTIN) might be modified, so `child.eval(sampleCoords)` is treated as
44 * Explicit. If writesToSampleCoords is false, treats that as PassThrough, instead.
45 * If elidedSampleCoordCount is provided, the pointed to value will be incremented by the
46 * number of sample calls where the above rewrite was performed.
48 SampleUsage GetSampleUsage(const Program& program,
49 const Variable& child,
50 bool writesToSampleCoords = true,
51 int* elidedSampleCoordCount = nullptr);
53 bool ReferencesBuiltin(const Program& program, int builtin);
55 bool ReferencesSampleCoords(const Program& program);
56 bool ReferencesFragCoords(const Program& program);
58 bool CallsSampleOutsideMain(const Program& program);
60 bool CallsColorTransformIntrinsics(const Program& program);
63 * Determines if `function` always returns an opaque color (a vec4 where the last component is known
64 * to be 1). This is conservative, and based on constant expression analysis.
66 bool ReturnsOpaqueColor(const FunctionDefinition& function);
69 * Checks for recursion or overly-deep function-call chains, and rejects programs which have them.
70 * Also, computes the size of the program in a completely flattened state--loops fully unrolled,
71 * function calls inlined--and rejects programs that exceed an arbitrary upper bound. This is
72 * intended to prevent absurdly large programs from overwhemling SkVM. Only strict-ES2 mode is
73 * supported; complex control flow is not SkVM-compatible (and this becomes the halting problem)
75 bool CheckProgramStructure(const Program& program, bool enforceSizeLimit);
78 * Detect an orphaned variable declaration outside of a scope, e.g. if (true) int a;. Returns
79 * true if an error was reported.
81 bool DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors = nullptr);
83 int NodeCountUpToLimit(const FunctionDefinition& function, int limit);
86 * Finds unconditional exits from a switch-case. Returns true if this statement unconditionally
87 * causes an exit from this switch (via continue, break or return).
89 bool SwitchCaseContainsUnconditionalExit(Statement& stmt);
92 * Finds conditional exits from a switch-case. Returns true if this statement contains a
93 * conditional that wraps a potential exit from the switch (via continue, break or return).
95 bool SwitchCaseContainsConditionalExit(Statement& stmt);
97 std::unique_ptr<ProgramUsage> GetUsage(const Program& program);
98 std::unique_ptr<ProgramUsage> GetUsage(const LoadedModule& module, const ParsedModule& base);
100 bool StatementWritesToVariable(const Statement& stmt, const Variable& var);
102 struct AssignmentInfo {
103 VariableReference* fAssignedVar = nullptr;
105 bool IsAssignable(Expression& expr, AssignmentInfo* info = nullptr,
106 ErrorReporter* errors = nullptr);
109 * Updates the `refKind` field of the VariableReference at the top level of `expr`.
110 * If `expr` can be assigned to (`IsAssignable`), true is returned and no errors are reported.
111 * If not, false is returned. and an error is reported if `errors` is non-null.
113 bool UpdateVariableRefKind(Expression* expr, VariableRefKind kind, ErrorReporter* errors = nullptr);
116 * A "trivial" expression is one where we'd feel comfortable cloning it multiple times in
117 * the code, without worrying about incurring a performance penalty. Examples:
126 * Trivial-ness is stackable. Somewhat large expressions can occasionally make the cut:
128 * - myStruct.myArrayField[7].xyz
130 bool IsTrivialExpression(const Expression& expr);
133 * Returns true if both expression trees are the same. Used by the optimizer to look for self-
134 * assignment or self-comparison; won't necessarily catch complex cases. Rejects expressions
135 * that may cause side effects.
137 bool IsSameExpressionTree(const Expression& left, const Expression& right);
140 * Returns true if expr is a constant-expression, as defined by GLSL 1.0, section 5.10.
141 * A constant expression is one of:
143 * - A global or local variable qualified as 'const', excluding function parameters
144 * - An expression formed by an operator on operands that are constant expressions, including
145 * getting an element of a constant vector or a constant matrix, or a field of a constant
147 * - A constructor whose arguments are all constant expressions
148 * - A built-in function call whose arguments are all constant expressions, with the exception
149 * of the texture lookup functions
151 bool IsConstantExpression(const Expression& expr);
154 * Returns true if expr is a valid constant-index-expression, as defined by GLSL 1.0, Appendix A,
155 * Section 5. A constant-index-expression is:
156 * - A constant-expression
157 * - Loop indices (as defined in Appendix A, Section 4)
158 * - Expressions composed of both of the above
160 bool IsConstantIndexExpression(const Expression& expr,
161 const std::set<const Variable*>* loopIndices);
164 * Ensures that a for-loop meets the strict requirements of The OpenGL ES Shading Language 1.00,
165 * Appendix A, Section 4.
166 * If the requirements are met, information about the loop's structure is returned.
167 * If the requirements are not met, the problem is reported via `errors` (if not nullptr), and
170 std::unique_ptr<LoopUnrollInfo> GetLoopUnrollInfo(Position pos,
171 const ForLoopPositions& positions,
172 const Statement* loopInitializer,
173 const Expression* loopTest,
174 const Expression* loopNext,
175 const Statement* loopStatement,
176 ErrorReporter* errors);
178 void ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors);
180 /** Detects functions that fail to return a value on at least one path. */
181 bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl, const Statement& body);
184 * Runs at finalization time to perform any last-minute correctness checks:
185 * - Reports @if/@switch statements that didn't optimize away
186 * - Reports dangling FunctionReference or TypeReference expressions
187 * - Reports function `out` params which are never written to (structs are currently exempt)
189 void DoFinalizationChecks(const Program& program);
191 } // namespace Analysis