• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)97 bool Analysis::IsConstantExpression(const Expression& expr) {
98     return !ConstantExpressionVisitor{/*loopIndices=*/nullptr}.visitExpression(expr);
99 }
100 
IsConstantIndexExpression(const Expression & expr,const std::set<const Variable * > * loopIndices)101 bool Analysis::IsConstantIndexExpression(const Expression& expr,
102                                          const std::set<const Variable*>* loopIndices) {
103     return !ConstantExpressionVisitor{loopIndices}.visitExpression(expr);
104 }
105 
106 }  // namespace SkSL
107