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