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 class FloatType;
19 class Identifier;
20 class IndexType;
21 class IntegerType;
22 class MLIRContext;
23 class TypeStorage;
24 
25 namespace detail {
26 struct FunctionTypeStorage;
27 struct OpaqueTypeStorage;
28 } // namespace detail
29 
30 /// Instances of the Type class are immutable and uniqued.  They wrap a pointer
31 /// to the storage object owned by MLIRContext.  Therefore, instances of Type
32 /// are passed around by value.
33 ///
34 /// Some types are "primitives" meaning they do not have any parameters, for
35 /// example the Index type.  Parametric types have additional information that
36 /// differentiates the types of the same kind between them, for example the
37 /// Integer type has bitwidth, making i8 and i16 belong to the same kind by be
38 /// different instances of the IntegerType.
39 ///
40 /// Types are constructed and uniqued via the 'detail::TypeUniquer' class.
41 ///
42 /// Derived type classes are expected to implement several required
43 /// implementation hooks:
44 ///  * Required:
45 ///    - static bool kindof(unsigned kind);
46 ///      * Returns if the provided type kind corresponds to an instance of the
47 ///        current type. Used for isa/dyn_cast casting functionality.
48 ///
49 ///  * Optional:
50 ///    - static LogicalResult verifyConstructionInvariants(Location loc,
51 ///                                                        Args... args)
52 ///      * This method is invoked when calling the 'TypeBase::get/getChecked'
53 ///        methods to ensure that the arguments passed in are valid to construct
54 ///        a type instance with.
55 ///      * This method is expected to return failure if a type cannot be
56 ///        constructed with 'args', success otherwise.
57 ///      * 'args' must correspond with the arguments passed into the
58 ///        'TypeBase::get' call after the type kind.
59 ///
60 ///
61 /// Type storage objects inherit from TypeStorage and contain the following:
62 ///    - The type kind (for LLVM-style RTTI).
63 ///    - The dialect that defined the type.
64 ///    - Any parameters of the type.
65 /// For non-parametric types, a convenience DefaultTypeStorage is provided.
66 /// Parametric storage types must derive TypeStorage and respect the following:
67 ///    - Define a type alias, KeyTy, to a type that uniquely identifies the
68 ///      instance of the type within its kind.
69 ///      * The key type must be constructible from the values passed into the
70 ///        detail::TypeUniquer::get call after the type kind.
71 ///      * If the KeyTy does not have an llvm::DenseMapInfo specialization, the
72 ///        storage class must define a hashing method:
73 ///         'static unsigned hashKey(const KeyTy &)'
74 ///
75 ///    - Provide a method, 'bool operator==(const KeyTy &) const', to
76 ///      compare the storage instance against an instance of the key type.
77 ///
78 ///    - Provide a construction method:
79 ///        'DerivedStorage *construct(TypeStorageAllocator &, const KeyTy &key)'
80 ///      that builds a unique instance of the derived storage. The arguments to
81 ///      this function are an allocator to store any uniqued data within the
82 ///      context and the key type for this storage.
83 class Type {
84 public:
85   /// Integer identifier for all the concrete type kinds.
86   /// Note: This is not an enum class as each dialect will likely define a
87   /// separate enumeration for the specific types that they define. Not being an
88   /// enum class also simplifies the handling of type kinds by not requiring
89   /// casts for each use.
90   enum Kind {
91     // Builtin types.
92     Function,
93     Opaque,
94     LAST_BUILTIN_TYPE = Opaque,
95 
96   // Reserve type kinds for dialect specific type system extensions.
97 #define DEFINE_SYM_KIND_RANGE(Dialect)                                         \
98   FIRST_##Dialect##_TYPE, LAST_##Dialect##_TYPE = FIRST_##Dialect##_TYPE + 0xff,
99 #include "DialectSymbolRegistry.def"
100   };
101 
102   /// Utility class for implementing types.
103   template <typename ConcreteType, typename BaseType, typename StorageType,
104             template <typename T> class... Traits>
105   using TypeBase = detail::StorageUserBase<ConcreteType, BaseType, StorageType,
106                                            detail::TypeUniquer, Traits...>;
107 
108   using ImplType = TypeStorage;
109 
Type()110   constexpr Type() : impl(nullptr) {}
Type(const ImplType * impl)111   /* implicit */ Type(const ImplType *impl)
112       : impl(const_cast<ImplType *>(impl)) {}
113 
114   Type(const Type &other) = default;
115   Type &operator=(const Type &other) = default;
116 
117   bool operator==(Type other) const { return impl == other.impl; }
118   bool operator!=(Type other) const { return !(*this == other); }
119   explicit operator bool() const { return impl; }
120 
121   bool operator!() const { return impl == nullptr; }
122 
123   template <typename U> bool isa() const;
124   template <typename First, typename Second, typename... Rest>
125   bool isa() const;
126   template <typename U> U dyn_cast() const;
127   template <typename U> U dyn_cast_or_null() const;
128   template <typename U> U cast() const;
129 
130   // Support type casting Type to itself.
classof(Type)131   static bool classof(Type) { return true; }
132 
133   /// Return the classification for this type.
134   unsigned getKind() const;
135 
136   /// Return the LLVMContext in which this type was uniqued.
137   MLIRContext *getContext() const;
138 
139   /// Get the dialect this type is registered to.
140   Dialect &getDialect() const;
141 
142   // Convenience predicates.  This is only for floating point types,
143   // derived types should use isa/dyn_cast.
144   bool isIndex();
145   bool isBF16();
146   bool isF16();
147   bool isF32();
148   bool isF64();
149 
150   /// Return true if this is an integer type with the specified width.
151   bool isInteger(unsigned width);
152   /// Return true if this is a signless integer type (with the specified width).
153   bool isSignlessInteger();
154   bool isSignlessInteger(unsigned width);
155   /// Return true if this is a signed integer type (with the specified width).
156   bool isSignedInteger();
157   bool isSignedInteger(unsigned width);
158   /// Return true if this is an unsigned integer type (with the specified
159   /// width).
160   bool isUnsignedInteger();
161   bool isUnsignedInteger(unsigned width);
162 
163   /// Return the bit width of an integer or a float type, assert failure on
164   /// other types.
165   unsigned getIntOrFloatBitWidth();
166 
167   /// Return true if this is a signless integer or index type.
168   bool isSignlessIntOrIndex();
169   /// Return true if this is a signless integer, index, or float type.
170   bool isSignlessIntOrIndexOrFloat();
171   /// Return true of this is a signless integer or a float type.
172   bool isSignlessIntOrFloat();
173 
174   /// Return true if this is an integer (of any signedness) or an index type.
175   bool isIntOrIndex();
176   /// Return true if this is an integer (of any signedness) or a float type.
177   bool isIntOrFloat();
178   /// Return true if this is an integer (of any signedness), index, or float
179   /// type.
180   bool isIntOrIndexOrFloat();
181 
182   /// Print the current type.
183   void print(raw_ostream &os);
184   void dump();
185 
186   friend ::llvm::hash_code hash_value(Type arg);
187 
188   unsigned getSubclassData() const;
189   void setSubclassData(unsigned val);
190 
191   /// Methods for supporting PointerLikeTypeTraits.
getAsOpaquePointer()192   const void *getAsOpaquePointer() const {
193     return static_cast<const void *>(impl);
194   }
getFromOpaquePointer(const void * pointer)195   static Type getFromOpaquePointer(const void *pointer) {
196     return Type(reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
197   }
198 
199   /// Return the abstract type descriptor for this type.
getAbstractType()200   const AbstractType &getAbstractType() { return impl->getAbstractType(); }
201 
202 protected:
203   ImplType *impl;
204 };
205 
206 inline raw_ostream &operator<<(raw_ostream &os, Type type) {
207   type.print(os);
208   return os;
209 }
210 
211 //===----------------------------------------------------------------------===//
212 // TypeTraitBase
213 //===----------------------------------------------------------------------===//
214 
215 namespace TypeTrait {
216 /// This class represents the base of a type trait.
217 template <typename ConcreteType, template <typename> class TraitType>
218 using TraitBase = detail::StorageUserTraitBase<ConcreteType, TraitType>;
219 } // namespace TypeTrait
220 
221 //===----------------------------------------------------------------------===//
222 // TypeInterface
223 //===----------------------------------------------------------------------===//
224 
225 /// This class represents the base of a type interface. See the definition  of
226 /// `detail::Interface` for requirements on the `Traits` type.
227 template <typename ConcreteType, typename Traits>
228 class TypeInterface : public detail::Interface<ConcreteType, Type, Traits, Type,
229                                                TypeTrait::TraitBase> {
230 public:
231   using Base = TypeInterface<ConcreteType, Traits>;
232   using InterfaceBase =
233       detail::Interface<ConcreteType, Type, Traits, Type, TypeTrait::TraitBase>;
234   using InterfaceBase::InterfaceBase;
235 
236 private:
237   /// Returns the impl interface instance for the given type.
getInterfaceFor(Type type)238   static typename InterfaceBase::Concept *getInterfaceFor(Type type) {
239     return type.getAbstractType().getInterface<ConcreteType>();
240   }
241 
242   /// Allow access to 'getInterfaceFor'.
243   friend InterfaceBase;
244 };
245 
246 //===----------------------------------------------------------------------===//
247 // FunctionType
248 //===----------------------------------------------------------------------===//
249 
250 /// Function types map from a list of inputs to a list of results.
251 class FunctionType
252     : public Type::TypeBase<FunctionType, Type, detail::FunctionTypeStorage> {
253 public:
254   using Base::Base;
255 
256   static FunctionType get(ArrayRef<Type> inputs, ArrayRef<Type> results,
257                           MLIRContext *context);
258 
259   // Input types.
getNumInputs()260   unsigned getNumInputs() const { return getSubclassData(); }
261 
getInput(unsigned i)262   Type getInput(unsigned i) const { return getInputs()[i]; }
263 
264   ArrayRef<Type> getInputs() const;
265 
266   // Result types.
267   unsigned getNumResults() const;
268 
getResult(unsigned i)269   Type getResult(unsigned i) const { return getResults()[i]; }
270 
271   ArrayRef<Type> getResults() const;
272 
273   /// Methods for support type inquiry through isa, cast, and dyn_cast.
kindof(unsigned kind)274   static bool kindof(unsigned kind) { return kind == Kind::Function; }
275 };
276 
277 //===----------------------------------------------------------------------===//
278 // OpaqueType
279 //===----------------------------------------------------------------------===//
280 
281 /// Opaque types represent types of non-registered dialects. These are types
282 /// represented in their raw string form, and can only usefully be tested for
283 /// type equality.
284 class OpaqueType
285     : public Type::TypeBase<OpaqueType, Type, detail::OpaqueTypeStorage> {
286 public:
287   using Base::Base;
288 
289   /// Get or create a new OpaqueType with the provided dialect and string data.
290   static OpaqueType get(Identifier dialect, StringRef typeData,
291                         MLIRContext *context);
292 
293   /// Get or create a new OpaqueType with the provided dialect and string data.
294   /// If the given identifier is not a valid namespace for a dialect, then a
295   /// null type is returned.
296   static OpaqueType getChecked(Identifier dialect, StringRef typeData,
297                                MLIRContext *context, Location location);
298 
299   /// Returns the dialect namespace of the opaque type.
300   Identifier getDialectNamespace() const;
301 
302   /// Returns the raw type data of the opaque type.
303   StringRef getTypeData() const;
304 
305   /// Verify the construction of an opaque type.
306   static LogicalResult verifyConstructionInvariants(Location loc,
307                                                     Identifier dialect,
308                                                     StringRef typeData);
309 
kindof(unsigned kind)310   static bool kindof(unsigned kind) { return kind == Kind::Opaque; }
311 };
312 
313 // Make Type hashable.
hash_value(Type arg)314 inline ::llvm::hash_code hash_value(Type arg) {
315   return ::llvm::hash_value(arg.impl);
316 }
317 
isa()318 template <typename U> bool Type::isa() const {
319   assert(impl && "isa<> used on a null type.");
320   return U::classof(*this);
321 }
322 
323 template <typename First, typename Second, typename... Rest>
isa()324 bool Type::isa() const {
325   return isa<First>() || isa<Second, Rest...>();
326 }
327 
dyn_cast()328 template <typename U> U Type::dyn_cast() const {
329   return isa<U>() ? U(impl) : U(nullptr);
330 }
dyn_cast_or_null()331 template <typename U> U Type::dyn_cast_or_null() const {
332   return (impl && isa<U>()) ? U(impl) : U(nullptr);
333 }
cast()334 template <typename U> U Type::cast() const {
335   assert(isa<U>());
336   return U(impl);
337 }
338 
339 } // end namespace mlir
340 
341 namespace llvm {
342 
343 // Type hash just like pointers.
344 template <> struct DenseMapInfo<mlir::Type> {
345   static mlir::Type getEmptyKey() {
346     auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
347     return mlir::Type(static_cast<mlir::Type::ImplType *>(pointer));
348   }
349   static mlir::Type getTombstoneKey() {
350     auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
351     return mlir::Type(static_cast<mlir::Type::ImplType *>(pointer));
352   }
353   static unsigned getHashValue(mlir::Type val) { return mlir::hash_value(val); }
354   static bool isEqual(mlir::Type LHS, mlir::Type RHS) { return LHS == RHS; }
355 };
356 
357 /// We align TypeStorage by 8, so allow LLVM to steal the low bits.
358 template <> struct PointerLikeTypeTraits<mlir::Type> {
359 public:
360   static inline void *getAsVoidPointer(mlir::Type I) {
361     return const_cast<void *>(I.getAsOpaquePointer());
362   }
363   static inline mlir::Type getFromVoidPointer(void *P) {
364     return mlir::Type::getFromOpaquePointer(P);
365   }
366   static constexpr int NumLowBitsAvailable = 3;
367 };
368 
369 } // namespace llvm
370 
371 #endif // MLIR_IR_TYPES_H
372