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