blob: 4963000b0174921645ddc52006e8143240aeb6ca [file] [log] [blame]
Chris Lattnerf7e22732018-06-22 22:03:48 -07001//===- MLIRContext.cpp - MLIR Type Classes --------------------------------===//
2//
3// Copyright 2019 The MLIR Authors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// =============================================================================
17
18#include "mlir/IR/MLIRContext.h"
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -070019#include "AttributeListStorage.h"
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070020#include "mlir/IR/AffineExpr.h"
21#include "mlir/IR/AffineMap.h"
Chris Lattner36b4ed12018-07-04 10:43:29 -070022#include "mlir/IR/Attributes.h"
23#include "mlir/IR/Identifier.h"
Chris Lattnerff0d5902018-07-05 09:12:11 -070024#include "mlir/IR/OperationSet.h"
25#include "mlir/IR/StandardOps.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070026#include "mlir/IR/Types.h"
Chris Lattner36b4ed12018-07-04 10:43:29 -070027#include "mlir/Support/STLExtras.h"
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -070028#include "third_party/llvm/llvm/include/llvm/ADT/STLExtras.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070029#include "llvm/ADT/DenseSet.h"
Chris Lattnered65a732018-06-28 20:45:33 -070030#include "llvm/ADT/StringMap.h"
Chris Lattnerf7e22732018-06-22 22:03:48 -070031#include "llvm/Support/Allocator.h"
32using namespace mlir;
33using namespace llvm;
34
35namespace {
James Molloy87d81022018-07-23 11:44:40 -070036struct FunctionTypeKeyInfo : DenseMapInfo<FunctionType *> {
Chris Lattnerf7e22732018-06-22 22:03:48 -070037 // Functions are uniqued based on their inputs and results.
James Molloy87d81022018-07-23 11:44:40 -070038 using KeyTy = std::pair<ArrayRef<Type *>, ArrayRef<Type *>>;
39 using DenseMapInfo<FunctionType *>::getHashValue;
40 using DenseMapInfo<FunctionType *>::isEqual;
Chris Lattnerf7e22732018-06-22 22:03:48 -070041
42 static unsigned getHashValue(KeyTy key) {
James Molloy87d81022018-07-23 11:44:40 -070043 return hash_combine(
44 hash_combine_range(key.first.begin(), key.first.end()),
45 hash_combine_range(key.second.begin(), key.second.end()));
Chris Lattnerf7e22732018-06-22 22:03:48 -070046 }
47
48 static bool isEqual(const KeyTy &lhs, const FunctionType *rhs) {
49 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
50 return false;
51 return lhs == KeyTy(rhs->getInputs(), rhs->getResults());
52 }
53};
Uday Bondhugula015cbb12018-07-03 20:16:08 -070054
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070055struct AffineMapKeyInfo : DenseMapInfo<AffineMap *> {
Uday Bondhugula015cbb12018-07-03 20:16:08 -070056 // Affine maps are uniqued based on their dim/symbol counts and affine
57 // expressions.
Uday Bondhugula0115dbb2018-07-11 21:31:07 -070058 using KeyTy = std::tuple<unsigned, unsigned, ArrayRef<AffineExpr *>,
59 ArrayRef<AffineExpr *>>;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070060 using DenseMapInfo<AffineMap *>::getHashValue;
61 using DenseMapInfo<AffineMap *>::isEqual;
62
63 static unsigned getHashValue(KeyTy key) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -070064 return hash_combine(
Chris Lattner36b4ed12018-07-04 10:43:29 -070065 std::get<0>(key), std::get<1>(key),
Uday Bondhugula0115dbb2018-07-11 21:31:07 -070066 hash_combine_range(std::get<2>(key).begin(), std::get<2>(key).end()),
67 hash_combine_range(std::get<3>(key).begin(), std::get<3>(key).end()));
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070068 }
69
Uday Bondhugula015cbb12018-07-03 20:16:08 -070070 static bool isEqual(const KeyTy &lhs, const AffineMap *rhs) {
71 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
72 return false;
Chris Lattner36b4ed12018-07-04 10:43:29 -070073 return lhs == std::make_tuple(rhs->getNumDims(), rhs->getNumSymbols(),
Uday Bondhugula0115dbb2018-07-11 21:31:07 -070074 rhs->getResults(), rhs->getRangeSizes());
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -070075 }
76};
77
James Molloy87d81022018-07-23 11:44:40 -070078struct VectorTypeKeyInfo : DenseMapInfo<VectorType *> {
Chris Lattnerf7e22732018-06-22 22:03:48 -070079 // Vectors are uniqued based on their element type and shape.
James Molloy87d81022018-07-23 11:44:40 -070080 using KeyTy = std::pair<Type *, ArrayRef<unsigned>>;
81 using DenseMapInfo<VectorType *>::getHashValue;
82 using DenseMapInfo<VectorType *>::isEqual;
Chris Lattnerf7e22732018-06-22 22:03:48 -070083
84 static unsigned getHashValue(KeyTy key) {
James Molloy87d81022018-07-23 11:44:40 -070085 return hash_combine(
86 DenseMapInfo<Type *>::getHashValue(key.first),
87 hash_combine_range(key.second.begin(), key.second.end()));
Chris Lattnerf7e22732018-06-22 22:03:48 -070088 }
89
90 static bool isEqual(const KeyTy &lhs, const VectorType *rhs) {
91 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
92 return false;
93 return lhs == KeyTy(rhs->getElementType(), rhs->getShape());
94 }
95};
Chris Lattner36b4ed12018-07-04 10:43:29 -070096
James Molloy87d81022018-07-23 11:44:40 -070097struct RankedTensorTypeKeyInfo : DenseMapInfo<RankedTensorType *> {
MLIR Team355ec862018-06-23 18:09:09 -070098 // Ranked tensors are uniqued based on their element type and shape.
James Molloy87d81022018-07-23 11:44:40 -070099 using KeyTy = std::pair<Type *, ArrayRef<int>>;
100 using DenseMapInfo<RankedTensorType *>::getHashValue;
101 using DenseMapInfo<RankedTensorType *>::isEqual;
MLIR Team355ec862018-06-23 18:09:09 -0700102
103 static unsigned getHashValue(KeyTy key) {
James Molloy87d81022018-07-23 11:44:40 -0700104 return hash_combine(
105 DenseMapInfo<Type *>::getHashValue(key.first),
106 hash_combine_range(key.second.begin(), key.second.end()));
MLIR Team355ec862018-06-23 18:09:09 -0700107 }
108
109 static bool isEqual(const KeyTy &lhs, const RankedTensorType *rhs) {
110 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
111 return false;
112 return lhs == KeyTy(rhs->getElementType(), rhs->getShape());
113 }
114};
Chris Lattner36b4ed12018-07-04 10:43:29 -0700115
James Molloy87d81022018-07-23 11:44:40 -0700116struct MemRefTypeKeyInfo : DenseMapInfo<MemRefType *> {
MLIR Team718c82f2018-07-16 09:45:22 -0700117 // MemRefs are uniqued based on their element type, shape, affine map
118 // composition, and memory space.
James Molloy87d81022018-07-23 11:44:40 -0700119 using KeyTy =
120 std::tuple<Type *, ArrayRef<int>, ArrayRef<AffineMap *>, unsigned>;
121 using DenseMapInfo<MemRefType *>::getHashValue;
122 using DenseMapInfo<MemRefType *>::isEqual;
MLIR Team718c82f2018-07-16 09:45:22 -0700123
124 static unsigned getHashValue(KeyTy key) {
125 return hash_combine(
James Molloy87d81022018-07-23 11:44:40 -0700126 DenseMapInfo<Type *>::getHashValue(std::get<0>(key)),
MLIR Team718c82f2018-07-16 09:45:22 -0700127 hash_combine_range(std::get<1>(key).begin(), std::get<1>(key).end()),
128 hash_combine_range(std::get<2>(key).begin(), std::get<2>(key).end()),
129 std::get<3>(key));
130 }
131
132 static bool isEqual(const KeyTy &lhs, const MemRefType *rhs) {
133 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
134 return false;
135 return lhs == std::make_tuple(rhs->getElementType(), rhs->getShape(),
136 rhs->getAffineMaps(), rhs->getMemorySpace());
137 }
138};
139
James Molloy87d81022018-07-23 11:44:40 -0700140struct ArrayAttrKeyInfo : DenseMapInfo<ArrayAttr *> {
Chris Lattner36b4ed12018-07-04 10:43:29 -0700141 // Array attributes are uniqued based on their elements.
James Molloy87d81022018-07-23 11:44:40 -0700142 using KeyTy = ArrayRef<Attribute *>;
143 using DenseMapInfo<ArrayAttr *>::getHashValue;
144 using DenseMapInfo<ArrayAttr *>::isEqual;
Chris Lattner36b4ed12018-07-04 10:43:29 -0700145
146 static unsigned getHashValue(KeyTy key) {
147 return hash_combine_range(key.begin(), key.end());
148 }
149
150 static bool isEqual(const KeyTy &lhs, const ArrayAttr *rhs) {
151 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
152 return false;
153 return lhs == rhs->getValue();
154 }
155};
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -0700156
157struct AttributeListKeyInfo : DenseMapInfo<AttributeListStorage *> {
158 // Array attributes are uniqued based on their elements.
159 using KeyTy = ArrayRef<NamedAttribute>;
160 using DenseMapInfo<AttributeListStorage *>::getHashValue;
161 using DenseMapInfo<AttributeListStorage *>::isEqual;
162
163 static unsigned getHashValue(KeyTy key) {
164 return hash_combine_range(key.begin(), key.end());
165 }
166
167 static bool isEqual(const KeyTy &lhs, const AttributeListStorage *rhs) {
168 if (rhs == getEmptyKey() || rhs == getTombstoneKey())
169 return false;
170 return lhs == rhs->getElements();
171 }
172};
173
Chris Lattnerf7e22732018-06-22 22:03:48 -0700174} // end anonymous namespace.
175
Chris Lattnerf7e22732018-06-22 22:03:48 -0700176namespace mlir {
177/// This is the implementation of the MLIRContext class, using the pImpl idiom.
178/// This class is completely private to this file, so everything is public.
179class MLIRContextImpl {
180public:
181 /// We put immortal objects into this allocator.
182 llvm::BumpPtrAllocator allocator;
183
Chris Lattnerff0d5902018-07-05 09:12:11 -0700184 /// This is the set of all operations that are registered with the system.
185 OperationSet operationSet;
186
Chris Lattnered65a732018-06-28 20:45:33 -0700187 /// These are identifiers uniqued into this MLIRContext.
James Molloy87d81022018-07-23 11:44:40 -0700188 llvm::StringMap<char, llvm::BumpPtrAllocator &> identifiers;
Chris Lattnered65a732018-06-28 20:45:33 -0700189
Chris Lattnerc3251192018-07-27 13:09:58 -0700190 // Uniquing table for 'other' types.
191 OtherType *otherTypes[int(Type::Kind::LAST_OTHER_TYPE) -
192 int(Type::Kind::FIRST_OTHER_TYPE) + 1] = {nullptr};
193
194 // Uniquing table for 'float' types.
195 FloatType *floatTypes[int(Type::Kind::LAST_FLOATING_POINT_TYPE) -
196 int(Type::Kind::FIRST_FLOATING_POINT_TYPE) + 1] = {
James Molloy87d81022018-07-23 11:44:40 -0700197 nullptr};
Chris Lattnerf7e22732018-06-22 22:03:48 -0700198
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700199 // Affine map uniquing.
200 using AffineMapSet = DenseSet<AffineMap *, AffineMapKeyInfo>;
201 AffineMapSet affineMaps;
202
Uday Bondhugula0b80a162018-07-03 21:34:58 -0700203 // Affine binary op expression uniquing. Figure out uniquing of dimensional
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700204 // or symbolic identifiers.
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700205 DenseMap<std::tuple<unsigned, AffineExpr *, AffineExpr *>, AffineExpr *>
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700206 affineExprs;
207
Uday Bondhugula4e5078b2018-07-24 22:34:09 -0700208 // Uniqui'ing of AffineDimExpr, AffineSymbolExpr's by their position.
209 std::vector<AffineDimExpr *> dimExprs;
210 std::vector<AffineSymbolExpr *> symbolExprs;
211
212 // Uniqui'ing of AffineConstantExpr using constant value as key.
213 DenseMap<int64_t, AffineConstantExpr *> constExprs;
214
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700215 /// Integer type uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700216 DenseMap<unsigned, IntegerType *> integers;
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700217
Chris Lattnerf7e22732018-06-22 22:03:48 -0700218 /// Function type uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700219 using FunctionTypeSet = DenseSet<FunctionType *, FunctionTypeKeyInfo>;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700220 FunctionTypeSet functions;
221
222 /// Vector type uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700223 using VectorTypeSet = DenseSet<VectorType *, VectorTypeKeyInfo>;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700224 VectorTypeSet vectors;
225
MLIR Team355ec862018-06-23 18:09:09 -0700226 /// Ranked tensor type uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700227 using RankedTensorTypeSet =
228 DenseSet<RankedTensorType *, RankedTensorTypeKeyInfo>;
MLIR Team355ec862018-06-23 18:09:09 -0700229 RankedTensorTypeSet rankedTensors;
230
231 /// Unranked tensor type uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700232 DenseMap<Type *, UnrankedTensorType *> unrankedTensors;
MLIR Team355ec862018-06-23 18:09:09 -0700233
MLIR Team718c82f2018-07-16 09:45:22 -0700234 /// MemRef type uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700235 using MemRefTypeSet = DenseSet<MemRefType *, MemRefTypeKeyInfo>;
MLIR Team718c82f2018-07-16 09:45:22 -0700236 MemRefTypeSet memrefs;
237
Chris Lattner36b4ed12018-07-04 10:43:29 -0700238 // Attribute uniquing.
James Molloy87d81022018-07-23 11:44:40 -0700239 BoolAttr *boolAttrs[2] = {nullptr};
240 DenseMap<int64_t, IntegerAttr *> integerAttrs;
241 DenseMap<int64_t, FloatAttr *> floatAttrs;
242 StringMap<StringAttr *> stringAttrs;
243 using ArrayAttrSet = DenseSet<ArrayAttr *, ArrayAttrKeyInfo>;
Chris Lattner36b4ed12018-07-04 10:43:29 -0700244 ArrayAttrSet arrayAttrs;
James Molloy87d81022018-07-23 11:44:40 -0700245 DenseMap<AffineMap *, AffineMapAttr *> affineMapAttrs;
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -0700246 using AttributeListSet =
247 DenseSet<AttributeListStorage *, AttributeListKeyInfo>;
248 AttributeListSet attributeLists;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700249
250public:
Chris Lattnerff0d5902018-07-05 09:12:11 -0700251 MLIRContextImpl() : identifiers(allocator) {
252 registerStandardOperations(operationSet);
253 }
Chris Lattnered65a732018-06-28 20:45:33 -0700254
Chris Lattnerf7e22732018-06-22 22:03:48 -0700255 /// Copy the specified array of elements into memory managed by our bump
256 /// pointer allocator. This assumes the elements are all PODs.
James Molloy87d81022018-07-23 11:44:40 -0700257 template <typename T> ArrayRef<T> copyInto(ArrayRef<T> elements) {
Chris Lattnerf7e22732018-06-22 22:03:48 -0700258 auto result = allocator.Allocate<T>(elements.size());
259 std::uninitialized_copy(elements.begin(), elements.end(), result);
260 return ArrayRef<T>(result, elements.size());
261 }
262};
263} // end namespace mlir
264
James Molloy87d81022018-07-23 11:44:40 -0700265MLIRContext::MLIRContext() : impl(new MLIRContextImpl()) {}
Chris Lattnerf7e22732018-06-22 22:03:48 -0700266
James Molloy87d81022018-07-23 11:44:40 -0700267MLIRContext::~MLIRContext() {}
Chris Lattnerf7e22732018-06-22 22:03:48 -0700268
Chris Lattnerff0d5902018-07-05 09:12:11 -0700269/// Return the operation set associated with the specified MLIRContext object.
270OperationSet &OperationSet::get(MLIRContext *context) {
271 return context->getImpl().operationSet;
272}
Chris Lattnerf7e22732018-06-22 22:03:48 -0700273
Chris Lattner21e67f62018-07-06 10:46:19 -0700274/// If this operation has a registered operation description in the
275/// OperationSet, return it. Otherwise return null.
276/// TODO: Shouldn't have to pass a Context here.
277const AbstractOperation *
278Operation::getAbstractOperation(MLIRContext *context) const {
279 return OperationSet::get(context).lookup(getName().str());
280}
281
Chris Lattnered65a732018-06-28 20:45:33 -0700282//===----------------------------------------------------------------------===//
Chris Lattner36b4ed12018-07-04 10:43:29 -0700283// Identifier uniquing
Chris Lattnered65a732018-06-28 20:45:33 -0700284//===----------------------------------------------------------------------===//
285
286/// Return an identifier for the specified string.
287Identifier Identifier::get(StringRef str, const MLIRContext *context) {
288 assert(!str.empty() && "Cannot create an empty identifier");
289 assert(str.find('\0') == StringRef::npos &&
290 "Cannot create an identifier with a nul character");
291
292 auto &impl = context->getImpl();
293 auto it = impl.identifiers.insert({str, char()}).first;
294 return Identifier(it->getKeyData());
295}
296
Chris Lattnered65a732018-06-28 20:45:33 -0700297//===----------------------------------------------------------------------===//
Chris Lattner36b4ed12018-07-04 10:43:29 -0700298// Type uniquing
Chris Lattnered65a732018-06-28 20:45:33 -0700299//===----------------------------------------------------------------------===//
300
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700301IntegerType *IntegerType::get(unsigned width, MLIRContext *context) {
302 auto &impl = context->getImpl();
303
304 auto *&result = impl.integers[width];
305 if (!result) {
306 result = impl.allocator.Allocate<IntegerType>();
307 new (result) IntegerType(width, context);
308 }
309
310 return result;
Chris Lattnerf7e22732018-06-22 22:03:48 -0700311}
312
Chris Lattnerc3251192018-07-27 13:09:58 -0700313FloatType *FloatType::get(Kind kind, MLIRContext *context) {
314 assert(kind >= Kind::FIRST_FLOATING_POINT_TYPE &&
315 kind <= Kind::LAST_FLOATING_POINT_TYPE && "Not an FP type kind");
316 auto &impl = context->getImpl();
317
318 // We normally have these types.
319 auto *&entry =
320 impl.floatTypes[(int)kind - int(Kind::FIRST_FLOATING_POINT_TYPE)];
321 if (entry)
322 return entry;
323
324 // On the first use, we allocate them into the bump pointer.
325 auto *ptr = impl.allocator.Allocate<FloatType>();
326
327 // Initialize the memory using placement new.
328 new (ptr) FloatType(kind, context);
329
330 // Cache and return it.
331 return entry = ptr;
332}
333
334OtherType *OtherType::get(Kind kind, MLIRContext *context) {
335 assert(kind >= Kind::FIRST_OTHER_TYPE && kind <= Kind::LAST_OTHER_TYPE &&
336 "Not an 'other' type kind");
337 auto &impl = context->getImpl();
338
339 // We normally have these types.
340 auto *&entry = impl.otherTypes[(int)kind - int(Kind::FIRST_OTHER_TYPE)];
341 if (entry)
342 return entry;
343
344 // On the first use, we allocate them into the bump pointer.
345 auto *ptr = impl.allocator.Allocate<OtherType>();
346
347 // Initialize the memory using placement new.
348 new (ptr) OtherType(kind, context);
349
350 // Cache and return it.
351 return entry = ptr;
352}
353
James Molloy87d81022018-07-23 11:44:40 -0700354FunctionType *FunctionType::get(ArrayRef<Type *> inputs,
355 ArrayRef<Type *> results,
Chris Lattnerf7e22732018-06-22 22:03:48 -0700356 MLIRContext *context) {
357 auto &impl = context->getImpl();
358
359 // Look to see if we already have this function type.
360 FunctionTypeKeyInfo::KeyTy key(inputs, results);
361 auto existing = impl.functions.insert_as(nullptr, key);
362
363 // If we already have it, return that value.
364 if (!existing.second)
365 return *existing.first;
366
367 // On the first use, we allocate them into the bump pointer.
368 auto *result = impl.allocator.Allocate<FunctionType>();
369
370 // Copy the inputs and results into the bump pointer.
James Molloy87d81022018-07-23 11:44:40 -0700371 SmallVector<Type *, 16> types;
372 types.reserve(inputs.size() + results.size());
Chris Lattnerf7e22732018-06-22 22:03:48 -0700373 types.append(inputs.begin(), inputs.end());
374 types.append(results.begin(), results.end());
James Molloy87d81022018-07-23 11:44:40 -0700375 auto typesList = impl.copyInto(ArrayRef<Type *>(types));
Chris Lattnerf7e22732018-06-22 22:03:48 -0700376
377 // Initialize the memory using placement new.
James Molloy87d81022018-07-23 11:44:40 -0700378 new (result)
379 FunctionType(typesList.data(), inputs.size(), results.size(), context);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700380
381 // Cache and return it.
382 return *existing.first = result;
383}
384
Chris Lattnerf7e22732018-06-22 22:03:48 -0700385VectorType *VectorType::get(ArrayRef<unsigned> shape, Type *elementType) {
386 assert(!shape.empty() && "vector types must have at least one dimension");
Chris Lattnerc3251192018-07-27 13:09:58 -0700387 assert((isa<FloatType>(elementType) || isa<IntegerType>(elementType)) &&
Chris Lattnerf7e22732018-06-22 22:03:48 -0700388 "vectors elements must be primitives");
389
390 auto *context = elementType->getContext();
391 auto &impl = context->getImpl();
392
393 // Look to see if we already have this vector type.
394 VectorTypeKeyInfo::KeyTy key(elementType, shape);
395 auto existing = impl.vectors.insert_as(nullptr, key);
396
397 // If we already have it, return that value.
398 if (!existing.second)
399 return *existing.first;
400
401 // On the first use, we allocate them into the bump pointer.
402 auto *result = impl.allocator.Allocate<VectorType>();
403
404 // Copy the shape into the bump pointer.
405 shape = impl.copyInto(shape);
406
407 // Initialize the memory using placement new.
Jacques Pienaar3cdb8542018-07-23 11:48:22 -0700408 new (result) VectorType(shape, elementType, context);
Chris Lattnerf7e22732018-06-22 22:03:48 -0700409
410 // Cache and return it.
411 return *existing.first = result;
412}
MLIR Team355ec862018-06-23 18:09:09 -0700413
Chris Lattnereee1a2d2018-07-04 09:13:39 -0700414TensorType::TensorType(Kind kind, Type *elementType, MLIRContext *context)
James Molloy87d81022018-07-23 11:44:40 -0700415 : Type(kind, context), elementType(elementType) {
Chris Lattnerc3251192018-07-27 13:09:58 -0700416 assert((isa<FloatType>(elementType) || isa<VectorType>(elementType) ||
Chris Lattnerf958bbe2018-06-29 22:08:05 -0700417 isa<IntegerType>(elementType)) &&
MLIR Team355ec862018-06-23 18:09:09 -0700418 "tensor elements must be primitives or vectors");
419 assert(isa<TensorType>(this));
420}
421
MLIR Team355ec862018-06-23 18:09:09 -0700422RankedTensorType *RankedTensorType::get(ArrayRef<int> shape,
423 Type *elementType) {
424 auto *context = elementType->getContext();
425 auto &impl = context->getImpl();
426
427 // Look to see if we already have this ranked tensor type.
428 RankedTensorTypeKeyInfo::KeyTy key(elementType, shape);
429 auto existing = impl.rankedTensors.insert_as(nullptr, key);
430
431 // If we already have it, return that value.
432 if (!existing.second)
433 return *existing.first;
434
435 // On the first use, we allocate them into the bump pointer.
436 auto *result = impl.allocator.Allocate<RankedTensorType>();
437
438 // Copy the shape into the bump pointer.
439 shape = impl.copyInto(shape);
440
441 // Initialize the memory using placement new.
442 new (result) RankedTensorType(shape, elementType, context);
443
444 // Cache and return it.
445 return *existing.first = result;
446}
447
448UnrankedTensorType *UnrankedTensorType::get(Type *elementType) {
449 auto *context = elementType->getContext();
450 auto &impl = context->getImpl();
451
452 // Look to see if we already have this unranked tensor type.
Chris Lattner36b4ed12018-07-04 10:43:29 -0700453 auto *&result = impl.unrankedTensors[elementType];
MLIR Team355ec862018-06-23 18:09:09 -0700454
455 // If we already have it, return that value.
Chris Lattner36b4ed12018-07-04 10:43:29 -0700456 if (result)
457 return result;
MLIR Team355ec862018-06-23 18:09:09 -0700458
459 // On the first use, we allocate them into the bump pointer.
Chris Lattner36b4ed12018-07-04 10:43:29 -0700460 result = impl.allocator.Allocate<UnrankedTensorType>();
MLIR Team355ec862018-06-23 18:09:09 -0700461
462 // Initialize the memory using placement new.
463 new (result) UnrankedTensorType(elementType, context);
Chris Lattner36b4ed12018-07-04 10:43:29 -0700464 return result;
465}
466
MLIR Team718c82f2018-07-16 09:45:22 -0700467MemRefType *MemRefType::get(ArrayRef<int> shape, Type *elementType,
James Molloy87d81022018-07-23 11:44:40 -0700468 ArrayRef<AffineMap *> affineMapComposition,
MLIR Team718c82f2018-07-16 09:45:22 -0700469 unsigned memorySpace) {
470 auto *context = elementType->getContext();
471 auto &impl = context->getImpl();
472
473 // Look to see if we already have this memref type.
James Molloy87d81022018-07-23 11:44:40 -0700474 auto key =
475 std::make_tuple(elementType, shape, affineMapComposition, memorySpace);
MLIR Team718c82f2018-07-16 09:45:22 -0700476 auto existing = impl.memrefs.insert_as(nullptr, key);
477
478 // If we already have it, return that value.
479 if (!existing.second)
480 return *existing.first;
481
482 // On the first use, we allocate them into the bump pointer.
483 auto *result = impl.allocator.Allocate<MemRefType>();
484
485 // Copy the shape into the bump pointer.
486 shape = impl.copyInto(shape);
487
488 // Copy the affine map composition into the bump pointer.
489 // TODO(andydavis) Assert that the structure of the composition is valid.
James Molloy87d81022018-07-23 11:44:40 -0700490 affineMapComposition =
491 impl.copyInto(ArrayRef<AffineMap *>(affineMapComposition));
MLIR Team718c82f2018-07-16 09:45:22 -0700492
493 // Initialize the memory using placement new.
494 new (result) MemRefType(shape, elementType, affineMapComposition, memorySpace,
495 context);
496 // Cache and return it.
497 return *existing.first = result;
498}
499
Chris Lattner36b4ed12018-07-04 10:43:29 -0700500//===----------------------------------------------------------------------===//
501// Attribute uniquing
502//===----------------------------------------------------------------------===//
503
504BoolAttr *BoolAttr::get(bool value, MLIRContext *context) {
505 auto *&result = context->getImpl().boolAttrs[value];
506 if (result)
507 return result;
508
509 result = context->getImpl().allocator.Allocate<BoolAttr>();
510 new (result) BoolAttr(value);
511 return result;
512}
513
514IntegerAttr *IntegerAttr::get(int64_t value, MLIRContext *context) {
515 auto *&result = context->getImpl().integerAttrs[value];
516 if (result)
517 return result;
518
519 result = context->getImpl().allocator.Allocate<IntegerAttr>();
520 new (result) IntegerAttr(value);
521 return result;
522}
523
524FloatAttr *FloatAttr::get(double value, MLIRContext *context) {
525 // We hash based on the bit representation of the double to ensure we don't
526 // merge things like -0.0 and 0.0 in the hash comparison.
527 union {
528 double floatValue;
529 int64_t intValue;
530 };
531 floatValue = value;
532
533 auto *&result = context->getImpl().floatAttrs[intValue];
534 if (result)
535 return result;
536
537 result = context->getImpl().allocator.Allocate<FloatAttr>();
538 new (result) FloatAttr(value);
539 return result;
540}
541
542StringAttr *StringAttr::get(StringRef bytes, MLIRContext *context) {
543 auto it = context->getImpl().stringAttrs.insert({bytes, nullptr}).first;
544
545 if (it->second)
546 return it->second;
547
548 auto result = context->getImpl().allocator.Allocate<StringAttr>();
549 new (result) StringAttr(it->first());
550 it->second = result;
551 return result;
552}
553
James Molloy87d81022018-07-23 11:44:40 -0700554ArrayAttr *ArrayAttr::get(ArrayRef<Attribute *> value, MLIRContext *context) {
Chris Lattner36b4ed12018-07-04 10:43:29 -0700555 auto &impl = context->getImpl();
556
557 // Look to see if we already have this.
558 auto existing = impl.arrayAttrs.insert_as(nullptr, value);
559
560 // If we already have it, return that value.
561 if (!existing.second)
562 return *existing.first;
563
564 // On the first use, we allocate them into the bump pointer.
565 auto *result = impl.allocator.Allocate<ArrayAttr>();
566
567 // Copy the elements into the bump pointer.
568 value = impl.copyInto(value);
569
570 // Initialize the memory using placement new.
571 new (result) ArrayAttr(value);
MLIR Team355ec862018-06-23 18:09:09 -0700572
573 // Cache and return it.
Chris Lattner36b4ed12018-07-04 10:43:29 -0700574 return *existing.first = result;
MLIR Team355ec862018-06-23 18:09:09 -0700575}
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700576
James Molloy87d81022018-07-23 11:44:40 -0700577AffineMapAttr *AffineMapAttr::get(AffineMap *value, MLIRContext *context) {
MLIR Teamb61885d2018-07-18 16:29:21 -0700578 auto *&result = context->getImpl().affineMapAttrs[value];
579 if (result)
580 return result;
581
582 result = context->getImpl().allocator.Allocate<AffineMapAttr>();
583 new (result) AffineMapAttr(value);
584 return result;
585}
586
Chris Lattnerdf1a2fc2018-07-05 21:20:59 -0700587/// Perform a three-way comparison between the names of the specified
588/// NamedAttributes.
589static int compareNamedAttributes(const NamedAttribute *lhs,
590 const NamedAttribute *rhs) {
591 return lhs->first.str().compare(rhs->first.str());
592}
593
594/// Given a list of NamedAttribute's, canonicalize the list (sorting
595/// by name) and return the unique'd result. Note that the empty list is
596/// represented with a null pointer.
597AttributeListStorage *AttributeListStorage::get(ArrayRef<NamedAttribute> attrs,
598 MLIRContext *context) {
599 // We need to sort the element list to canonicalize it, but we also don't want
600 // to do a ton of work in the super common case where the element list is
601 // already sorted.
602 SmallVector<NamedAttribute, 8> storage;
603 switch (attrs.size()) {
604 case 0:
605 // An empty list is represented with a null pointer.
606 return nullptr;
607 case 1:
608 // A single element is already sorted.
609 break;
610 case 2:
611 // Don't invoke a general sort for two element case.
612 if (attrs[0].first.str() > attrs[1].first.str()) {
613 storage.push_back(attrs[1]);
614 storage.push_back(attrs[0]);
615 attrs = storage;
616 }
617 break;
618 default:
619 // Check to see they are sorted already.
620 bool isSorted = true;
621 for (unsigned i = 0, e = attrs.size() - 1; i != e; ++i) {
622 if (attrs[i].first.str() > attrs[i + 1].first.str()) {
623 isSorted = false;
624 break;
625 }
626 }
627 // If not, do a general sort.
628 if (!isSorted) {
629 storage.append(attrs.begin(), attrs.end());
630 llvm::array_pod_sort(storage.begin(), storage.end(),
631 compareNamedAttributes);
632 attrs = storage;
633 }
634 }
635
636 // Ok, now that we've canonicalized our attributes, unique them.
637 auto &impl = context->getImpl();
638
639 // Look to see if we already have this.
640 auto existing = impl.attributeLists.insert_as(nullptr, attrs);
641
642 // If we already have it, return that value.
643 if (!existing.second)
644 return *existing.first;
645
646 // Otherwise, allocate a new AttributeListStorage, unique it and return it.
647 auto byteSize =
648 AttributeListStorage::totalSizeToAlloc<NamedAttribute>(attrs.size());
649 auto rawMem = impl.allocator.Allocate(byteSize, alignof(NamedAttribute));
650
651 // Placement initialize the AggregateSymbolicValue.
652 auto result = ::new (rawMem) AttributeListStorage(attrs.size());
653 std::uninitialized_copy(attrs.begin(), attrs.end(),
654 result->getTrailingObjects<NamedAttribute>());
655 return *existing.first = result;
656}
657
Chris Lattner36b4ed12018-07-04 10:43:29 -0700658//===----------------------------------------------------------------------===//
659// AffineMap and AffineExpr uniquing
660//===----------------------------------------------------------------------===//
661
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700662AffineMap *AffineMap::get(unsigned dimCount, unsigned symbolCount,
663 ArrayRef<AffineExpr *> results,
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700664 ArrayRef<AffineExpr *> rangeSizes,
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700665 MLIRContext *context) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700666 // The number of results can't be zero.
667 assert(!results.empty());
668
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700669 assert(rangeSizes.empty() || results.size() == rangeSizes.size());
670
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700671 auto &impl = context->getImpl();
672
673 // Check if we already have this affine map.
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700674 auto key = std::make_tuple(dimCount, symbolCount, results, rangeSizes);
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700675 auto existing = impl.affineMaps.insert_as(nullptr, key);
676
677 // If we already have it, return that value.
678 if (!existing.second)
679 return *existing.first;
680
681 // On the first use, we allocate them into the bump pointer.
682 auto *res = impl.allocator.Allocate<AffineMap>();
683
Uday Bondhugula1e500b42018-07-12 18:04:04 -0700684 // Copy the results and range sizes into the bump pointer.
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700685 results = impl.copyInto(ArrayRef<AffineExpr *>(results));
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700686 rangeSizes = impl.copyInto(ArrayRef<AffineExpr *>(rangeSizes));
687
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700688 // Initialize the memory using placement new.
Uday Bondhugula0115dbb2018-07-11 21:31:07 -0700689 new (res) AffineMap(dimCount, symbolCount, results.size(), results.data(),
690 rangeSizes.empty() ? nullptr : rangeSizes.data());
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700691
692 // Cache and return it.
693 return *existing.first = res;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700694}
695
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700696/// Return a binary affine op expression with the specified op type and
697/// operands: if it doesn't exist, create it and store it; if it is already
698/// present, return from the list. The stored expressions are unique: they are
699/// constructed and stored in a simplified/canonicalized form. The result after
700/// simplification could be any form of affine expression.
701AffineExpr *AffineBinaryOpExpr::get(AffineExpr::Kind kind, AffineExpr *lhs,
702 AffineExpr *rhs, MLIRContext *context) {
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700703 auto &impl = context->getImpl();
704
Uday Bondhugula0dd940c2018-07-26 00:19:21 -0700705 // Check if we already have this affine expression, and return it if we do.
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700706 auto keyValue = std::make_tuple((unsigned)kind, lhs, rhs);
Uday Bondhugula0dd940c2018-07-26 00:19:21 -0700707 auto cached = impl.affineExprs.find(keyValue);
708 if (cached != impl.affineExprs.end())
709 return cached->second;
Uday Bondhugula3934d4d2018-07-09 09:00:25 -0700710
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700711 // Simplify the expression if possible.
712 AffineExpr *simplified;
713 switch (kind) {
714 case Kind::Add:
715 simplified = AffineBinaryOpExpr::simplifyAdd(lhs, rhs, context);
716 break;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700717 case Kind::Mul:
718 simplified = AffineBinaryOpExpr::simplifyMul(lhs, rhs, context);
719 break;
720 case Kind::FloorDiv:
721 simplified = AffineBinaryOpExpr::simplifyFloorDiv(lhs, rhs, context);
722 break;
723 case Kind::CeilDiv:
724 simplified = AffineBinaryOpExpr::simplifyCeilDiv(lhs, rhs, context);
725 break;
726 case Kind::Mod:
727 simplified = AffineBinaryOpExpr::simplifyMod(lhs, rhs, context);
728 break;
729 default:
730 llvm_unreachable("unexpected binary affine expr");
Uday Bondhugula015cbb12018-07-03 20:16:08 -0700731 }
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700732
Uday Bondhugula0dd940c2018-07-26 00:19:21 -0700733 // The simplified one would have already been cached; just return it.
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700734 if (simplified)
Uday Bondhugula0dd940c2018-07-26 00:19:21 -0700735 return simplified;
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700736
Uday Bondhugula0dd940c2018-07-26 00:19:21 -0700737 // An expression with these operands will already be in the
738 // simplified/canonical form. Create and store it.
739 auto *result = impl.allocator.Allocate<AffineBinaryOpExpr>();
Uday Bondhugulae082aad2018-07-11 21:19:31 -0700740 // Initialize the memory using placement new.
Uday Bondhugula0dd940c2018-07-26 00:19:21 -0700741 new (result) AffineBinaryOpExpr(kind, lhs, rhs);
742 bool inserted = impl.affineExprs.insert({keyValue, result}).second;
743 assert(inserted && "the expression shouldn't already exist in the map");
744 (void)inserted;
745 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700746}
747
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700748AffineDimExpr *AffineDimExpr::get(unsigned position, MLIRContext *context) {
Uday Bondhugula4e5078b2018-07-24 22:34:09 -0700749 auto &impl = context->getImpl();
750
751 // Check if we need to resize.
752 if (position >= impl.dimExprs.size())
753 impl.dimExprs.resize(position + 1, nullptr);
754
755 auto *&result = impl.dimExprs[position];
756 if (result)
757 return result;
758
759 result = impl.allocator.Allocate<AffineDimExpr>();
760 // Initialize the memory using placement new.
761 new (result) AffineDimExpr(position);
762 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700763}
764
765AffineSymbolExpr *AffineSymbolExpr::get(unsigned position,
766 MLIRContext *context) {
Uday Bondhugula4e5078b2018-07-24 22:34:09 -0700767 auto &impl = context->getImpl();
768
769 // Check if we need to resize.
770 if (position >= impl.symbolExprs.size())
771 impl.symbolExprs.resize(position + 1, nullptr);
772
773 auto *&result = impl.symbolExprs[position];
774 if (result)
775 return result;
776
777 result = impl.allocator.Allocate<AffineSymbolExpr>();
778 // Initialize the memory using placement new.
779 new (result) AffineSymbolExpr(position);
780 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700781}
782
783AffineConstantExpr *AffineConstantExpr::get(int64_t constant,
784 MLIRContext *context) {
Uday Bondhugula4e5078b2018-07-24 22:34:09 -0700785 auto &impl = context->getImpl();
786 auto *&result = impl.constExprs[constant];
787
788 if (result)
789 return result;
790
791 result = impl.allocator.Allocate<AffineConstantExpr>();
792 // Initialize the memory using placement new.
793 new (result) AffineConstantExpr(constant);
794 return result;
Uday Bondhugulafaf37dd2018-06-29 18:09:29 -0700795}