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