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