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