//===- Types.h - MLIR Type Classes ------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef MLIR_IR_TYPES_H #define MLIR_IR_TYPES_H #include "mlir/IR/TypeSupport.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/PointerLikeTypeTraits.h" namespace mlir { class AsmState; /// Instances of the Type class are uniqued, have an immutable identifier and an /// optional mutable component. They wrap a pointer to the storage object owned /// by MLIRContext. Therefore, instances of Type are passed around by value. /// /// Some types are "primitives" meaning they do not have any parameters, for /// example the Index type. Parametric types have additional information that /// differentiates the types of the same class, for example the Integer type has /// bitwidth, making i8 and i16 belong to the same kind by be different /// instances of the IntegerType. Type parameters are part of the unique /// immutable key. The mutable component of the type can be modified after the /// type is created, but cannot affect the identity of the type. /// /// Types are constructed and uniqued via the 'detail::TypeUniquer' class. /// /// Derived type classes are expected to implement several required /// implementation hooks: /// * Optional: /// - static LogicalResult verifyInvariants( /// function_ref<InFlightDiagnostic()> emitError, /// Args... args) /// * This method is invoked when calling the 'TypeBase::get/getChecked' /// methods to ensure that the arguments passed in are valid to construct /// a type instance with. /// * This method is expected to return failure if a type cannot be /// constructed with 'args', success otherwise. /// * 'args' must correspond with the arguments passed into the /// 'TypeBase::get' call. /// /// /// Type storage objects inherit from TypeStorage and contain the following: /// - The dialect that defined the type. /// - Any parameters of the type. /// - An optional mutable component. /// For non-parametric types, a convenience DefaultTypeStorage is provided. /// Parametric storage types must derive TypeStorage and respect the following: /// - Define a type alias, KeyTy, to a type that uniquely identifies the /// instance of the type. /// * The key type must be constructible from the values passed into the /// detail::TypeUniquer::get call. /// * If the KeyTy does not have an llvm::DenseMapInfo specialization, the /// storage class must define a hashing method: /// 'static unsigned hashKey(const KeyTy &)' /// /// - Provide a method, 'bool operator==(const KeyTy &) const', to /// compare the storage instance against an instance of the key type. /// /// - Provide a static construction method: /// 'DerivedStorage *construct(TypeStorageAllocator &, const KeyTy &key)' /// that builds a unique instance of the derived storage. The arguments to /// this function are an allocator to store any uniqued data within the /// context and the key type for this storage. /// /// - If they have a mutable component, this component must not be a part of /// the key. class Type { … }; inline raw_ostream &operator<<(raw_ostream &os, Type type) { … } //===----------------------------------------------------------------------===// // TypeTraitBase //===----------------------------------------------------------------------===// namespace TypeTrait { /// This class represents the base of a type trait. TraitBase; } // namespace TypeTrait //===----------------------------------------------------------------------===// // TypeInterface //===----------------------------------------------------------------------===// /// This class represents the base of a type interface. See the definition of /// `detail::Interface` for requirements on the `Traits` type. template <typename ConcreteType, typename Traits> class TypeInterface : public detail::Interface<ConcreteType, Type, Traits, Type, TypeTrait::TraitBase> { … }; //===----------------------------------------------------------------------===// // Core TypeTrait //===----------------------------------------------------------------------===// /// This trait is used to determine if a type is mutable or not. It is attached /// on a type if the corresponding ImplType defines a `mutate` function with /// a proper signature. namespace TypeTrait { IsMutable; } // namespace TypeTrait //===----------------------------------------------------------------------===// // Type Utils //===----------------------------------------------------------------------===// // Make Type hashable. inline ::llvm::hash_code hash_value(Type arg) { … } template <typename... Tys> bool Type::isa() const { … } template <typename... Tys> bool Type::isa_and_nonnull() const { … } template <typename U> U Type::dyn_cast() const { … } template <typename U> U Type::dyn_cast_or_null() const { … } template <typename U> U Type::cast() const { … } } // namespace mlir namespace llvm { // Type hash just like pointers. template <> struct DenseMapInfo<mlir::Type> { … }; DenseMapInfo<T, std::enable_if_t<std::is_base_of<mlir::Type, T>::value && !mlir::detail::IsInterface<T>::value>>; /// We align TypeStorage by 8, so allow LLVM to steal the low bits. template <> struct PointerLikeTypeTraits<mlir::Type> { … }; /// Add support for llvm style casts. /// We provide a cast between To and From if From is mlir::Type or derives from /// it CastInfo<To, From, std::enable_if_t<std::is_same_v<mlir::Type, std::remove_const_t<From>> || std::is_base_of_v<mlir::Type, From>>>; } // namespace llvm #endif // MLIR_IR_TYPES_H