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"
20#include "mlir/IR/IntegerSet.h"
21#include "mlir/IR/MLIRContext.h"
22#include "llvm/ADT/APFloat.h"
23#include "llvm/Support/Allocator.h"
24#include <mutex>
25
26namespace mlir {
27namespace detail {
28
29//===----------------------------------------------------------------------===//
30// Elements Attributes
31//===----------------------------------------------------------------------===//
32
33/// Return the bit width which DenseElementsAttr should use for this type.
34inline size_t getDenseElementBitWidth(Type eltType) {
35 // Align the width for complex to 8 to make storage and interpretation easier.
36 if (ComplexType comp = llvm::dyn_cast<ComplexType>(eltType))
37 return llvm::alignTo<8>(getDenseElementBitWidth(comp.getElementType())) * 2;
38 if (eltType.isIndex())
39 return IndexType::kInternalStorageBitWidth;
40 return eltType.getIntOrFloatBitWidth();
41}
42
43/// An attribute representing a reference to a dense vector or tensor object.
45public:
47
48 ShapedType type;
49};
50
51/// An attribute representing a reference to a dense vector or tensor object.
55
56 struct KeyTy {
57 KeyTy(ShapedType type, ArrayRef<char> data, llvm::hash_code hashCode)
59
60 /// The type of the dense elements.
61 ShapedType type;
62
63 /// The raw buffer for the data storage.
65
66 /// The computed hash code for the storage data.
67 llvm::hash_code hashCode;
68 };
69
70 /// Compare this storage instance with the provided key.
71 bool operator==(const KeyTy &key) const {
72 return key.type == type && key.data == data;
73 }
74
75 /// Construct a key from a shaped type and raw data buffer.
76 static KeyTy getKey(ShapedType ty, ArrayRef<char> data) {
77 // Handle an empty storage instance.
78 if (data.empty())
79 return KeyTy(ty, data, 0);
80
81 size_t elementWidth = getDenseElementBitWidth(ty.getElementType());
82 // Dense elements are padded to 8-bits.
83 size_t storageSize = llvm::divideCeil(elementWidth, CHAR_BIT);
84
85 // If the data buffer holds a single element, it is a known splat.
86 if (data.size() == storageSize)
87 return KeyTy(ty, data, llvm::hash_value(data));
88
89 assert(((data.size() / storageSize) ==
90 static_cast<size_t>(ty.getNumElements())) &&
91 "data does not hold expected number of elements");
92
93 // Create the initial hash value with just the first element.
94 auto firstElt = data.take_front(storageSize);
95 auto hashVal = llvm::hash_value(firstElt);
96
97 // Check to see if this storage represents a splat. If it doesn't then
98 // combine the hash for the data starting with the first non splat element.
99 for (size_t i = storageSize, e = data.size(); i != e; i += storageSize)
100 if (memcmp(data.data(), &data[i], storageSize))
101 return KeyTy(ty, data, llvm::hash_combine(hashVal, data.drop_front(i)));
102
103 // Otherwise, this is a splat so just return the hash of the first element.
104 return KeyTy(ty, firstElt, hashVal);
105 }
106
107 /// Hash the key for the storage.
108 static llvm::hash_code hashKey(const KeyTy &key) {
109 return llvm::hash_combine(key.type, key.hashCode);
110 }
111
112 /// Construct a new storage instance.
115 // If the data buffer is non-empty, we copy it into the allocator with a
116 // 64-bit alignment.
118 if (!data.empty()) {
119 char *rawData = reinterpret_cast<char *>(
120 allocator.allocate(data.size(), alignof(uint64_t)));
121 std::memcpy(rawData, data.data(), data.size());
122 copy = ArrayRef<char>(rawData, data.size());
123 }
124
125 return new (allocator.allocate<DenseIntOrFPElementsAttrStorage>())
127 }
128
130};
131
132/// An attribute representing a reference to a dense vector or tensor object
133/// containing strings.
137
138 struct KeyTy {
139 KeyTy(ShapedType type, ArrayRef<StringRef> data, llvm::hash_code hashCode)
141
142 /// The type of the dense elements.
143 ShapedType type;
144
145 /// The raw buffer for the data storage.
147
148 /// The computed hash code for the storage data.
149 llvm::hash_code hashCode;
150 };
151
152 /// Compare this storage instance with the provided key.
153 bool operator==(const KeyTy &key) const {
154 if (key.type != type)
155 return false;
156
157 // Otherwise, we can default to just checking the data. StringRefs compare
158 // by contents.
159 return key.data == data;
160 }
161
162 /// Construct a key from a shaped type and StringRef data buffer.
163 static KeyTy getKey(ShapedType ty, ArrayRef<StringRef> data) {
164 // Handle an empty storage instance.
165 if (data.empty())
166 return KeyTy(ty, data, 0);
167
168 // If the data buffer holds a single element, it is a known splat.
169 if (data.size() == 1)
170 return KeyTy(ty, data, llvm::hash_value(data.front()));
171
172 // Create the initial hash value with just the first element.
173 const auto &firstElt = data.front();
174 auto hashVal = llvm::hash_value(firstElt);
175
176 // Check to see if this storage represents a splat. If it doesn't then
177 // combine the hash for the data starting with the first non splat element.
178 for (size_t i = 1, e = data.size(); i != e; ++i)
179 if (firstElt != data[i])
180 return KeyTy(ty, data, llvm::hash_combine(hashVal, data.drop_front(i)));
181
182 // Otherwise, this is a splat so just return the hash of the first element.
183 return KeyTy(ty, data.take_front(), hashVal);
184 }
185
186 /// Hash the key for the storage.
187 static llvm::hash_code hashKey(const KeyTy &key) {
188 return llvm::hash_combine(key.type, key.hashCode);
189 }
190
191 /// Construct a new storage instance.
194 // If the data buffer is non-empty, we copy it into the allocator with a
195 // 64-bit alignment.
197 if (data.empty()) {
198 return new (allocator.allocate<DenseStringElementsAttrStorage>())
200 }
201
202 size_t numEntries = data.size();
203
204 // Compute the amount data needed to store the ArrayRef and StringRef
205 // contents.
206 size_t dataSize = sizeof(StringRef) * numEntries;
207 for (size_t i = 0; i < numEntries; ++i)
208 dataSize += data[i].size();
209
210 char *rawData = reinterpret_cast<char *>(
211 allocator.allocate(dataSize, alignof(uint64_t)));
212
213 // Setup a mutable array ref of our string refs so that we can update their
214 // contents.
215 auto mutableCopy = MutableArrayRef<StringRef>(
216 reinterpret_cast<StringRef *>(rawData), numEntries);
217 auto *stringData = rawData + numEntries * sizeof(StringRef);
218
219 for (size_t i = 0; i < numEntries; ++i) {
220 memcpy(stringData, data[i].data(), data[i].size());
221 mutableCopy[i] = StringRef(stringData, data[i].size());
222 stringData += data[i].size();
223 }
224
225 copy =
226 ArrayRef<StringRef>(reinterpret_cast<StringRef *>(rawData), numEntries);
227
228 return new (allocator.allocate<DenseStringElementsAttrStorage>())
230 }
231
233};
234
235//===----------------------------------------------------------------------===//
236// StringAttr
237//===----------------------------------------------------------------------===//
238
242
243 /// The hash key is a tuple of the parameter types.
244 using KeyTy = std::pair<StringRef, Type>;
245 bool operator==(const KeyTy &key) const {
246 return value == key.first && type == key.second;
247 }
248 static ::llvm::hash_code hashKey(const KeyTy &key) {
250 }
251
252 /// Define a construction method for creating a new instance of this
253 /// storage.
255 const KeyTy &key) {
256 return new (allocator.allocate<StringAttrStorage>())
257 StringAttrStorage(allocator.copyInto(key.first), key.second);
258 }
259
260 /// Initialize the storage given an MLIRContext.
261 void initialize(MLIRContext *context);
262
263 /// The type of the string.
265 /// The raw string value.
266 StringRef value;
267 /// If the string value contains a dialect namespace prefix (e.g.
268 /// dialect.blah), this is the dialect referenced.
270};
271
272//===----------------------------------------------------------------------===//
273// DistinctAttr
274//===----------------------------------------------------------------------===//
275
276/// An attribute to store a distinct reference to another attribute.
279
282
283 /// Returns the referenced attribute as key.
284 KeyTy getAsKey() const { return KeyTy(referencedAttr); }
285
286 /// The referenced attribute.
288};
289
290/// A specialized attribute uniquer for distinct attributes that always
291/// allocates since the distinct attribute instances use the address of their
292/// storage as unique identifier.
294public:
295 /// Creates a distinct attribute storage. Allocates every time since the
296 /// address of the storage serves as unique identifier.
297 template <typename T, typename... Args>
298 static T get(MLIRContext *context, Args &&...args) {
299 static_assert(std::is_same_v<typename T::ImplType, DistinctAttrStorage>,
300 "expects a distinct attribute storage");
301 DistinctAttrStorage *storage = DistinctAttributeUniquer::allocateStorage(
302 context, std::forward<Args>(args)...);
305 return storage;
306 }
307
308private:
309 /// Allocates a distinct attribute storage.
310 static DistinctAttrStorage *allocateStorage(MLIRContext *context,
311 Attribute referencedAttr);
312};
313
314/// An allocator for distinct attribute storage instances. Uses a synchronized
315/// BumpPtrAllocator to ensure thread-safety. The allocated storage is deleted
316/// when the DistinctAttributeAllocator is destroyed.
318public:
324
326 std::scoped_lock<std::mutex> guard(allocatorMutex);
327 return new (allocator.Allocate<DistinctAttrStorage>())
328 DistinctAttrStorage(referencedAttr);
329 };
330
331private:
332 /// Used to allocate distict attribute storages. The managed memory is freed
333 /// automatically when the allocator instance is destroyed.
334 llvm::BumpPtrAllocator allocator;
335
336 /// Used to lock access to the allocator.
337 std::mutex allocatorMutex;
338};
339} // namespace detail
340} // namespace mlir
341
342#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
bool isIndex() const
Definition Types.cpp:56
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition Types.cpp:124
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
llvm::hash_code hashCode
The computed hash code for the storage data.
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.
An attribute representing a reference to a dense vector or tensor object.
bool operator==(const KeyTy &key) const
Compare this storage instance with the provided key.
static llvm::hash_code hashKey(const KeyTy &key)
Hash the key for the storage.
static DenseIntOrFPElementsAttrStorage * construct(AttributeStorageAllocator &allocator, KeyTy key)
Construct a new storage instance.
static KeyTy getKey(ShapedType ty, ArrayRef< char > data)
Construct a key from a shaped type and raw data buffer.
DenseIntOrFPElementsAttrStorage(ShapedType ty, ArrayRef< char > data)
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.
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.