| /* |
| * Copyright 2021 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkTypes.h" |
| #include "include/private/SkSLIRNode.h" |
| #include "include/private/SkSLModifiers.h" |
| #include "include/sksl/SkSLOperator.h" |
| #include "src/sksl/SkSLAnalysis.h" |
| #include "src/sksl/analysis/SkSLProgramVisitor.h" |
| #include "src/sksl/ir/SkSLBinaryExpression.h" |
| #include "src/sksl/ir/SkSLExpression.h" |
| #include "src/sksl/ir/SkSLVariable.h" |
| #include "src/sksl/ir/SkSLVariableReference.h" |
| |
| #include <set> |
| |
| namespace SkSL { |
| |
| // Checks for ES2 constant-expression rules, and (optionally) constant-index-expression rules |
| // (if loopIndices is non-nullptr) |
| class ConstantExpressionVisitor : public ProgramVisitor { |
| public: |
| ConstantExpressionVisitor(const std::set<const Variable*>* loopIndices) |
| : fLoopIndices(loopIndices) {} |
| |
| bool visitExpression(const Expression& e) override { |
| // A constant-(index)-expression is one of... |
| switch (e.kind()) { |
| // ... a literal value |
| case Expression::Kind::kLiteral: |
| return false; |
| |
| // ... settings can appear in fragment processors; they will resolve when compiled |
| case Expression::Kind::kSetting: |
| return false; |
| |
| // ... a global or local variable qualified as 'const', excluding function parameters. |
| // ... loop indices as defined in section 4. [constant-index-expression] |
| case Expression::Kind::kVariableReference: { |
| const Variable* v = e.as<VariableReference>().variable(); |
| if ((v->storage() == Variable::Storage::kGlobal || |
| v->storage() == Variable::Storage::kLocal) && |
| (v->modifiers().fFlags & Modifiers::kConst_Flag)) { |
| return false; |
| } |
| return !fLoopIndices || fLoopIndices->find(v) == fLoopIndices->end(); |
| } |
| |
| // ... not a sequence expression (skia:13311)... |
| case Expression::Kind::kBinary: |
| if (e.as<BinaryExpression>().getOperator().kind() == Operator::Kind::COMMA) { |
| return true; |
| } |
| [[fallthrough]]; |
| |
| // ... expressions composed of both of the above |
| case Expression::Kind::kConstructorArray: |
| case Expression::Kind::kConstructorArrayCast: |
| case Expression::Kind::kConstructorCompound: |
| case Expression::Kind::kConstructorCompoundCast: |
| case Expression::Kind::kConstructorDiagonalMatrix: |
| case Expression::Kind::kConstructorMatrixResize: |
| case Expression::Kind::kConstructorScalarCast: |
| case Expression::Kind::kConstructorSplat: |
| case Expression::Kind::kConstructorStruct: |
| case Expression::Kind::kFieldAccess: |
| case Expression::Kind::kIndex: |
| case Expression::Kind::kPrefix: |
| case Expression::Kind::kPostfix: |
| case Expression::Kind::kSwizzle: |
| case Expression::Kind::kTernary: |
| return INHERITED::visitExpression(e); |
| |
| // Function calls are completely disallowed in SkSL constant-(index)-expressions. |
| // GLSL does mandate that calling a built-in function where the arguments are all |
| // constant-expressions should result in a constant-expression. SkSL handles this by |
| // optimizing fully-constant function calls into literals in FunctionCall::Make. |
| case Expression::Kind::kFunctionCall: |
| case Expression::Kind::kExternalFunctionCall: |
| case Expression::Kind::kChildCall: |
| |
| // These shouldn't appear in a valid program at all, and definitely aren't |
| // constant-(index)-expressions. |
| case Expression::Kind::kPoison: |
| case Expression::Kind::kFunctionReference: |
| case Expression::Kind::kExternalFunctionReference: |
| case Expression::Kind::kMethodReference: |
| case Expression::Kind::kTypeReference: |
| return true; |
| |
| default: |
| SkDEBUGFAIL("Unexpected expression type"); |
| return true; |
| } |
| } |
| |
| private: |
| const std::set<const Variable*>* fLoopIndices; |
| using INHERITED = ProgramVisitor; |
| }; |
| |
| bool Analysis::IsConstantExpression(const Expression& expr) { |
| return !ConstantExpressionVisitor{/*loopIndices=*/nullptr}.visitExpression(expr); |
| } |
| |
| bool Analysis::IsConstantIndexExpression(const Expression& expr, |
| const std::set<const Variable*>* loopIndices) { |
| return !ConstantExpressionVisitor{loopIndices}.visitExpression(expr); |
| } |
| |
| } // namespace SkSL |