| // Copyright 2022 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef SRC_TINT_LANG_CORE_TYPE_TYPE_H_ |
| #define SRC_TINT_LANG_CORE_TYPE_TYPE_H_ |
| |
| #include <functional> |
| #include <string> |
| |
| #include "src/tint/lang/core/type/clone_context.h" |
| #include "src/tint/lang/core/type/unique_node.h" |
| #include "src/tint/utils/containers/enum_set.h" |
| #include "src/tint/utils/containers/vector.h" |
| |
| // Forward declarations |
| namespace tint { |
| class ProgramBuilder; |
| class SymbolTable; |
| } // namespace tint |
| namespace tint::core::type { |
| class Type; |
| } // namespace tint::core::type |
| |
| namespace tint::core::type { |
| |
| /// Flag is an enumerator of type flag bits, used by Flags. |
| enum Flag { |
| /// Type is constructable. |
| /// @see https://gpuweb.github.io/gpuweb/wgsl/#constructible-types |
| kConstructable, |
| /// Type has a creation-fixed footprint. |
| /// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types |
| kCreationFixedFootprint, |
| /// Type has a fixed footprint. |
| /// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types |
| kFixedFootprint, |
| }; |
| |
| /// An alias to tint::EnumSet<Flag> |
| using Flags = tint::EnumSet<Flag>; |
| |
| /// TypeAndCount holds a type and count |
| struct TypeAndCount { |
| /// The type |
| const Type* type = nullptr; |
| /// The count |
| uint32_t count = 0; |
| }; |
| |
| /// Equality operator. |
| /// @param lhs the LHS TypeAndCount |
| /// @param rhs the RHS TypeAndCount |
| /// @returns true if the two TypeAndCounts have the same type and count |
| inline bool operator==(TypeAndCount lhs, TypeAndCount rhs) { |
| return lhs.type == rhs.type && lhs.count == rhs.count; |
| } |
| |
| /// Base class for a type in the system |
| class Type : public Castable<Type, UniqueNode> { |
| public: |
| /// Destructor |
| ~Type() override; |
| |
| /// @returns the name for this type that closely resembles how it would be |
| /// declared in WGSL. |
| virtual std::string FriendlyName() const = 0; |
| |
| /// @returns the inner most pointee type if this is a pointer, `this` |
| /// otherwise |
| const Type* UnwrapPtr() const; |
| |
| /// @returns the inner type if this is a reference, `this` otherwise |
| const Type* UnwrapRef() const; |
| |
| /// @returns the inner type if this is a pointer or a reference, `this` otherwise |
| const Type* UnwrapPtrOrRef() const; |
| |
| /// @returns the size in bytes of the type. This may include tail padding. |
| /// @note opaque types will return a size of 0. |
| virtual uint32_t Size() const; |
| |
| /// @returns the alignment in bytes of the type. This may include tail |
| /// padding. |
| /// @note opaque types will return a size of 0. |
| virtual uint32_t Align() const; |
| |
| /// @param ctx the clone context |
| /// @returns a clone of this type created in the provided context |
| virtual Type* Clone(CloneContext& ctx) const = 0; |
| |
| /// @returns the flags on the type |
| core::type::Flags Flags() { return flags_; } |
| |
| /// @returns true if type is constructable |
| /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types |
| inline bool IsConstructible() const { return flags_.Contains(Flag::kConstructable); } |
| |
| /// @returns true has a creation-fixed footprint. |
| /// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types |
| inline bool HasCreationFixedFootprint() const { |
| return flags_.Contains(Flag::kCreationFixedFootprint); |
| } |
| |
| /// @returns true has a fixed footprint. |
| /// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types |
| inline bool HasFixedFootprint() const { return flags_.Contains(Flag::kFixedFootprint); } |
| |
| /// @returns true if this type is a float scalar |
| bool is_float_scalar() const; |
| /// @returns true if this type is a float matrix |
| bool is_float_matrix() const; |
| /// @returns true if this type is a square float matrix |
| bool is_square_float_matrix() const; |
| /// @returns true if this type is a float vector |
| bool is_float_vector() const; |
| /// @returns true if this type is a float scalar or vector |
| bool is_float_scalar_or_vector() const; |
| /// @returns true if this type is a float scalar or vector or matrix |
| bool is_float_scalar_or_vector_or_matrix() const; |
| /// @returns true if this type is an integer scalar |
| bool is_integer_scalar() const; |
| /// @returns true if this type is a signed integer scalar |
| bool is_signed_integer_scalar() const; |
| /// @returns true if this type is an unsigned integer scalar |
| bool is_unsigned_integer_scalar() const; |
| /// @returns true if this type is a signed integer vector |
| bool is_signed_integer_vector() const; |
| /// @returns true if this type is an unsigned vector |
| bool is_unsigned_integer_vector() const; |
| /// @returns true if this type is an unsigned scalar or vector |
| bool is_unsigned_integer_scalar_or_vector() const; |
| /// @returns true if this type is a signed scalar or vector |
| bool is_signed_integer_scalar_or_vector() const; |
| /// @returns true if this type is an integer scalar or vector |
| bool is_integer_scalar_or_vector() const; |
| /// @returns true if this type is an abstract integer vector |
| bool is_abstract_integer_vector() const; |
| /// @returns true if this type is an abstract float vector |
| bool is_abstract_float_vector() const; |
| /// @returns true if this type is an abstract integer scalar or vector |
| bool is_abstract_integer_scalar_or_vector() const; |
| /// @returns true if this type is an abstract float scalar or vector |
| bool is_abstract_float_scalar_or_vector() const; |
| /// @returns true if this type is a boolean vector |
| bool is_bool_vector() const; |
| /// @returns true if this type is boolean scalar or vector |
| bool is_bool_scalar_or_vector() const; |
| /// @returns true if this type is a numeric vector |
| bool is_numeric_vector() const; |
| /// @returns true if this type is a vector of scalar type |
| bool is_scalar_vector() const; |
| /// @returns true if this type is a numeric scale or vector |
| bool is_numeric_scalar_or_vector() const; |
| /// @returns true if this type is a handle type |
| bool is_handle() const; |
| |
| /// @returns true if this type is an abstract-numeric or if the type holds an element that is an |
| /// abstract-numeric. |
| bool HoldsAbstract() const; |
| |
| /// kNoConversion is returned from ConversionRank() when the implicit conversion is not |
| /// permitted. |
| static constexpr uint32_t kNoConversion = 0xffffffffu; |
| |
| /// ConversionRank returns the implicit conversion rank when attempting to convert `from` to |
| /// `to`. Lower ranks are preferred over higher ranks. |
| /// @param from the source type |
| /// @param to the destination type |
| /// @returns the rank value for converting from type `from` to type `to`, or #kNoConversion if |
| /// the implicit conversion is not allowed. |
| /// @see https://www.w3.org/TR/WGSL/#conversion-rank |
| static uint32_t ConversionRank(const Type* from, const Type* to); |
| |
| /// @param type_if_invalid the type to return if this type has no child elements. |
| /// @param count_if_invalid the count to return if this type has no child elements, or the |
| /// number is unbounded. |
| /// @returns The child element type and the the number of child elements held by this type. |
| /// If this type has no child element types, then @p invalid is returned. |
| /// If this type can hold a mix of different elements types (like a Struct), then |
| /// `[type_if_invalid, N]` is returned, where `N` is the number of elements. |
| /// If this type is unbounded in size (e.g. runtime sized arrays), then the returned count will |
| /// equal `count_if_invalid`. |
| /// |
| /// Examples: |
| /// * Elements() of `array<vec3<f32>, 5>` returns `[vec3<f32>, 5]`. |
| /// * Elements() of `array<f32>` returns `[f32, count_if_invalid]`. |
| /// * Elements() of `struct S { a : f32, b : i32 }` returns `[count_if_invalid, 2]`. |
| /// * Elements() of `struct S { a : i32, b : i32 }` also returns `[count_if_invalid, 2]`. |
| virtual TypeAndCount Elements(const Type* type_if_invalid = nullptr, |
| uint32_t count_if_invalid = 0) const; |
| |
| /// @param index the i'th element index to return |
| /// @returns The child element with the given index, or nullptr if the element does not exist. |
| /// |
| /// Examples: |
| /// * Element(1) of `mat3x2<f32>` returns `vec2<f32>`. |
| /// * Element(1) of `array<vec3<f32>, 5>` returns `vec3<f32>`. |
| /// * Element(0) of `struct S { a : f32, b : i32 }` returns `f32`. |
| /// * Element(0) of `f32` returns `nullptr`. |
| /// * Element(3) of `vec3<f32>` returns `nullptr`. |
| /// * Element(3) of `struct S { a : f32, b : i32 }` returns `nullptr`. |
| virtual const Type* Element(uint32_t index) const; |
| |
| /// @returns the most deeply nested element of the type. For non-composite types, |
| /// DeepestElement() will return this type. Examples: |
| /// * Element() of `f32` returns `f32`. |
| /// * Element() of `vec3<f32>` returns `f32`. |
| /// * Element() of `mat3x2<f32>` returns `f32`. |
| /// * Element() of `array<vec3<f32>, 5>` returns `f32`. |
| /// * Element() of `struct S { a : f32, b : i32 }` returns `S`. |
| const Type* DeepestElement() const; |
| |
| /// @param types the list of types |
| /// @returns the lowest-ranking type that all types in `types` can be implicitly converted to, |
| /// or nullptr if there is no consistent common type across all types in `types`. |
| /// @see https://www.w3.org/TR/WGSL/#conversion-rank |
| static const Type* Common(VectorRef<const Type*> types); |
| |
| protected: |
| /// Constructor |
| /// @param hash the immutable hash for the node |
| /// @param flags the flags of this type |
| Type(size_t hash, core::type::Flags flags); |
| |
| /// The flags of this type. |
| const core::type::Flags flags_; |
| }; |
| |
| } // namespace tint::core::type |
| |
| namespace std { |
| |
| /// std::hash specialization for tint::core::type::Type |
| template <> |
| struct hash<tint::core::type::Type> { |
| /// @param type the type to obtain a hash from |
| /// @returns the hash of the type |
| size_t operator()(const tint::core::type::Type& type) const { return type.unique_hash; } |
| }; |
| |
| /// std::equal_to specialization for tint::core::type::Type |
| template <> |
| struct equal_to<tint::core::type::Type> { |
| /// @param a the first type to compare |
| /// @param b the second type to compare |
| /// @returns true if the two types are equal |
| bool operator()(const tint::core::type::Type& a, const tint::core::type::Type& b) const { |
| return a.Equals(b); |
| } |
| }; |
| |
| } // namespace std |
| |
| #endif // SRC_TINT_LANG_CORE_TYPE_TYPE_H_ |