• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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 #ifndef SKSL_EXPRESSION
9 #define SKSL_EXPRESSION
10 
11 #include "include/private/SkSLStatement.h"
12 #include "include/private/SkTHash.h"
13 #include "include/private/SkTOptional.h"
14 #include "src/sksl/ir/SkSLType.h"
15 
16 #include <unordered_map>
17 
18 namespace SkSL {
19 
20 class AnyConstructor;
21 class Expression;
22 class IRGenerator;
23 class Variable;
24 
25 /**
26  * Abstract supertype of all expressions.
27  */
28 class Expression : public IRNode {
29 public:
30     enum class Kind {
31         kBinary = (int) Statement::Kind::kLast + 1,
32         kChildCall,
33         kCodeString,
34         kConstructorArray,
35         kConstructorArrayCast,
36         kConstructorCompound,
37         kConstructorCompoundCast,
38         kConstructorDiagonalMatrix,
39         kConstructorMatrixResize,
40         kConstructorScalarCast,
41         kConstructorSplat,
42         kConstructorStruct,
43         kExternalFunctionCall,
44         kExternalFunctionReference,
45         kFieldAccess,
46         kFunctionReference,
47         kFunctionCall,
48         kIndex,
49         kLiteral,
50         kMethodReference,
51         kPoison,
52         kPostfix,
53         kPrefix,
54         kSetting,
55         kSwizzle,
56         kTernary,
57         kTypeReference,
58         kVariableReference,
59 
60         kFirst = kBinary,
61         kLast = kVariableReference
62     };
63 
64     enum class Property {
65         kSideEffects,
66         kContainsRTAdjust
67     };
68 
Expression(int line,Kind kind,const Type * type)69     Expression(int line, Kind kind, const Type* type)
70         : INHERITED(line, (int) kind)
71         , fType(type) {
72         SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast);
73     }
74 
kind()75     Kind kind() const {
76         return (Kind) fKind;
77     }
78 
type()79     virtual const Type& type() const {
80         return *fType;
81     }
82 
83     /**
84      *  Use is<T> to check the type of an expression.
85      *  e.g. replace `e.kind() == Expression::Kind::kLiteral` with `e.is<Literal>()`.
86      */
87     template <typename T>
is()88     bool is() const {
89         return this->kind() == T::kExpressionKind;
90     }
91 
isAnyConstructor()92     bool isAnyConstructor() const {
93         static_assert((int)Kind::kConstructorArray - 1 == (int)Kind::kCodeString);
94         static_assert((int)Kind::kConstructorStruct + 1 == (int)Kind::kExternalFunctionCall);
95         return this->kind() >= Kind::kConstructorArray && this->kind() <= Kind::kConstructorStruct;
96     }
97 
isIntLiteral()98     bool isIntLiteral() const {
99         return this->kind() == Kind::kLiteral && this->type().isInteger();
100     }
101 
isFloatLiteral()102     bool isFloatLiteral() const {
103         return this->kind() == Kind::kLiteral && this->type().isFloat();
104     }
105 
isBoolLiteral()106     bool isBoolLiteral() const {
107         return this->kind() == Kind::kLiteral && this->type().isBoolean();
108     }
109 
110     /**
111      *  Use as<T> to downcast expressions: e.g. replace `(Literal&) i` with `i.as<Literal>()`.
112      */
113     template <typename T>
as()114     const T& as() const {
115         SkASSERT(this->is<T>());
116         return static_cast<const T&>(*this);
117     }
118 
119     template <typename T>
as()120     T& as() {
121         SkASSERT(this->is<T>());
122         return static_cast<T&>(*this);
123     }
124 
125     AnyConstructor& asAnyConstructor();
126     const AnyConstructor& asAnyConstructor() const;
127 
128     /**
129      * Returns true if this expression is constant. compareConstant must be implemented for all
130      * constants!
131      */
isCompileTimeConstant()132     virtual bool isCompileTimeConstant() const {
133         return false;
134     }
135 
136     /**
137      * Returns true if this expression is incomplete. Specifically, dangling function/method-call
138      * references that were never invoked, or type references that were never constructed, are
139      * considered incomplete expressions and should result in an error.
140      */
141     bool isIncomplete(const Context& context) const;
142 
143     /**
144      * Compares this constant expression against another constant expression. Returns kUnknown if
145      * we aren't able to deduce a result (an expression isn't actually constant, the types are
146      * mismatched, etc).
147      */
148     enum class ComparisonResult {
149         kUnknown = -1,
150         kNotEqual,
151         kEqual
152     };
compareConstant(const Expression & other)153     virtual ComparisonResult compareConstant(const Expression& other) const {
154         return ComparisonResult::kUnknown;
155     }
156 
157     /**
158      * Returns true if, given fixed values for uniforms, this expression always evaluates to the
159      * same result with no side effects.
160      */
isConstantOrUniform()161     virtual bool isConstantOrUniform() const {
162         SkASSERT(!this->isCompileTimeConstant() || !this->hasSideEffects());
163         return this->isCompileTimeConstant();
164     }
165 
166     virtual bool hasProperty(Property property) const = 0;
167 
hasSideEffects()168     bool hasSideEffects() const {
169         return this->hasProperty(Property::kSideEffects);
170     }
171 
containsRTAdjust()172     bool containsRTAdjust() const {
173         return this->hasProperty(Property::kContainsRTAdjust);
174     }
175 
coercionCost(const Type & target)176     virtual CoercionCost coercionCost(const Type& target) const {
177         return this->type().coercionCost(target);
178     }
179 
180     /**
181      * Returns true if this expression type supports `getConstantValue`. (This particular expression
182      * may or may not actually contain a constant value.) It's harmless to call `getConstantValue`
183      * on expressions which don't support constant values or don't contain any constant values, but
184      * if `supportsConstantValues` returns false, you can assume that `getConstantValue` will return
185      * nullopt for every slot of this expression. This allows for early-out opportunities in some
186      * cases. (Some expressions have tons of slots but never hold a constant value; e.g. a variable
187      * holding a very large array.)
188      */
supportsConstantValues()189     virtual bool supportsConstantValues() const {
190         return false;
191     }
192 
193     /**
194      * Returns the n'th compile-time constant value within a literal or constructor.
195      * Use Type::slotCount to determine the number of slots within an expression.
196      * Slots which do not contain compile-time constant values will return nullopt.
197      * `vec4(1, vec2(2), 3)` contains four compile-time constants: (1, 2, 2, 3)
198      * `mat2(f)` contains four slots, and two are constant: (nullopt, 0,
199      *                                                       0, nullopt)
200      * All classes which override this function must also implement `supportsConstantValues`.
201      */
getConstantValue(int n)202     virtual skstd::optional<double> getConstantValue(int n) const {
203         SkASSERT(!this->supportsConstantValues());
204         return skstd::nullopt;
205     }
206 
207     virtual std::unique_ptr<Expression> clone() const = 0;
208 
209 private:
210     const Type* fType;
211 
212     using INHERITED = IRNode;
213 };
214 
215 }  // namespace SkSL
216 
217 #endif
218