• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 #include "include/core/SkSpan.h"
12 #include "include/private/SkSLDefines.h"
13 #include "include/private/SkSLSampleUsage.h"
14 
15 #include <memory>
16 #include <set>
17 
18 namespace SkSL {
19 
20 class ErrorReporter;
21 class Expression;
22 class ForStatement;
23 class FunctionDeclaration;
24 class FunctionDefinition;
25 struct LoadedModule;
26 struct Program;
27 class ProgramElement;
28 class ProgramUsage;
29 class Statement;
30 struct LoopUnrollInfo;
31 class Variable;
32 class VariableReference;
33 enum class VariableRefKind : int8_t;
34 
35 /**
36  * Provides utilities for analyzing SkSL statically before it's composed into a full program.
37  */
38 namespace Analysis {
39 
40 /**
41  * Determines how `program` samples `child`. By default, assumes that the sample coords
42  * (SK_MAIN_COORDS_BUILTIN) might be modified, so `child.eval(sampleCoords)` is treated as
43  * Explicit. If writesToSampleCoords is false, treats that as PassThrough, instead.
44  * If elidedSampleCoordCount is provided, the pointed to value will be incremented by the
45  * number of sample calls where the above rewrite was performed.
46  */
47 SampleUsage GetSampleUsage(const Program& program,
48                            const Variable& child,
49                            bool writesToSampleCoords = true,
50                            int* elidedSampleCoordCount = nullptr);
51 
52 bool ReferencesBuiltin(const Program& program, int builtin);
53 
54 bool ReferencesSampleCoords(const Program& program);
55 bool ReferencesFragCoords(const Program& program);
56 
57 bool CallsSampleOutsideMain(const Program& program);
58 
59 /**
60  * Computes the size of the program in a completely flattened state--loops fully unrolled,
61  * function calls inlined--and rejects programs that exceed an arbitrary upper bound. This is
62  * intended to prevent absurdly large programs from overwhemling SkVM. Only strict-ES2 mode is
63  * supported; complex control flow is not SkVM-compatible (and this becomes the halting problem)
64  */
65 bool CheckProgramUnrolledSize(const Program& program);
66 
67 /**
68  * Detect an orphaned variable declaration outside of a scope, e.g. if (true) int a;. Returns
69  * true if an error was reported.
70  */
71 bool DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors = nullptr);
72 
73 int NodeCountUpToLimit(const FunctionDefinition& function, int limit);
74 
75 /**
76  * Finds unconditional exits from a switch-case. Returns true if this statement unconditionally
77  * causes an exit from this switch (via continue, break or return).
78  */
79 bool SwitchCaseContainsUnconditionalExit(Statement& stmt);
80 
81 /**
82  * Finds conditional exits from a switch-case. Returns true if this statement contains a
83  * conditional that wraps a potential exit from the switch (via continue, break or return).
84  */
85 bool SwitchCaseContainsConditionalExit(Statement& stmt);
86 
87 std::unique_ptr<ProgramUsage> GetUsage(const Program& program);
88 std::unique_ptr<ProgramUsage> GetUsage(const LoadedModule& module);
89 
90 bool StatementWritesToVariable(const Statement& stmt, const Variable& var);
91 
92 struct AssignmentInfo {
93     VariableReference* fAssignedVar = nullptr;
94 };
95 bool IsAssignable(Expression& expr, AssignmentInfo* info = nullptr,
96                   ErrorReporter* errors = nullptr);
97 
98 /**
99  * Updates the `refKind` field of the VariableReference at the top level of `expr`.
100  * If `expr` can be assigned to (`IsAssignable`), true is returned and no errors are reported.
101  * If not, false is returned. and an error is reported if `errors` is non-null.
102  */
103 bool UpdateVariableRefKind(Expression* expr, VariableRefKind kind, ErrorReporter* errors = nullptr);
104 
105 /**
106  * A "trivial" expression is one where we'd feel comfortable cloning it multiple times in
107  * the code, without worrying about incurring a performance penalty. Examples:
108  * - true
109  * - 3.14159265
110  * - myIntVariable
111  * - myColor.rgb
112  * - myArray[123]
113  * - myStruct.myField
114  * - half4(0)
115  *
116  * Trivial-ness is stackable. Somewhat large expressions can occasionally make the cut:
117  * - half4(myColor.a)
118  * - myStruct.myArrayField[7].xyz
119  */
120 bool IsTrivialExpression(const Expression& expr);
121 
122 /**
123  * Returns true if both expression trees are the same. Used by the optimizer to look for self-
124  * assignment or self-comparison; won't necessarily catch complex cases. Rejects expressions
125  * that may cause side effects.
126  */
127 bool IsSameExpressionTree(const Expression& left, const Expression& right);
128 
129 /**
130  * Returns true if expr is a constant-expression, as defined by GLSL 1.0, section 5.10.
131  * A constant expression is one of:
132  * - A literal value
133  * - A global or local variable qualified as 'const', excluding function parameters
134  * - An expression formed by an operator on operands that are constant expressions, including
135  *   getting an element of a constant vector or a constant matrix, or a field of a constant
136  *   structure
137  * - A constructor whose arguments are all constant expressions
138  * - A built-in function call whose arguments are all constant expressions, with the exception
139  *   of the texture lookup functions
140  */
141 bool IsConstantExpression(const Expression& expr);
142 
143 /**
144  * Returns true if expr is a valid constant-index-expression, as defined by GLSL 1.0, Appendix A,
145  * Section 5. A constant-index-expression is:
146  * - A constant-expression
147  * - Loop indices (as defined in Appendix A, Section 4)
148  * - Expressions composed of both of the above
149  */
150 bool IsConstantIndexExpression(const Expression& expr,
151                                const std::set<const Variable*>* loopIndices);
152 
153 /**
154  * Ensures that a for-loop meets the strict requirements of The OpenGL ES Shading Language 1.00,
155  * Appendix A, Section 4.
156  * If the requirements are met, information about the loop's structure is returned.
157  * If the requirements are not met, the problem is reported via `errors` (if not nullptr), and
158  * null is returned.
159  */
160 std::unique_ptr<LoopUnrollInfo> GetLoopUnrollInfo(int line,
161                                                   const Statement* loopInitializer,
162                                                   const Expression* loopTest,
163                                                   const Expression* loopNext,
164                                                   const Statement* loopStatement,
165                                                   ErrorReporter* errors);
166 
167 void ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors);
168 
169 /** Detects functions that fail to return a value on at least one path. */
170 bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl, const Statement& body);
171 
172 /**
173  * Searches for @if/@switch statements that didn't optimize away, or dangling
174  * FunctionReference or TypeReference expressions, and reports them as errors.
175  */
176 void VerifyStaticTestsAndExpressions(const Program& program);
177 
178 }  // namespace Analysis
179 }  // namespace SkSL
180 
181 #endif
182