• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- Types.h - MLIR Type Classes ------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef MLIR_IR_TYPES_H
10 #define MLIR_IR_TYPES_H
11 
12 #include "mlir/IR/TypeSupport.h"
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/DenseMapInfo.h"
15 #include "llvm/Support/PointerLikeTypeTraits.h"
16 
17 namespace mlir {
18 /// Instances of the Type class are uniqued, have an immutable identifier and an
19 /// optional mutable component.  They wrap a pointer to the storage object owned
20 /// by MLIRContext.  Therefore, instances of Type are passed around by value.
21 ///
22 /// Some types are "primitives" meaning they do not have any parameters, for
23 /// example the Index type.  Parametric types have additional information that
24 /// differentiates the types of the same class, for example the Integer type has
25 /// bitwidth, making i8 and i16 belong to the same kind by be different
26 /// instances of the IntegerType. Type parameters are part of the unique
27 /// immutable key.  The mutable component of the type can be modified after the
28 /// type is created, but cannot affect the identity of the type.
29 ///
30 /// Types are constructed and uniqued via the 'detail::TypeUniquer' class.
31 ///
32 /// Derived type classes are expected to implement several required
33 /// implementation hooks:
34 ///  * Optional:
35 ///    - static LogicalResult verifyConstructionInvariants(Location loc,
36 ///                                                        Args... args)
37 ///      * This method is invoked when calling the 'TypeBase::get/getChecked'
38 ///        methods to ensure that the arguments passed in are valid to construct
39 ///        a type instance with.
40 ///      * This method is expected to return failure if a type cannot be
41 ///        constructed with 'args', success otherwise.
42 ///      * 'args' must correspond with the arguments passed into the
43 ///        'TypeBase::get' call.
44 ///
45 ///
46 /// Type storage objects inherit from TypeStorage and contain the following:
47 ///    - The dialect that defined the type.
48 ///    - Any parameters of the type.
49 ///    - An optional mutable component.
50 /// For non-parametric types, a convenience DefaultTypeStorage is provided.
51 /// Parametric storage types must derive TypeStorage and respect the following:
52 ///    - Define a type alias, KeyTy, to a type that uniquely identifies the
53 ///      instance of the type.
54 ///      * The key type must be constructible from the values passed into the
55 ///        detail::TypeUniquer::get call.
56 ///      * If the KeyTy does not have an llvm::DenseMapInfo specialization, the
57 ///        storage class must define a hashing method:
58 ///         'static unsigned hashKey(const KeyTy &)'
59 ///
60 ///    - Provide a method, 'bool operator==(const KeyTy &) const', to
61 ///      compare the storage instance against an instance of the key type.
62 ///
63 ///    - Provide a static construction method:
64 ///        'DerivedStorage *construct(TypeStorageAllocator &, const KeyTy &key)'
65 ///      that builds a unique instance of the derived storage. The arguments to
66 ///      this function are an allocator to store any uniqued data within the
67 ///      context and the key type for this storage.
68 ///
69 ///    - If they have a mutable component, this component must not be a part of
70 //       the key.
71 class Type {
72 public:
73   /// Utility class for implementing types.
74   template <typename ConcreteType, typename BaseType, typename StorageType,
75             template <typename T> class... Traits>
76   using TypeBase = detail::StorageUserBase<ConcreteType, BaseType, StorageType,
77                                            detail::TypeUniquer, Traits...>;
78 
79   using ImplType = TypeStorage;
80 
Type()81   constexpr Type() : impl(nullptr) {}
Type(const ImplType * impl)82   /* implicit */ Type(const ImplType *impl)
83       : impl(const_cast<ImplType *>(impl)) {}
84 
85   Type(const Type &other) = default;
86   Type &operator=(const Type &other) = default;
87 
88   bool operator==(Type other) const { return impl == other.impl; }
89   bool operator!=(Type other) const { return !(*this == other); }
90   explicit operator bool() const { return impl; }
91 
92   bool operator!() const { return impl == nullptr; }
93 
94   template <typename U> bool isa() const;
95   template <typename First, typename Second, typename... Rest>
96   bool isa() const;
97   template <typename U> U dyn_cast() const;
98   template <typename U> U dyn_cast_or_null() const;
99   template <typename U> U cast() const;
100 
101   // Support type casting Type to itself.
classof(Type)102   static bool classof(Type) { return true; }
103 
104   /// Return a unique identifier for the concrete type. This is used to support
105   /// dynamic type casting.
getTypeID()106   TypeID getTypeID() { return impl->getAbstractType().getTypeID(); }
107 
108   /// Return the MLIRContext in which this type was uniqued.
109   MLIRContext *getContext() const;
110 
111   /// Get the dialect this type is registered to.
112   Dialect &getDialect() const;
113 
114   // Convenience predicates.  This is only for floating point types,
115   // derived types should use isa/dyn_cast.
116   bool isIndex() const;
117   bool isBF16() const;
118   bool isF16() const;
119   bool isF32() const;
120   bool isF64() const;
121 
122   /// Return true if this is an integer type with the specified width.
123   bool isInteger(unsigned width) const;
124   /// Return true if this is a signless integer type (with the specified width).
125   bool isSignlessInteger() const;
126   bool isSignlessInteger(unsigned width) const;
127   /// Return true if this is a signed integer type (with the specified width).
128   bool isSignedInteger() const;
129   bool isSignedInteger(unsigned width) const;
130   /// Return true if this is an unsigned integer type (with the specified
131   /// width).
132   bool isUnsignedInteger() const;
133   bool isUnsignedInteger(unsigned width) const;
134 
135   /// Return the bit width of an integer or a float type, assert failure on
136   /// other types.
137   unsigned getIntOrFloatBitWidth() const;
138 
139   /// Return true if this is a signless integer or index type.
140   bool isSignlessIntOrIndex() const;
141   /// Return true if this is a signless integer, index, or float type.
142   bool isSignlessIntOrIndexOrFloat() const;
143   /// Return true of this is a signless integer or a float type.
144   bool isSignlessIntOrFloat() const;
145 
146   /// Return true if this is an integer (of any signedness) or an index type.
147   bool isIntOrIndex() const;
148   /// Return true if this is an integer (of any signedness) or a float type.
149   bool isIntOrFloat() const;
150   /// Return true if this is an integer (of any signedness), index, or float
151   /// type.
152   bool isIntOrIndexOrFloat() const;
153 
154   /// Print the current type.
155   void print(raw_ostream &os);
156   void dump();
157 
158   friend ::llvm::hash_code hash_value(Type arg);
159 
160   /// Methods for supporting PointerLikeTypeTraits.
getAsOpaquePointer()161   const void *getAsOpaquePointer() const {
162     return static_cast<const void *>(impl);
163   }
getFromOpaquePointer(const void * pointer)164   static Type getFromOpaquePointer(const void *pointer) {
165     return Type(reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
166   }
167 
168   /// Return the abstract type descriptor for this type.
getAbstractType()169   const AbstractType &getAbstractType() { return impl->getAbstractType(); }
170 
171 protected:
172   ImplType *impl;
173 };
174 
175 inline raw_ostream &operator<<(raw_ostream &os, Type type) {
176   type.print(os);
177   return os;
178 }
179 
180 //===----------------------------------------------------------------------===//
181 // TypeTraitBase
182 //===----------------------------------------------------------------------===//
183 
184 namespace TypeTrait {
185 /// This class represents the base of a type trait.
186 template <typename ConcreteType, template <typename> class TraitType>
187 using TraitBase = detail::StorageUserTraitBase<ConcreteType, TraitType>;
188 } // namespace TypeTrait
189 
190 //===----------------------------------------------------------------------===//
191 // TypeInterface
192 //===----------------------------------------------------------------------===//
193 
194 /// This class represents the base of a type interface. See the definition  of
195 /// `detail::Interface` for requirements on the `Traits` type.
196 template <typename ConcreteType, typename Traits>
197 class TypeInterface : public detail::Interface<ConcreteType, Type, Traits, Type,
198                                                TypeTrait::TraitBase> {
199 public:
200   using Base = TypeInterface<ConcreteType, Traits>;
201   using InterfaceBase =
202       detail::Interface<ConcreteType, Type, Traits, Type, TypeTrait::TraitBase>;
203   using InterfaceBase::InterfaceBase;
204 
205 private:
206   /// Returns the impl interface instance for the given type.
getInterfaceFor(Type type)207   static typename InterfaceBase::Concept *getInterfaceFor(Type type) {
208     return type.getAbstractType().getInterface<ConcreteType>();
209   }
210 
211   /// Allow access to 'getInterfaceFor'.
212   friend InterfaceBase;
213 };
214 
215 //===----------------------------------------------------------------------===//
216 // Type Utils
217 //===----------------------------------------------------------------------===//
218 
219 // Make Type hashable.
hash_value(Type arg)220 inline ::llvm::hash_code hash_value(Type arg) {
221   return ::llvm::hash_value(arg.impl);
222 }
223 
isa()224 template <typename U> bool Type::isa() const {
225   assert(impl && "isa<> used on a null type.");
226   return U::classof(*this);
227 }
228 
229 template <typename First, typename Second, typename... Rest>
isa()230 bool Type::isa() const {
231   return isa<First>() || isa<Second, Rest...>();
232 }
233 
dyn_cast()234 template <typename U> U Type::dyn_cast() const {
235   return isa<U>() ? U(impl) : U(nullptr);
236 }
dyn_cast_or_null()237 template <typename U> U Type::dyn_cast_or_null() const {
238   return (impl && isa<U>()) ? U(impl) : U(nullptr);
239 }
cast()240 template <typename U> U Type::cast() const {
241   assert(isa<U>());
242   return U(impl);
243 }
244 
245 } // end namespace mlir
246 
247 namespace llvm {
248 
249 // Type hash just like pointers.
250 template <> struct DenseMapInfo<mlir::Type> {
251   static mlir::Type getEmptyKey() {
252     auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
253     return mlir::Type(static_cast<mlir::Type::ImplType *>(pointer));
254   }
255   static mlir::Type getTombstoneKey() {
256     auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
257     return mlir::Type(static_cast<mlir::Type::ImplType *>(pointer));
258   }
259   static unsigned getHashValue(mlir::Type val) { return mlir::hash_value(val); }
260   static bool isEqual(mlir::Type LHS, mlir::Type RHS) { return LHS == RHS; }
261 };
262 
263 /// We align TypeStorage by 8, so allow LLVM to steal the low bits.
264 template <> struct PointerLikeTypeTraits<mlir::Type> {
265 public:
266   static inline void *getAsVoidPointer(mlir::Type I) {
267     return const_cast<void *>(I.getAsOpaquePointer());
268   }
269   static inline mlir::Type getFromVoidPointer(void *P) {
270     return mlir::Type::getFromOpaquePointer(P);
271   }
272   static constexpr int NumLowBitsAvailable = 3;
273 };
274 
275 } // namespace llvm
276 
277 #endif // MLIR_IR_TYPES_H
278