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 "src/sksl/ir/SkSLType.h" 14 15 #include <unordered_map> 16 17 namespace SkSL { 18 19 class AnyConstructor; 20 class Expression; 21 class IRGenerator; 22 class Variable; 23 24 /** 25 * Abstract supertype of all expressions. 26 */ 27 class Expression : public IRNode { 28 public: 29 enum class Kind { 30 kBinary = (int) Statement::Kind::kLast + 1, 31 kBoolLiteral, 32 kCodeString, 33 kConstructorArray, 34 kConstructorCompound, 35 kConstructorCompoundCast, 36 kConstructorDiagonalMatrix, 37 kConstructorMatrixResize, 38 kConstructorScalarCast, 39 kConstructorSplat, 40 kConstructorStruct, 41 kExternalFunctionCall, 42 kExternalFunctionReference, 43 kIntLiteral, 44 kFieldAccess, 45 kFloatLiteral, 46 kFunctionReference, 47 kFunctionCall, 48 kIndex, 49 kPrefix, 50 kPostfix, 51 kSetting, 52 kSwizzle, 53 kTernary, 54 kTypeReference, 55 kVariableReference, 56 57 kFirst = kBinary, 58 kLast = kVariableReference 59 }; 60 61 enum class Property { 62 kSideEffects, 63 kContainsRTAdjust 64 }; 65 Expression(int offset,Kind kind,const Type * type)66 Expression(int offset, Kind kind, const Type* type) 67 : INHERITED(offset, (int) kind) 68 , fType(type) { 69 SkASSERT(kind >= Kind::kFirst && kind <= Kind::kLast); 70 } 71 kind()72 Kind kind() const { 73 return (Kind) fKind; 74 } 75 type()76 virtual const Type& type() const { 77 return *fType; 78 } 79 80 /** 81 * Use is<T> to check the type of an expression. 82 * e.g. replace `e.kind() == Expression::Kind::kIntLiteral` with `e.is<IntLiteral>()`. 83 */ 84 template <typename T> is()85 bool is() const { 86 return this->kind() == T::kExpressionKind; 87 } 88 isAnyConstructor()89 bool isAnyConstructor() const { 90 static_assert((int)Kind::kConstructorArray - 1 == (int)Kind::kCodeString); 91 static_assert((int)Kind::kConstructorStruct + 1 == (int)Kind::kExternalFunctionCall); 92 return this->kind() >= Kind::kConstructorArray && this->kind() <= Kind::kConstructorStruct; 93 } 94 95 /** 96 * Use as<T> to downcast expressions: e.g. replace `(IntLiteral&) i` with `i.as<IntLiteral>()`. 97 */ 98 template <typename T> as()99 const T& as() const { 100 SkASSERT(this->is<T>()); 101 return static_cast<const T&>(*this); 102 } 103 104 template <typename T> as()105 T& as() { 106 SkASSERT(this->is<T>()); 107 return static_cast<T&>(*this); 108 } 109 110 AnyConstructor& asAnyConstructor(); 111 const AnyConstructor& asAnyConstructor() const; 112 113 /** 114 * Returns true if this expression is constant. compareConstant must be implemented for all 115 * constants! 116 */ isCompileTimeConstant()117 virtual bool isCompileTimeConstant() const { 118 return false; 119 } 120 121 /** 122 * Compares this constant expression against another constant expression. Returns kUnknown if 123 * we aren't able to deduce a result (an expression isn't actually constant, the types are 124 * mismatched, etc). 125 */ 126 enum class ComparisonResult { 127 kUnknown = -1, 128 kNotEqual, 129 kEqual 130 }; compareConstant(const Expression & other)131 virtual ComparisonResult compareConstant(const Expression& other) const { 132 return ComparisonResult::kUnknown; 133 } 134 135 /** 136 * Returns true if, given fixed values for uniforms, this expression always evaluates to the 137 * same result with no side effects. 138 */ isConstantOrUniform()139 virtual bool isConstantOrUniform() const { 140 SkASSERT(!this->isCompileTimeConstant() || !this->hasSideEffects()); 141 return this->isCompileTimeConstant(); 142 } 143 144 virtual bool hasProperty(Property property) const = 0; 145 hasSideEffects()146 bool hasSideEffects() const { 147 return this->hasProperty(Property::kSideEffects); 148 } 149 containsRTAdjust()150 bool containsRTAdjust() const { 151 return this->hasProperty(Property::kContainsRTAdjust); 152 } 153 coercionCost(const Type & target)154 virtual CoercionCost coercionCost(const Type& target) const { 155 return this->type().coercionCost(target); 156 } 157 158 /** 159 * Returns the n'th compile-time constant expression within a literal or constructor. 160 * Use Type::slotCount to determine the number of subexpressions within an expression. 161 * Subexpressions which are not compile-time constants will return null. 162 * `vec4(1, vec2(2), 3)` contains four subexpressions: (1, 2, 2, 3) 163 * `mat2(f)` contains four subexpressions: (null, 0, 164 * 0, null) 165 */ getConstantSubexpression(int n)166 virtual const Expression* getConstantSubexpression(int n) const { 167 return nullptr; 168 } 169 170 virtual std::unique_ptr<Expression> clone() const = 0; 171 172 private: 173 const Type* fType; 174 175 using INHERITED = IRNode; 176 }; 177 178 } // namespace SkSL 179 180 #endif 181