1 /* 2 * Copyright 2021 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 #include "include/private/SkSLStatement.h" 9 #include "src/sksl/SkSLAnalysis.h" 10 #include "src/sksl/analysis/SkSLProgramVisitor.h" 11 #include "src/sksl/ir/SkSLDoStatement.h" 12 #include "src/sksl/ir/SkSLForStatement.h" 13 #include "src/sksl/ir/SkSLFunctionDeclaration.h" 14 #include "src/sksl/ir/SkSLIfStatement.h" 15 #include "src/sksl/ir/SkSLSwitchStatement.h" 16 17 namespace SkSL { 18 19 // Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules 20 // (if loopIndices is non-nullptr) 21 class ConstantExpressionVisitor : public ProgramVisitor { 22 public: ConstantExpressionVisitor(const std::set<const Variable * > * loopIndices)23 ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices) 24 : fLoopIndices(loopIndices) {} 25 visitExpression(const Expression & e)26 bool visitExpression(const Expression& e) override { 27 // A constant-(index)-expression is one of... 28 switch (e.kind()) { 29 // ... a literal value 30 case Expression::Kind::kLiteral: 31 return false; 32 33 // ... settings can appear in fragment processors; they will resolve when compiled 34 case Expression::Kind::kSetting: 35 return false; 36 37 // ... a global or local variable qualified as 'const', excluding function parameters. 38 // ... loop indices as defined in section 4. [constant-index-expression] 39 case Expression::Kind::kVariableReference: { 40 const Variable* v = e.as<VariableReference>().variable(); 41 if ((v->storage() == Variable::Storage::kGlobal || 42 v->storage() == Variable::Storage::kLocal) && 43 (v->modifiers().fFlags & Modifiers::kConst_Flag)) { 44 return false; 45 } 46 return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end(); 47 } 48 49 // ... expressions composed of both of the above 50 case Expression::Kind::kBinary: 51 case Expression::Kind::kConstructorArray: 52 case Expression::Kind::kConstructorArrayCast: 53 case Expression::Kind::kConstructorCompound: 54 case Expression::Kind::kConstructorCompoundCast: 55 case Expression::Kind::kConstructorDiagonalMatrix: 56 case Expression::Kind::kConstructorMatrixResize: 57 case Expression::Kind::kConstructorScalarCast: 58 case Expression::Kind::kConstructorSplat: 59 case Expression::Kind::kConstructorStruct: 60 case Expression::Kind::kFieldAccess: 61 case Expression::Kind::kIndex: 62 case Expression::Kind::kPrefix: 63 case Expression::Kind::kPostfix: 64 case Expression::Kind::kSwizzle: 65 case Expression::Kind::kTernary: 66 return INHERITED::visitExpression(e); 67 68 // Function calls are completely disallowed in SkSL constant-(index)-expressions. 69 // GLSL does mandate that calling a built-in function where the arguments are all 70 // constant-expressions should result in a constant-expression. SkSL handles this by 71 // optimizing fully-constant function calls into literals in FunctionCall::Make. 72 case Expression::Kind::kFunctionCall: 73 case Expression::Kind::kExternalFunctionCall: 74 case Expression::Kind::kChildCall: 75 76 // These shouldn't appear in a valid program at all, and definitely aren't 77 // constant-(index)-expressions. 78 case Expression::Kind::kPoison: 79 case Expression::Kind::kFunctionReference: 80 case Expression::Kind::kExternalFunctionReference: 81 case Expression::Kind::kMethodReference: 82 case Expression::Kind::kTypeReference: 83 case Expression::Kind::kCodeString: 84 return true; 85 86 default: 87 SkDEBUGFAIL("Unexpected expression type"); 88 return true; 89 } 90 } 91 92 private: 93 const std::set<const Variable*>* fLoopIndices; 94 using INHERITED = ProgramVisitor; 95 }; 96 IsConstantExpression(const Expression & expr)97bool Analysis::IsConstantExpression(const Expression& expr) { 98 return !ConstantExpressionVisitor{/*loopIndices=*/nullptr}.visitExpression(expr); 99 } 100 IsConstantIndexExpression(const Expression & expr,const std::set<const Variable * > * loopIndices)101bool Analysis::IsConstantIndexExpression(const Expression& expr, 102 const std::set<const Variable*>* loopIndices) { 103 return !ConstantExpressionVisitor{loopIndices}.visitExpression(expr); 104 } 105 106 } // namespace SkSL 107