• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- TypeDetail.h - MLIR Type storage details -----------------*- 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 // This holds implementation details of Type.
10 //
11 //===----------------------------------------------------------------------===//
12 #ifndef TYPEDETAIL_H_
13 #define TYPEDETAIL_H_
14 
15 #include "mlir/IR/AffineMap.h"
16 #include "mlir/IR/BuiltinTypes.h"
17 #include "mlir/IR/Identifier.h"
18 #include "mlir/IR/MLIRContext.h"
19 #include "mlir/IR/OperationSupport.h"
20 #include "mlir/IR/TypeRange.h"
21 #include "llvm/ADT/bit.h"
22 #include "llvm/Support/TrailingObjects.h"
23 
24 namespace mlir {
25 
26 class MLIRContext;
27 
28 namespace detail {
29 
30 /// Opaque Type Storage and Uniquing.
31 struct OpaqueTypeStorage : public TypeStorage {
OpaqueTypeStorageOpaqueTypeStorage32   OpaqueTypeStorage(Identifier dialectNamespace, StringRef typeData)
33       : dialectNamespace(dialectNamespace), typeData(typeData) {}
34 
35   /// The hash key used for uniquing.
36   using KeyTy = std::pair<Identifier, StringRef>;
37   bool operator==(const KeyTy &key) const {
38     return key == KeyTy(dialectNamespace, typeData);
39   }
40 
constructOpaqueTypeStorage41   static OpaqueTypeStorage *construct(TypeStorageAllocator &allocator,
42                                       const KeyTy &key) {
43     StringRef tyData = allocator.copyInto(key.second);
44     return new (allocator.allocate<OpaqueTypeStorage>())
45         OpaqueTypeStorage(key.first, tyData);
46   }
47 
48   // The dialect namespace.
49   Identifier dialectNamespace;
50 
51   // The parser type data for this opaque type.
52   StringRef typeData;
53 };
54 
55 /// Integer Type Storage and Uniquing.
56 struct IntegerTypeStorage : public TypeStorage {
IntegerTypeStorageIntegerTypeStorage57   IntegerTypeStorage(unsigned width,
58                      IntegerType::SignednessSemantics signedness)
59       : width(width), signedness(signedness) {}
60 
61   /// The hash key used for uniquing.
62   using KeyTy = std::pair<unsigned, IntegerType::SignednessSemantics>;
63 
hashKeyIntegerTypeStorage64   static llvm::hash_code hashKey(const KeyTy &key) {
65     return llvm::hash_value(key);
66   }
67 
68   bool operator==(const KeyTy &key) const {
69     return KeyTy(width, signedness) == key;
70   }
71 
constructIntegerTypeStorage72   static IntegerTypeStorage *construct(TypeStorageAllocator &allocator,
73                                        KeyTy key) {
74     return new (allocator.allocate<IntegerTypeStorage>())
75         IntegerTypeStorage(key.first, key.second);
76   }
77 
78   unsigned width : 30;
79   IntegerType::SignednessSemantics signedness : 2;
80 };
81 
82 /// Function Type Storage and Uniquing.
83 struct FunctionTypeStorage : public TypeStorage {
FunctionTypeStorageFunctionTypeStorage84   FunctionTypeStorage(unsigned numInputs, unsigned numResults,
85                       Type const *inputsAndResults)
86       : numInputs(numInputs), numResults(numResults),
87         inputsAndResults(inputsAndResults) {}
88 
89   /// The hash key used for uniquing.
90   using KeyTy = std::pair<TypeRange, TypeRange>;
91   bool operator==(const KeyTy &key) const {
92     return key == KeyTy(getInputs(), getResults());
93   }
94 
95   /// Construction.
constructFunctionTypeStorage96   static FunctionTypeStorage *construct(TypeStorageAllocator &allocator,
97                                         const KeyTy &key) {
98     TypeRange inputs = key.first, results = key.second;
99 
100     // Copy the inputs and results into the bump pointer.
101     SmallVector<Type, 16> types;
102     types.reserve(inputs.size() + results.size());
103     types.append(inputs.begin(), inputs.end());
104     types.append(results.begin(), results.end());
105     auto typesList = allocator.copyInto(ArrayRef<Type>(types));
106 
107     // Initialize the memory using placement new.
108     return new (allocator.allocate<FunctionTypeStorage>())
109         FunctionTypeStorage(inputs.size(), results.size(), typesList.data());
110   }
111 
getInputsFunctionTypeStorage112   ArrayRef<Type> getInputs() const {
113     return ArrayRef<Type>(inputsAndResults, numInputs);
114   }
getResultsFunctionTypeStorage115   ArrayRef<Type> getResults() const {
116     return ArrayRef<Type>(inputsAndResults + numInputs, numResults);
117   }
118 
119   unsigned numInputs;
120   unsigned numResults;
121   Type const *inputsAndResults;
122 };
123 
124 /// Shaped Type Storage.
125 struct ShapedTypeStorage : public TypeStorage {
ShapedTypeStorageShapedTypeStorage126   ShapedTypeStorage(Type elementTy) : elementType(elementTy) {}
127 
128   /// The hash key used for uniquing.
129   using KeyTy = Type;
130   bool operator==(const KeyTy &key) const { return key == elementType; }
131 
132   Type elementType;
133 };
134 
135 /// Vector Type Storage and Uniquing.
136 struct VectorTypeStorage : public ShapedTypeStorage {
VectorTypeStorageVectorTypeStorage137   VectorTypeStorage(unsigned shapeSize, Type elementTy,
138                     const int64_t *shapeElements)
139       : ShapedTypeStorage(elementTy), shapeElements(shapeElements),
140         shapeSize(shapeSize) {}
141 
142   /// The hash key used for uniquing.
143   using KeyTy = std::pair<ArrayRef<int64_t>, Type>;
144   bool operator==(const KeyTy &key) const {
145     return key == KeyTy(getShape(), elementType);
146   }
147 
148   /// Construction.
constructVectorTypeStorage149   static VectorTypeStorage *construct(TypeStorageAllocator &allocator,
150                                       const KeyTy &key) {
151     // Copy the shape into the bump pointer.
152     ArrayRef<int64_t> shape = allocator.copyInto(key.first);
153 
154     // Initialize the memory using placement new.
155     return new (allocator.allocate<VectorTypeStorage>())
156         VectorTypeStorage(shape.size(), key.second, shape.data());
157   }
158 
getShapeVectorTypeStorage159   ArrayRef<int64_t> getShape() const {
160     return ArrayRef<int64_t>(shapeElements, shapeSize);
161   }
162 
163   const int64_t *shapeElements;
164   unsigned shapeSize;
165 };
166 
167 struct RankedTensorTypeStorage : public ShapedTypeStorage {
RankedTensorTypeStorageRankedTensorTypeStorage168   RankedTensorTypeStorage(unsigned shapeSize, Type elementTy,
169                           const int64_t *shapeElements)
170       : ShapedTypeStorage(elementTy), shapeElements(shapeElements),
171         shapeSize(shapeSize) {}
172 
173   /// The hash key used for uniquing.
174   using KeyTy = std::pair<ArrayRef<int64_t>, Type>;
175   bool operator==(const KeyTy &key) const {
176     return key == KeyTy(getShape(), elementType);
177   }
178 
179   /// Construction.
constructRankedTensorTypeStorage180   static RankedTensorTypeStorage *construct(TypeStorageAllocator &allocator,
181                                             const KeyTy &key) {
182     // Copy the shape into the bump pointer.
183     ArrayRef<int64_t> shape = allocator.copyInto(key.first);
184 
185     // Initialize the memory using placement new.
186     return new (allocator.allocate<RankedTensorTypeStorage>())
187         RankedTensorTypeStorage(shape.size(), key.second, shape.data());
188   }
189 
getShapeRankedTensorTypeStorage190   ArrayRef<int64_t> getShape() const {
191     return ArrayRef<int64_t>(shapeElements, shapeSize);
192   }
193 
194   const int64_t *shapeElements;
195   unsigned shapeSize;
196 };
197 
198 struct UnrankedTensorTypeStorage : public ShapedTypeStorage {
199   using ShapedTypeStorage::KeyTy;
200   using ShapedTypeStorage::ShapedTypeStorage;
201 
202   /// Construction.
constructUnrankedTensorTypeStorage203   static UnrankedTensorTypeStorage *construct(TypeStorageAllocator &allocator,
204                                               Type elementTy) {
205     return new (allocator.allocate<UnrankedTensorTypeStorage>())
206         UnrankedTensorTypeStorage(elementTy);
207   }
208 };
209 
210 struct BaseMemRefTypeStorage : public ShapedTypeStorage {
BaseMemRefTypeStorageBaseMemRefTypeStorage211   BaseMemRefTypeStorage(Type elementType, unsigned memorySpace)
212       : ShapedTypeStorage(elementType), memorySpace(memorySpace) {}
213 
214   /// Memory space in which data referenced by memref resides.
215   const unsigned memorySpace;
216 };
217 
218 struct MemRefTypeStorage : public BaseMemRefTypeStorage {
MemRefTypeStorageMemRefTypeStorage219   MemRefTypeStorage(unsigned shapeSize, Type elementType,
220                     const int64_t *shapeElements, const unsigned numAffineMaps,
221                     AffineMap const *affineMapList, const unsigned memorySpace)
222       : BaseMemRefTypeStorage(elementType, memorySpace),
223         shapeElements(shapeElements), shapeSize(shapeSize),
224         numAffineMaps(numAffineMaps), affineMapList(affineMapList) {}
225 
226   /// The hash key used for uniquing.
227   // MemRefs are uniqued based on their shape, element type, affine map
228   // composition, and memory space.
229   using KeyTy =
230       std::tuple<ArrayRef<int64_t>, Type, ArrayRef<AffineMap>, unsigned>;
231   bool operator==(const KeyTy &key) const {
232     return key == KeyTy(getShape(), elementType, getAffineMaps(), memorySpace);
233   }
234 
235   /// Construction.
constructMemRefTypeStorage236   static MemRefTypeStorage *construct(TypeStorageAllocator &allocator,
237                                       const KeyTy &key) {
238     // Copy the shape into the bump pointer.
239     ArrayRef<int64_t> shape = allocator.copyInto(std::get<0>(key));
240 
241     // Copy the affine map composition into the bump pointer.
242     ArrayRef<AffineMap> affineMapComposition =
243         allocator.copyInto(std::get<2>(key));
244 
245     // Initialize the memory using placement new.
246     return new (allocator.allocate<MemRefTypeStorage>())
247         MemRefTypeStorage(shape.size(), std::get<1>(key), shape.data(),
248                           affineMapComposition.size(),
249                           affineMapComposition.data(), std::get<3>(key));
250   }
251 
getShapeMemRefTypeStorage252   ArrayRef<int64_t> getShape() const {
253     return ArrayRef<int64_t>(shapeElements, shapeSize);
254   }
255 
getAffineMapsMemRefTypeStorage256   ArrayRef<AffineMap> getAffineMaps() const {
257     return ArrayRef<AffineMap>(affineMapList, numAffineMaps);
258   }
259 
260   /// An array of integers which stores the shape dimension sizes.
261   const int64_t *shapeElements;
262   /// The number of shape elements.
263   unsigned shapeSize;
264   /// The number of affine maps in the 'affineMapList' array.
265   const unsigned numAffineMaps;
266   /// List of affine maps in the memref's layout/index map composition.
267   AffineMap const *affineMapList;
268 };
269 
270 /// Unranked MemRef is a MemRef with unknown rank.
271 /// Only element type and memory space are known
272 struct UnrankedMemRefTypeStorage : public BaseMemRefTypeStorage {
273 
UnrankedMemRefTypeStorageUnrankedMemRefTypeStorage274   UnrankedMemRefTypeStorage(Type elementTy, const unsigned memorySpace)
275       : BaseMemRefTypeStorage(elementTy, memorySpace) {}
276 
277   /// The hash key used for uniquing.
278   using KeyTy = std::tuple<Type, unsigned>;
279   bool operator==(const KeyTy &key) const {
280     return key == KeyTy(elementType, memorySpace);
281   }
282 
283   /// Construction.
constructUnrankedMemRefTypeStorage284   static UnrankedMemRefTypeStorage *construct(TypeStorageAllocator &allocator,
285                                               const KeyTy &key) {
286 
287     // Initialize the memory using placement new.
288     return new (allocator.allocate<UnrankedMemRefTypeStorage>())
289         UnrankedMemRefTypeStorage(std::get<0>(key), std::get<1>(key));
290   }
291 };
292 
293 /// Complex Type Storage.
294 struct ComplexTypeStorage : public TypeStorage {
ComplexTypeStorageComplexTypeStorage295   ComplexTypeStorage(Type elementType) : elementType(elementType) {}
296 
297   /// The hash key used for uniquing.
298   using KeyTy = Type;
299   bool operator==(const KeyTy &key) const { return key == elementType; }
300 
301   /// Construction.
constructComplexTypeStorage302   static ComplexTypeStorage *construct(TypeStorageAllocator &allocator,
303                                        Type elementType) {
304     return new (allocator.allocate<ComplexTypeStorage>())
305         ComplexTypeStorage(elementType);
306   }
307 
308   Type elementType;
309 };
310 
311 /// A type representing a collection of other types.
312 struct TupleTypeStorage final
313     : public TypeStorage,
314       public llvm::TrailingObjects<TupleTypeStorage, Type> {
315   using KeyTy = TypeRange;
316 
TupleTypeStoragefinal317   TupleTypeStorage(unsigned numTypes) : numElements(numTypes) {}
318 
319   /// Construction.
constructfinal320   static TupleTypeStorage *construct(TypeStorageAllocator &allocator,
321                                      TypeRange key) {
322     // Allocate a new storage instance.
323     auto byteSize = TupleTypeStorage::totalSizeToAlloc<Type>(key.size());
324     auto rawMem = allocator.allocate(byteSize, alignof(TupleTypeStorage));
325     auto result = ::new (rawMem) TupleTypeStorage(key.size());
326 
327     // Copy in the element types into the trailing storage.
328     std::uninitialized_copy(key.begin(), key.end(),
329                             result->getTrailingObjects<Type>());
330     return result;
331   }
332 
333   bool operator==(const KeyTy &key) const { return key == getTypes(); }
334 
335   /// Return the number of held types.
sizefinal336   unsigned size() const { return numElements; }
337 
338   /// Return the held types.
getTypesfinal339   ArrayRef<Type> getTypes() const {
340     return {getTrailingObjects<Type>(), size()};
341   }
342 
343   /// The number of tuple elements.
344   unsigned numElements;
345 };
346 
347 } // namespace detail
348 } // namespace mlir
349 
350 #endif // TYPEDETAIL_H_
351