Coverage Report

Created: 2020-06-26 05:44

/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_