• 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/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)104 bool Analysis::IsConstantExpression(const Expression& expr) {
105     return !ConstantExpressionVisitor{/*loopIndices=*/nullptr}.visitExpression(expr);
106 }
107 
IsConstantIndexExpression(const Expression & expr,const std::set<const Variable * > * loopIndices)108 bool Analysis::IsConstantIndexExpression(const Expression& expr,
109                                          const std::set<const Variable*>* loopIndices) {
110     return !ConstantExpressionVisitor{loopIndices}.visitExpression(expr);
111 }
112 
113 }  // namespace SkSL
114