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