MLIR 23.0.0git
AttributeDetail.h
Go to the documentation of this file.
1//===- AttributeDetail.h - MLIR Affine Map details Class --------*- 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 Attribute.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef ATTRIBUTEDETAIL_H_
14#define ATTRIBUTEDETAIL_H_
15
16#include "mlir/IR/AffineMap.h"
21#include "mlir/IR/IntegerSet.h"
22#include "mlir/IR/MLIRContext.h"
23#include "llvm/ADT/APFloat.h"
24#include "llvm/Support/Allocator.h"
25#include <mutex>
26
27namespace mlir {
28namespace detail {
29
30//===----------------------------------------------------------------------===//
31// Elements Attributes
32//===----------------------------------------------------------------------===//
33
34/// Return the bit width which DenseElementsAttr should use for this type.
35inline size_t getDenseElementBitWidth(Type eltType) {
36 if (auto denseEltType = llvm::dyn_cast<DenseElementType>(eltType))
37 return denseEltType.getDenseElementBitSize();
38 llvm_unreachable("unsupported element type");
39}
40
41/// An attribute representing a reference to a dense vector or tensor object.
43public:
45
46 ShapedType type;
47};
48
49/// An attribute representing a reference to a dense vector or tensor object.
53
54 struct KeyTy {
55 KeyTy(ShapedType type, ArrayRef<char> data, llvm::hash_code hashCode)
57
58 /// The type of the dense elements.
59 ShapedType type;
60
61 /// The raw buffer for the data storage.
63
64 /// The computed hash code for the storage data.
65 llvm::hash_code hashCode;
66 };
67
68 /// Compare this storage instance with the provided key.
69 bool operator==(const KeyTy &key) const {
70 return key.type == type && key.data == data;
71 }
72
73 /// Construct a key from a shaped type and raw data buffer.
74 static KeyTy getKey(ShapedType ty, ArrayRef<char> data) {
75 // Handle an empty storage instance.
76 if (data.empty())
77 return KeyTy(ty, data, 0);
78
79 size_t elementWidth = getDenseElementBitWidth(ty.getElementType());
80 // Dense elements are padded to 8-bits.
81 size_t storageSize = llvm::divideCeil(elementWidth, CHAR_BIT);
82
83 // If the data buffer holds a single element, it is a known splat.
84 if (data.size() == storageSize)
85 return KeyTy(ty, data, llvm::hash_value(data));
86
87 assert(((data.size() / storageSize) ==
88 static_cast<size_t>(ty.getNumElements())) &&
89 "data does not hold expected number of elements");
90
91 // Create the initial hash value with just the first element.
92 auto firstElt = data.take_front(storageSize);
93 auto hashVal = llvm::hash_value(firstElt);
94
95 // Check to see if this storage represents a splat. If it doesn't then
96 // combine the hash for the data starting with the first non splat element.
97 for (size_t i = storageSize, e = data.size(); i != e; i += storageSize)
98 if (memcmp(data.data(), &data[i], storageSize))
99 return KeyTy(ty, data, llvm::hash_combine(hashVal, data.drop_front(i)));
100
101 // Otherwise, this is a splat so just return the hash of the first element.
102 return KeyTy(ty, firstElt, hashVal);
103 }
104
105 /// Hash the key for the storage.
106 static llvm::hash_code hashKey(const KeyTy &key) {
107 return llvm::hash_combine(key.type, key.hashCode);
108 }
109
110 /// Construct a new storage instance.
113 // If the data buffer is non-empty, we copy it into the allocator with a
114 // 64-bit alignment.
116 if (!data.empty()) {
117 char *rawData = reinterpret_cast<char *>(
118 allocator.allocate(data.size(), alignof(uint64_t)));
119 std::memcpy(rawData, data.data(), data.size());
120 copy = ArrayRef<char>(rawData, data.size());
121 }
122
123 return new (allocator.allocate<DenseTypedElementsAttrStorage>())
125 }
126
128};
129
130/// An attribute representing a reference to a dense vector or tensor object
131/// containing strings.
135
136 struct KeyTy {
137 KeyTy(ShapedType type, ArrayRef<StringRef> data, llvm::hash_code hashCode)
139
140 /// The type of the dense elements.
141 ShapedType type;
142
143 /// The raw buffer for the data storage.
145
146 /// The computed hash code for the storage data.
147 llvm::hash_code hashCode;
148 };
149
150 /// Compare this storage instance with the provided key.
151 bool operator==(const KeyTy &key) const {
152 if (key.type != type)
153 return false;
154
155 // Otherwise, we can default to just checking the data. StringRefs compare
156 // by contents.
157 return key.data == data;
158 }
159
160 /// Construct a key from a shaped type and StringRef data buffer.
161 static KeyTy getKey(ShapedType ty, ArrayRef<StringRef> data) {
162 // Handle an empty storage instance.
163 if (data.empty())
164 return KeyTy(ty, data, 0);
165
166 // If the data buffer holds a single element, it is a known splat.
167 if (data.size() == 1)
168 return KeyTy(ty, data, llvm::hash_value(data.front()));
169
170 // Create the initial hash value with just the first element.
171 const auto &firstElt = data.front();
172 auto hashVal = llvm::hash_value(firstElt);
173
174 // Check to see if this storage represents a splat. If it doesn't then
175 // combine the hash for the data starting with the first non splat element.
176 for (size_t i = 1, e = data.size(); i != e; ++i)
177 if (firstElt != data[i])
178 return KeyTy(ty, data, llvm::hash_combine(hashVal, data.drop_front(i)));
179
180 // Otherwise, this is a splat so just return the hash of the first element.
181 return KeyTy(ty, data.take_front(), hashVal);
182 }
183
184 /// Hash the key for the storage.
185 static llvm::hash_code hashKey(const KeyTy &key) {
186 return llvm::hash_combine(key.type, key.hashCode);
187 }
188
189 /// Construct a new storage instance.
192 // If the data buffer is non-empty, we copy it into the allocator with a
193 // 64-bit alignment.
195 if (data.empty()) {
196 return new (allocator.allocate<DenseStringElementsAttrStorage>())
198 }
199
200 size_t numEntries = data.size();
201
202 // Compute the amount data needed to store the ArrayRef and StringRef
203 // contents.
204 size_t dataSize = sizeof(StringRef) * numEntries;
205 for (size_t i = 0; i < numEntries; ++i)
206 dataSize += data[i].size();
207
208 char *rawData = reinterpret_cast<char *>(
209 allocator.allocate(dataSize, alignof(uint64_t)));
210
211 // Setup a mutable array ref of our string refs so that we can update their
212 // contents.
213 auto mutableCopy = MutableArrayRef<StringRef>(
214 reinterpret_cast<StringRef *>(rawData), numEntries);
215 auto *stringData = rawData + numEntries * sizeof(StringRef);
216
217 for (size_t i = 0; i < numEntries; ++i) {
218 memcpy(stringData, data[i].data(), data[i].size());
219 mutableCopy[i] = StringRef(stringData, data[i].size());
220 stringData += data[i].size();
221 }
222
223 copy =
224 ArrayRef<StringRef>(reinterpret_cast<StringRef *>(rawData), numEntries);
225
226 return new (allocator.allocate<DenseStringElementsAttrStorage>())
228 }
229
231};
232
233//===----------------------------------------------------------------------===//
234// StringAttr
235//===----------------------------------------------------------------------===//
236
240
241 /// The hash key is a tuple of the parameter types.
242 using KeyTy = std::pair<StringRef, Type>;
243 bool operator==(const KeyTy &key) const {
244 return value == key.first && type == key.second;
245 }
246 static ::llvm::hash_code hashKey(const KeyTy &key) {
248 }
249
250 /// Define a construction method for creating a new instance of this
251 /// storage.
253 const KeyTy &key) {
254 return new (allocator.allocate<StringAttrStorage>())
255 StringAttrStorage(allocator.copyInto(key.first), key.second);
256 }
257
258 /// Initialize the storage given an MLIRContext.
259 void initialize(MLIRContext *context);
260
261 /// The type of the string.
263 /// The raw string value.
264 StringRef value;
265 /// If the string value contains a dialect namespace prefix (e.g.
266 /// dialect.blah), this is the dialect referenced.
268};
269
270//===----------------------------------------------------------------------===//
271// DistinctAttr
272//===----------------------------------------------------------------------===//
273
274/// An attribute to store a distinct reference to another attribute.
277
280
281 /// Returns the referenced attribute as key.
282 KeyTy getAsKey() const { return KeyTy(referencedAttr); }
283
284 /// The referenced attribute.
286};
287
288/// A specialized attribute uniquer for distinct attributes that always
289/// allocates since the distinct attribute instances use the address of their
290/// storage as unique identifier.
292public:
293 /// Creates a distinct attribute storage. Allocates every time since the
294 /// address of the storage serves as unique identifier.
295 template <typename T, typename... Args>
296 static T get(MLIRContext *context, Args &&...args) {
297 static_assert(std::is_same_v<typename T::ImplType, DistinctAttrStorage>,
298 "expects a distinct attribute storage");
299 DistinctAttrStorage *storage = DistinctAttributeUniquer::allocateStorage(
300 context, std::forward<Args>(args)...);
303 return storage;
304 }
305
306private:
307 /// Allocates a distinct attribute storage.
308 static DistinctAttrStorage *allocateStorage(MLIRContext *context,
309 Attribute referencedAttr);
310};
311
312/// An allocator for distinct attribute storage instances. Uses a synchronized
313/// BumpPtrAllocator to ensure thread-safety. The allocated storage is deleted
314/// when the DistinctAttributeAllocator is destroyed.
316public:
322
324 std::scoped_lock<std::mutex> guard(allocatorMutex);
325 return new (allocator.Allocate<DistinctAttrStorage>())
326 DistinctAttrStorage(referencedAttr);
327 };
328
329private:
330 /// Used to allocate distict attribute storages. The managed memory is freed
331 /// automatically when the allocator instance is destroyed.
332 llvm::BumpPtrAllocator allocator;
333
334 /// Used to lock access to the allocator.
335 std::mutex allocatorMutex;
336};
337} // namespace detail
338} // namespace mlir
339
340#endif // ATTRIBUTEDETAIL_H_
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static const AbstractAttribute & lookup(TypeID typeID, MLIRContext *context)
Look up the specified abstract attribute in the MLIRContext and return a reference to it.
Base storage class appearing in an attribute.
void initializeAbstractAttribute(const AbstractAttribute &abstractAttr)
Set the abstract attribute for this storage instance.
Attributes are known-constant values of operations.
Definition Attributes.h:25
TypeID getTypeID()
Return a unique identifier for the concrete attribute type.
Definition Attributes.h:52
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
ArrayRef< T > copyInto(ArrayRef< T > elements)
Copy the specified array of elements into memory managed by our bump pointer allocator.
T * allocate()
Allocate an instance of the provided type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
DistinctAttrStorage * allocate(Attribute referencedAttr)
DistinctAttributeAllocator(const DistinctAttributeAllocator &)=delete
DistinctAttributeAllocator & operator=(const DistinctAttributeAllocator &)=delete
DistinctAttributeAllocator(DistinctAttributeAllocator &&)=delete
A specialized attribute uniquer for distinct attributes that always allocates since the distinct attr...
static T get(MLIRContext *context, Args &&...args)
Creates a distinct attribute storage.
AttrTypeReplacer.
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
Include the generated interface declarations.
llvm::DenseMapInfo< T, Enable > DenseMapInfo
Definition LLVM.h:114
StorageUniquer::StorageAllocator AttributeStorageAllocator
ShapedType type
The type of the dense elements.
ArrayRef< StringRef > data
The raw buffer for the data storage.
KeyTy(ShapedType type, ArrayRef< StringRef > data, llvm::hash_code hashCode)
llvm::hash_code hashCode
The computed hash code for the storage data.
An attribute representing a reference to a dense vector or tensor object containing strings.
bool operator==(const KeyTy &key) const
Compare this storage instance with the provided key.
static KeyTy getKey(ShapedType ty, ArrayRef< StringRef > data)
Construct a key from a shaped type and StringRef data buffer.
DenseStringElementsAttrStorage(ShapedType ty, ArrayRef< StringRef > data)
static DenseStringElementsAttrStorage * construct(AttributeStorageAllocator &allocator, KeyTy key)
Construct a new storage instance.
static llvm::hash_code hashKey(const KeyTy &key)
Hash the key for the storage.
KeyTy(ShapedType type, ArrayRef< char > data, llvm::hash_code hashCode)
ArrayRef< char > data
The raw buffer for the data storage.
ShapedType type
The type of the dense elements.
llvm::hash_code hashCode
The computed hash code for the storage data.
An attribute representing a reference to a dense vector or tensor object.
DenseTypedElementsAttrStorage(ShapedType ty, ArrayRef< char > data)
bool operator==(const KeyTy &key) const
Compare this storage instance with the provided key.
static DenseTypedElementsAttrStorage * construct(AttributeStorageAllocator &allocator, KeyTy key)
Construct a new storage instance.
static llvm::hash_code hashKey(const KeyTy &key)
Hash the key for the storage.
static KeyTy getKey(ShapedType ty, ArrayRef< char > data)
Construct a key from a shaped type and raw data buffer.
An attribute to store a distinct reference to another attribute.
DistinctAttrStorage(Attribute referencedAttr)
Attribute referencedAttr
The referenced attribute.
KeyTy getAsKey() const
Returns the referenced attribute as key.
Type type
The type of the string.
StringRef value
The raw string value.
bool operator==(const KeyTy &key) const
::llvm::hash_code hashKey(const KeyTy &key)
StringAttrStorage(StringRef value, Type type)
static StringAttrStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
Define a construction method for creating a new instance of this storage.
Dialect * referencedDialect
If the string value contains a dialect namespace prefix (e.g.
std::pair< StringRef, Type > KeyTy
The hash key is a tuple of the parameter types.
void initialize(MLIRContext *context)
Initialize the storage given an MLIRContext.