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