blob: fae0c444d8ef1a61634e26ea094ac04b8d41e937 [file] [log] [blame]
// 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_