• 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 bool CallsColorTransformIntrinsics(const Program& program);
60 
61 /**
62  * Determines if `function` always returns an opaque color (a vec4 where the last component is known
63  * to be 1). This is conservative, and based on constant expression analysis.
64  */
65 bool ReturnsOpaqueColor(const FunctionDefinition& function);
66 
67 /**
68  * Computes the size of the program in a completely flattened state--loops fully unrolled,
69  * function calls inlined--and rejects programs that exceed an arbitrary upper bound. This is
70  * intended to prevent absurdly large programs from overwhemling SkVM. Only strict-ES2 mode is
71  * supported; complex control flow is not SkVM-compatible (and this becomes the halting problem)
72  */
73 bool CheckProgramUnrolledSize(const Program& program);
74 
75 /**
76  * Detect an orphaned variable declaration outside of a scope, e.g. if (true) int a;. Returns
77  * true if an error was reported.
78  */
79 bool DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors = nullptr);
80 
81 int NodeCountUpToLimit(const FunctionDefinition& function, int limit);
82 
83 /**
84  * Finds unconditional exits from a switch-case. Returns true if this statement unconditionally
85  * causes an exit from this switch (via continue, break or return).
86  */
87 bool SwitchCaseContainsUnconditionalExit(Statement& stmt);
88 
89 /**
90  * Finds conditional exits from a switch-case. Returns true if this statement contains a
91  * conditional that wraps a potential exit from the switch (via continue, break or return).
92  */
93 bool SwitchCaseContainsConditionalExit(Statement& stmt);
94 
95 std::unique_ptr<ProgramUsage> GetUsage(const Program& program);
96 std::unique_ptr<ProgramUsage> GetUsage(const LoadedModule& module);
97 
98 bool StatementWritesToVariable(const Statement& stmt, const Variable& var);
99 
100 struct AssignmentInfo {
101     VariableReference* fAssignedVar = nullptr;
102 };
103 bool IsAssignable(Expression& expr, AssignmentInfo* info = nullptr,
104                   ErrorReporter* errors = nullptr);
105 
106 /**
107  * Updates the `refKind` field of the VariableReference at the top level of `expr`.
108  * If `expr` can be assigned to (`IsAssignable`), true is returned and no errors are reported.
109  * If not, false is returned. and an error is reported if `errors` is non-null.
110  */
111 bool UpdateVariableRefKind(Expression* expr, VariableRefKind kind, ErrorReporter* errors = nullptr);
112 
113 /**
114  * A "trivial" expression is one where we'd feel comfortable cloning it multiple times in
115  * the code, without worrying about incurring a performance penalty. Examples:
116  * - true
117  * - 3.14159265
118  * - myIntVariable
119  * - myColor.rgb
120  * - myArray[123]
121  * - myStruct.myField
122  * - half4(0)
123  *
124  * Trivial-ness is stackable. Somewhat large expressions can occasionally make the cut:
125  * - half4(myColor.a)
126  * - myStruct.myArrayField[7].xyz
127  */
128 bool IsTrivialExpression(const Expression& expr);
129 
130 /**
131  * Returns true if both expression trees are the same. Used by the optimizer to look for self-
132  * assignment or self-comparison; won't necessarily catch complex cases. Rejects expressions
133  * that may cause side effects.
134  */
135 bool IsSameExpressionTree(const Expression& left, const Expression& right);
136 
137 /**
138  * Returns true if expr is a constant-expression, as defined by GLSL 1.0, section 5.10.
139  * A constant expression is one of:
140  * - A literal value
141  * - A global or local variable qualified as 'const', excluding function parameters
142  * - An expression formed by an operator on operands that are constant expressions, including
143  *   getting an element of a constant vector or a constant matrix, or a field of a constant
144  *   structure
145  * - A constructor whose arguments are all constant expressions
146  * - A built-in function call whose arguments are all constant expressions, with the exception
147  *   of the texture lookup functions
148  */
149 bool IsConstantExpression(const Expression& expr);
150 
151 /**
152  * Returns true if expr is a valid constant-index-expression, as defined by GLSL 1.0, Appendix A,
153  * Section 5. A constant-index-expression is:
154  * - A constant-expression
155  * - Loop indices (as defined in Appendix A, Section 4)
156  * - Expressions composed of both of the above
157  */
158 bool IsConstantIndexExpression(const Expression& expr,
159                                const std::set<const Variable*>* loopIndices);
160 
161 /**
162  * Ensures that a for-loop meets the strict requirements of The OpenGL ES Shading Language 1.00,
163  * Appendix A, Section 4.
164  * If the requirements are met, information about the loop's structure is returned.
165  * If the requirements are not met, the problem is reported via `errors` (if not nullptr), and
166  * null is returned.
167  */
168 std::unique_ptr<LoopUnrollInfo> GetLoopUnrollInfo(int line,
169                                                   const Statement* loopInitializer,
170                                                   const Expression* loopTest,
171                                                   const Expression* loopNext,
172                                                   const Statement* loopStatement,
173                                                   ErrorReporter* errors);
174 
175 void ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors);
176 
177 /** Detects functions that fail to return a value on at least one path. */
178 bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl, const Statement& body);
179 
180 /**
181  * Runs at finalization time to perform any last-minute correctness checks:
182  * - Reports @if/@switch statements that didn't optimize away
183  * - Reports dangling FunctionReference or TypeReference expressions
184  * - Reports function `out` params which are never written to (structs are currently exempt)
185  */
186 void DoFinalizationChecks(const Program& program);
187 
188 }  // namespace Analysis
189 }  // namespace SkSL
190 
191 #endif
192