MLIR 23.0.0git
BuiltinAttributes.cpp
Go to the documentation of this file.
1//===- BuiltinAttributes.cpp - MLIR Builtin Attribute Classes -------------===//
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
10#include "AttributeDetail.h"
11#include "mlir/IR/AffineMap.h"
13#include "mlir/IR/Dialect.h"
15#include "mlir/IR/IntegerSet.h"
17#include "mlir/IR/Operation.h"
18#include "mlir/IR/SymbolTable.h"
19#include "mlir/IR/Types.h"
20#include "llvm/ADT/APSInt.h"
21#include "llvm/Support/Debug.h"
22#include "llvm/Support/DebugLog.h"
23#include "llvm/Support/Endian.h"
24#include <optional>
25
26#define DEBUG_TYPE "builtinattributes"
27
28using namespace mlir;
29using namespace mlir::detail;
30
31//===----------------------------------------------------------------------===//
32/// Tablegen Attribute Definitions
33//===----------------------------------------------------------------------===//
34
35#define GET_ATTRDEF_CLASSES
36#include "mlir/IR/BuiltinAttributes.cpp.inc"
37
38//===----------------------------------------------------------------------===//
39// BuiltinDialect
40//===----------------------------------------------------------------------===//
41
42void BuiltinDialect::registerAttributes() {
43 addAttributes<
44#define GET_ATTRDEF_LIST
45#include "mlir/IR/BuiltinAttributes.cpp.inc"
46 >();
47 addAttributes<DistinctAttr>();
48}
49
50//===----------------------------------------------------------------------===//
51// DictionaryAttr
52//===----------------------------------------------------------------------===//
53
54/// Helper function that does either an in place sort or sorts from source array
55/// into destination. If inPlace then storage is both the source and the
56/// destination, else value is the source and storage destination. Returns
57/// whether source was sorted.
58template <bool inPlace>
61 // Specialize for the common case.
62 switch (value.size()) {
63 case 0:
64 // Zero already sorted.
65 if (!inPlace)
66 storage.clear();
67 break;
68 case 1:
69 // One already sorted but may need to be copied.
70 if (!inPlace)
71 storage.assign({value[0]});
72 break;
73 case 2: {
74 bool isSorted = value[0] < value[1];
75 if (inPlace) {
76 if (!isSorted)
77 std::swap(storage[0], storage[1]);
78 } else if (isSorted) {
79 storage.assign({value[0], value[1]});
80 } else {
81 storage.assign({value[1], value[0]});
82 }
83 return !isSorted;
84 }
85 default:
86 if (!inPlace)
87 storage.assign(value.begin(), value.end());
88 // Check to see they are sorted already.
89 bool isSorted = llvm::is_sorted(value);
90 // If not, do a general sort.
91 if (!isSorted)
92 llvm::array_pod_sort(storage.begin(), storage.end());
93 return !isSorted;
94 }
95 return false;
96}
97
98/// Returns an entry with a duplicate name from the given sorted array of named
99/// attributes. Returns std::nullopt if all elements have unique names.
100static std::optional<NamedAttribute>
102 const std::optional<NamedAttribute> none{std::nullopt};
103 if (value.size() < 2)
104 return none;
105
106 if (value.size() == 2)
107 return value[0].getName() == value[1].getName() ? value[0] : none;
108
109 const auto *it = std::adjacent_find(value.begin(), value.end(),
111 return l.getName() == r.getName();
112 });
113 return it != value.end() ? *it : none;
114}
115
116bool DictionaryAttr::sort(ArrayRef<NamedAttribute> value,
118 bool isSorted = dictionaryAttrSort</*inPlace=*/false>(value, storage);
119 assert(!findDuplicateElement(storage) &&
120 "DictionaryAttr element names must be unique");
121 return isSorted;
122}
123
124bool DictionaryAttr::sortInPlace(SmallVectorImpl<NamedAttribute> &array) {
125 bool isSorted = dictionaryAttrSort</*inPlace=*/true>(array, array);
126 assert(!findDuplicateElement(array) &&
127 "DictionaryAttr element names must be unique");
128 return isSorted;
129}
130
131std::optional<NamedAttribute>
132DictionaryAttr::findDuplicate(SmallVectorImpl<NamedAttribute> &array,
133 bool isSorted) {
134 if (!isSorted)
135 dictionaryAttrSort</*inPlace=*/true>(array, array);
136 return findDuplicateElement(array);
137}
138
139DictionaryAttr DictionaryAttr::get(MLIRContext *context,
141 if (value.empty())
142 return DictionaryAttr::getEmpty(context);
143
144 // We need to sort the element list to canonicalize it.
145 SmallVector<NamedAttribute, 8> storage;
146 if (dictionaryAttrSort</*inPlace=*/false>(value, storage))
147 value = storage;
148 assert(!findDuplicateElement(value) &&
149 "DictionaryAttr element names must be unique");
150 return Base::get(context, value);
151}
152/// Construct a dictionary with an array of values that is known to already be
153/// sorted by name and uniqued.
154DictionaryAttr DictionaryAttr::getWithSorted(MLIRContext *context,
156 if (value.empty())
157 return DictionaryAttr::getEmpty(context);
158 // Ensure that the attribute elements are unique and sorted.
159 assert(llvm::is_sorted(
160 value, [](NamedAttribute l, NamedAttribute r) { return l < r; }) &&
161 "expected attribute values to be sorted");
162 assert(!findDuplicateElement(value) &&
163 "DictionaryAttr element names must be unique");
164 return Base::get(context, value);
165}
166
167/// Return the specified attribute if present, null otherwise.
168Attribute DictionaryAttr::get(StringRef name) const {
169 auto it = impl::findAttrSorted(begin(), end(), name);
170 return it.second ? it.first->getValue() : Attribute();
171}
172Attribute DictionaryAttr::get(StringAttr name) const {
173 auto it = impl::findAttrSorted(begin(), end(), name);
174 return it.second ? it.first->getValue() : Attribute();
175}
176
177/// Return the specified named attribute if present, std::nullopt otherwise.
178std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name) const {
179 auto it = impl::findAttrSorted(begin(), end(), name);
180 return it.second ? *it.first : std::optional<NamedAttribute>();
181}
182std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name) const {
183 auto it = impl::findAttrSorted(begin(), end(), name);
184 return it.second ? *it.first : std::optional<NamedAttribute>();
185}
186
187/// Return whether the specified attribute is present.
188bool DictionaryAttr::contains(StringRef name) const {
189 return impl::findAttrSorted(begin(), end(), name).second;
190}
191bool DictionaryAttr::contains(StringAttr name) const {
192 return impl::findAttrSorted(begin(), end(), name).second;
193}
194
195DictionaryAttr::iterator DictionaryAttr::begin() const {
196 return getValue().begin();
197}
198DictionaryAttr::iterator DictionaryAttr::end() const {
199 return getValue().end();
200}
201size_t DictionaryAttr::size() const { return getValue().size(); }
202
203DictionaryAttr DictionaryAttr::getEmptyUnchecked(MLIRContext *context) {
204 return Base::get(context, ArrayRef<NamedAttribute>());
205}
206
207//===----------------------------------------------------------------------===//
208// StridedLayoutAttr
209//===----------------------------------------------------------------------===//
210
211/// Prints a strided layout attribute.
212void StridedLayoutAttr::print(llvm::raw_ostream &os) const {
213 auto printIntOrQuestion = [&](int64_t value) {
214 if (ShapedType::isDynamic(value))
215 os << "?";
216 else
217 os << value;
218 };
219
220 os << "strided<[";
221 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
222 os << "]";
223
224 if (getOffset() != 0) {
225 os << ", offset: ";
226 printIntOrQuestion(getOffset());
227 }
228 os << ">";
229}
230
231/// Returns true if this layout is static, i.e. the strides and offset all have
232/// a known value > 0.
233bool StridedLayoutAttr::hasStaticLayout() const {
234 return ShapedType::isStatic(getOffset()) &&
235 ShapedType::isStaticShape(getStrides());
236}
237
238/// Returns the strided layout as an affine map.
239AffineMap StridedLayoutAttr::getAffineMap() const {
240 return makeStridedLinearLayoutMap(getStrides(), getOffset(), getContext());
241}
242
243/// Checks that the type-agnostic strided layout invariants are satisfied.
244LogicalResult
245StridedLayoutAttr::verify(function_ref<InFlightDiagnostic()> emitError,
246 int64_t offset, ArrayRef<int64_t> strides) {
247 return success();
248}
249
250/// Checks that the type-specific strided layout invariants are satisfied.
251LogicalResult StridedLayoutAttr::verifyLayout(
254 if (shape.size() != getStrides().size())
255 return emitError() << "expected the number of strides to match the rank";
256
257 return success();
258}
259
260LogicalResult
261StridedLayoutAttr::getStridesAndOffset(ArrayRef<int64_t>,
263 int64_t &offset) const {
264 llvm::append_range(strides, getStrides());
265 offset = getOffset();
266 return success();
267}
268
269//===----------------------------------------------------------------------===//
270// StringAttr
271//===----------------------------------------------------------------------===//
272
273StringAttr StringAttr::getEmptyStringAttrUnchecked(MLIRContext *context) {
274 return Base::get(context, "", NoneType::get(context));
275}
276
277/// Twine support for StringAttr.
278StringAttr StringAttr::get(MLIRContext *context, const Twine &twine) {
279 // Fast-path empty twine.
280 if (twine.isTriviallyEmpty())
281 return get(context);
282 SmallVector<char, 32> tempStr;
283 return Base::get(context, twine.toStringRef(tempStr), NoneType::get(context));
284}
285
286/// Twine support for StringAttr.
287StringAttr StringAttr::get(const Twine &twine, Type type) {
288 SmallVector<char, 32> tempStr;
289 return Base::get(type.getContext(), twine.toStringRef(tempStr), type);
290}
291
292StringRef StringAttr::getValue() const { return getImpl()->value; }
293
294Type StringAttr::getType() const { return getImpl()->type; }
295
296Dialect *StringAttr::getReferencedDialect() const {
297 return getImpl()->referencedDialect;
298}
299
300//===----------------------------------------------------------------------===//
301// FloatAttr
302//===----------------------------------------------------------------------===//
303
304double FloatAttr::getValueAsDouble() const {
305 return getValueAsDouble(getValue());
306}
307double FloatAttr::getValueAsDouble(APFloat value) {
308 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
309 bool losesInfo = false;
310 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
311 &losesInfo);
312 }
313 return value.convertToDouble();
314}
315
316LogicalResult FloatAttr::verify(function_ref<InFlightDiagnostic()> emitError,
317 Type type, APFloat value) {
318 // Verify that the type is correct.
319 if (!llvm::isa<FloatType>(type))
320 return emitError() << "expected floating point type";
321
322 // Verify that the type semantics match that of the value.
323 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
324 &value.getSemantics()) {
325 return emitError()
326 << "FloatAttr type doesn't match the type implied by its value";
327 }
328 return success();
329}
330
331//===----------------------------------------------------------------------===//
332// SymbolRefAttr
333//===----------------------------------------------------------------------===//
334
335SymbolRefAttr SymbolRefAttr::get(MLIRContext *ctx, StringRef value,
336 ArrayRef<FlatSymbolRefAttr> nestedRefs) {
337 return get(StringAttr::get(ctx, value), nestedRefs);
338}
339
340FlatSymbolRefAttr SymbolRefAttr::get(MLIRContext *ctx, StringRef value) {
341 return llvm::cast<FlatSymbolRefAttr>(get(ctx, value, {}));
342}
343
344FlatSymbolRefAttr SymbolRefAttr::get(StringAttr value) {
345 return llvm::cast<FlatSymbolRefAttr>(get(value, {}));
346}
347
348FlatSymbolRefAttr SymbolRefAttr::get(Operation *symbol) {
349 auto symName =
350 symbol->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
351 assert(symName && "value does not have a valid symbol name");
352 return SymbolRefAttr::get(symName);
353}
354
355StringAttr SymbolRefAttr::getLeafReference() const {
356 ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences();
357 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
358}
359
360//===----------------------------------------------------------------------===//
361// IntegerAttr
362//===----------------------------------------------------------------------===//
363
364int64_t IntegerAttr::getInt() const {
365 assert((getType().isIndex() || getType().isSignlessInteger()) &&
366 "must be signless integer");
367 return getValue().getSExtValue();
368}
369
370int64_t IntegerAttr::getSInt() const {
371 assert(getType().isSignedInteger() && "must be signed integer");
372 return getValue().getSExtValue();
373}
374
375uint64_t IntegerAttr::getUInt() const {
376 assert(getType().isUnsignedInteger() && "must be unsigned integer");
377 return getValue().getZExtValue();
378}
379
380/// Return the value as an APSInt which carries the signed from the type of
381/// the attribute. This traps on signless integers types!
382APSInt IntegerAttr::getAPSInt() const {
383 assert(!getType().isSignlessInteger() &&
384 "Signless integers don't carry a sign for APSInt");
385 return APSInt(getValue(), getType().isUnsignedInteger());
386}
387
388LogicalResult IntegerAttr::verify(function_ref<InFlightDiagnostic()> emitError,
389 Type type, APInt value) {
390 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
391 if (integerType.getWidth() != value.getBitWidth())
392 return emitError() << "integer type bit width (" << integerType.getWidth()
393 << ") doesn't match value bit width ("
394 << value.getBitWidth() << ")";
395 return success();
396 }
397 if (llvm::isa<IndexType>(type)) {
398 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
399 return emitError()
400 << "value bit width (" << value.getBitWidth()
401 << ") doesn't match index type internal storage bit width ("
402 << IndexType::kInternalStorageBitWidth << ")";
403 return success();
404 }
405 return emitError() << "expected integer or index type";
406}
407
408BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type, bool value) {
409 auto attr = Base::get(type.getContext(), type, APInt(/*numBits=*/1, value));
410 return llvm::cast<BoolAttr>(attr);
411}
412
413//===----------------------------------------------------------------------===//
414// BoolAttr
415//===----------------------------------------------------------------------===//
416
417bool BoolAttr::getValue() const {
418 auto *storage = reinterpret_cast<IntegerAttrStorage *>(impl);
419 return storage->value.getBoolValue();
420}
421
423 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
424 return intAttr && intAttr.getType().isSignlessInteger(1);
425}
426
427//===----------------------------------------------------------------------===//
428// OpaqueAttr
429//===----------------------------------------------------------------------===//
430
431LogicalResult OpaqueAttr::verify(function_ref<InFlightDiagnostic()> emitError,
432 StringAttr dialect, StringRef attrData,
433 Type type) {
434 if (!Dialect::isValidNamespace(dialect.strref()))
435 return emitError() << "invalid dialect namespace '" << dialect << "'";
436
437 // Check that the dialect is actually registered.
438 MLIRContext *context = dialect.getContext();
439 if (!context->allowsUnregisteredDialects() &&
440 !context->getLoadedDialect(dialect.strref())) {
441 return emitError()
442 << "#" << dialect << "<\"" << attrData << "\"> : " << type
443 << " attribute created with unregistered dialect. If this is "
444 "intended, please call allowUnregisteredDialects() on the "
445 "MLIRContext, or use -allow-unregistered-dialect with "
446 "the MLIR opt tool used";
447 }
448
449 return success();
450}
451
452//===----------------------------------------------------------------------===//
453// DenseElementsAttr Utilities
454//===----------------------------------------------------------------------===//
455
456/// Get the bitwidth of a dense element type within the buffer.
457/// DenseElementsAttr requires bitwidths to be aligned by 8.
458static size_t getDenseElementStorageWidth(size_t origWidth) {
459 return llvm::alignTo<8>(origWidth);
460}
461static size_t getDenseElementStorageWidth(Type elementType) {
463}
464
465/// Copy actual `numBytes` data from `value` (APInt) to char array(`result`) for
466/// BE format.
467static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes,
468 char *result) {
469 assert(llvm::endianness::native == llvm::endianness::big);
470 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
471
472 // Copy the words filled with data.
473 // For example, when `value` has 2 words, the first word is filled with data.
474 // `value` (10 bytes, BE):|abcdefgh|------ij| ==> `result` (BE):|abcdefgh|--|
475 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
476 std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
477 numFilledWords, result);
478 // Convert last word of APInt to LE format and store it in char
479 // array(`valueLE`).
480 // ex. last word of `value` (BE): |------ij| ==> `valueLE` (LE): |ji------|
481 size_t lastWordPos = numFilledWords;
482 SmallVector<char, 8> valueLE(APInt::APINT_WORD_SIZE);
483 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
484 reinterpret_cast<const char *>(value.getRawData()) + lastWordPos,
485 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
486 // Extract actual APInt data from `valueLE`, convert endianness to BE format,
487 // and store it in `result`.
488 // ex. `valueLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|ij|
489 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
490 valueLE.begin(), result + lastWordPos,
491 (numBytes - lastWordPos) * CHAR_BIT, 1);
492}
493
494/// Copy `numBytes` data from `inArray`(char array) to `result`(APINT) for BE
495/// format.
496static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes,
497 APInt &result) {
498 assert(llvm::endianness::native == llvm::endianness::big);
499 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
500
501 // Copy the data that fills the word of `result` from `inArray`.
502 // For example, when `result` has 2 words, the first word will be filled with
503 // data. So, the first 8 bytes are copied from `inArray` here.
504 // `inArray` (10 bytes, BE): |abcdefgh|ij|
505 // ==> `result` (2 words, BE): |abcdefgh|--------|
506 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
507 std::copy_n(
508 inArray, numFilledWords,
509 const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())));
510
511 // Convert array data which will be last word of `result` to LE format, and
512 // store it in char array(`inArrayLE`).
513 // ex. `inArray` (last two bytes, BE): |ij| ==> `inArrayLE` (LE): |ji------|
514 size_t lastWordPos = numFilledWords;
515 SmallVector<char, 8> inArrayLE(APInt::APINT_WORD_SIZE);
516 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
517 inArray + lastWordPos, inArrayLE.begin(),
518 (numBytes - lastWordPos) * CHAR_BIT, 1);
519
520 // Convert `inArrayLE` to BE format, and store it in last word of `result`.
521 // ex. `inArrayLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|------ij|
522 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
523 inArrayLE.begin(),
524 const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())) +
525 lastWordPos,
526 APInt::APINT_BITS_PER_WORD, 1);
527}
528
529/// Writes value to the bit position `bitPos` in array `rawData`.
530static void writeBits(char *rawData, size_t bitPos, APInt value) {
531 size_t bitWidth = value.getBitWidth();
532
533 // The bit position is guaranteed to be byte aligned.
534 assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
535 if (llvm::endianness::native == llvm::endianness::big) {
536 // Copy from `value` to `rawData + (bitPos / CHAR_BIT)`.
537 // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
538 // work correctly in BE format.
539 // ex. `value` (2 words including 10 bytes)
540 // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------|
541 copyAPIntToArrayForBEmachine(value, llvm::divideCeil(bitWidth, CHAR_BIT),
542 rawData + (bitPos / CHAR_BIT));
543 } else {
544 std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
545 llvm::divideCeil(bitWidth, CHAR_BIT),
546 rawData + (bitPos / CHAR_BIT));
547 }
548}
549
550/// Reads the next `bitWidth` bits from the bit position `bitPos` in array
551/// `rawData`.
552static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth) {
553 // The bit position is guaranteed to be byte aligned.
554 assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
555 APInt result(bitWidth, 0);
556 if (llvm::endianness::native == llvm::endianness::big) {
557 // Copy from `rawData + (bitPos / CHAR_BIT)` to `result`.
558 // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
559 // work correctly in BE format.
560 // ex. `result` (2 words including 10 bytes)
561 // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------| This function
562 copyArrayToAPIntForBEmachine(rawData + (bitPos / CHAR_BIT),
563 llvm::divideCeil(bitWidth, CHAR_BIT), result);
564 } else {
565 std::copy_n(rawData + (bitPos / CHAR_BIT),
566 llvm::divideCeil(bitWidth, CHAR_BIT),
567 const_cast<char *>(
568 reinterpret_cast<const char *>(result.getRawData())));
569 }
570 return result;
571}
572
573/// Returns true if 'values' corresponds to a splat, i.e. one element, or has
574/// the same element count as 'type'.
575template <typename Values>
576static bool hasSameNumElementsOrSplat(ShapedType type, const Values &values) {
577 return (values.size() == 1) ||
578 (type.getNumElements() == static_cast<int64_t>(values.size()));
579}
580
581//===----------------------------------------------------------------------===//
582// DenseElementsAttr Iterators
583//===----------------------------------------------------------------------===//
584
585//===----------------------------------------------------------------------===//
586// AttributeElementIterator
587//===----------------------------------------------------------------------===//
588
589DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
590 DenseElementsAttr attr, size_t index)
591 : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
593 attr.getAsOpaquePointer(), index) {}
594
596 auto owner = llvm::cast<DenseElementsAttr>(getFromOpaquePointer(base));
597 Type eltTy = owner.getElementType();
598 if (llvm::dyn_cast<IntegerType>(eltTy))
599 return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
600 if (llvm::isa<IndexType>(eltTy))
601 return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
602 if (auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
603 IntElementIterator intIt(owner, index);
604 FloatElementIterator floatIt(floatEltTy.getFloatSemantics(), intIt);
605 return FloatAttr::get(eltTy, *floatIt);
606 }
607 if (auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
608 auto complexEltTy = complexTy.getElementType();
609 ComplexIntElementIterator complexIntIt(owner, index);
610 if (llvm::isa<IntegerType>(complexEltTy)) {
611 auto value = *complexIntIt;
612 auto real = IntegerAttr::get(complexEltTy, value.real());
613 auto imag = IntegerAttr::get(complexEltTy, value.imag());
614 return ArrayAttr::get(complexTy.getContext(),
615 ArrayRef<Attribute>{real, imag});
616 }
617
618 ComplexFloatElementIterator complexFloatIt(
619 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
620 auto value = *complexFloatIt;
621 auto real = FloatAttr::get(complexEltTy, value.real());
622 auto imag = FloatAttr::get(complexEltTy, value.imag());
623 return ArrayAttr::get(complexTy.getContext(),
624 ArrayRef<Attribute>{real, imag});
625 }
626 if (llvm::isa<DenseStringElementsAttr>(owner)) {
627 ArrayRef<StringRef> vals = owner.getRawStringData();
628 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
629 }
630 llvm_unreachable("unexpected element type");
631}
632
633//===----------------------------------------------------------------------===//
634// BoolElementIterator
635//===----------------------------------------------------------------------===//
636
637DenseElementsAttr::BoolElementIterator::BoolElementIterator(
638 DenseElementsAttr attr, size_t dataIndex)
640 attr.getRawData().data(), attr.isSplat(), dataIndex) {}
641
643 return static_cast<bool>(getData()[getDataIndex()]);
644}
645
646//===----------------------------------------------------------------------===//
647// IntElementIterator
648//===----------------------------------------------------------------------===//
649
650DenseElementsAttr::IntElementIterator::IntElementIterator(
651 DenseElementsAttr attr, size_t dataIndex)
653 attr.getRawData().data(), attr.isSplat(), dataIndex),
654 bitWidth(getDenseElementBitWidth(attr.getElementType())) {}
655
657 return readBits(getData(),
659 bitWidth);
660}
661
662//===----------------------------------------------------------------------===//
663// ComplexIntElementIterator
664//===----------------------------------------------------------------------===//
665
666DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
667 DenseElementsAttr attr, size_t dataIndex)
669 std::complex<APInt>, std::complex<APInt>,
670 std::complex<APInt>>(
671 attr.getRawData().data(), attr.isSplat(), dataIndex) {
672 auto complexType = llvm::cast<ComplexType>(attr.getElementType());
673 bitWidth = getDenseElementBitWidth(complexType.getElementType());
674}
675
676std::complex<APInt>
678 size_t storageWidth = getDenseElementStorageWidth(bitWidth);
679 size_t offset = getDataIndex() * storageWidth * 2;
680 return {readBits(getData(), offset, bitWidth),
681 readBits(getData(), offset + storageWidth, bitWidth)};
682}
683
684//===----------------------------------------------------------------------===//
685// DenseArrayAttr
686//===----------------------------------------------------------------------===//
687
688LogicalResult
689DenseArrayAttr::verify(function_ref<InFlightDiagnostic()> emitError,
690 Type elementType, int64_t size, ArrayRef<char> rawData) {
691 if (!elementType.isIntOrIndexOrFloat())
692 return emitError() << "expected integer or floating point element type";
693 int64_t dataSize = rawData.size();
694 int64_t elementSize =
695 llvm::divideCeil(elementType.getIntOrFloatBitWidth(), CHAR_BIT);
696 if (size * elementSize != dataSize) {
697 return emitError() << "expected data size (" << size << " elements, "
698 << elementSize
699 << " bytes each) does not match: " << dataSize
700 << " bytes";
701 }
702 return success();
703}
704
705namespace {
706/// Instantiations of this class provide utilities for interacting with native
707/// data types in the context of DenseArrayAttr.
708template <size_t width,
709 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
710struct DenseArrayAttrIntUtil {
711 static bool checkElementType(Type eltType) {
712 auto type = llvm::dyn_cast<IntegerType>(eltType);
713 if (!type || type.getWidth() != width)
714 return false;
715 return type.getSignedness() == signedness;
716 }
717
719 return IntegerType::get(ctx, width, signedness);
720 }
721
722 template <typename T>
723 static void printElement(raw_ostream &os, T value) {
724 os << value;
725 }
726
727 template <typename T>
728 static ParseResult parseElement(AsmParser &parser, T &value) {
729 return parser.parseInteger(value);
730 }
731};
732template <typename T>
733struct DenseArrayAttrUtil;
734
735/// Specialization for boolean elements to print 'true' and 'false' literals for
736/// elements.
737template <>
738struct DenseArrayAttrUtil<bool> : public DenseArrayAttrIntUtil<1> {
739 static void printElement(raw_ostream &os, bool value) {
740 os << (value ? "true" : "false");
741 }
742};
743
744/// Specialization for 8-bit integers to ensure values are printed as integers
745/// and not characters.
746template <>
747struct DenseArrayAttrUtil<int8_t> : public DenseArrayAttrIntUtil<8> {
748 static void printElement(raw_ostream &os, int8_t value) {
749 os << static_cast<int>(value);
750 }
751};
752template <>
753struct DenseArrayAttrUtil<int16_t> : public DenseArrayAttrIntUtil<16> {};
754template <>
755struct DenseArrayAttrUtil<int32_t> : public DenseArrayAttrIntUtil<32> {};
756template <>
757struct DenseArrayAttrUtil<int64_t> : public DenseArrayAttrIntUtil<64> {};
758
759/// Specialization for 32-bit floats.
760template <>
761struct DenseArrayAttrUtil<float> {
762 static bool checkElementType(Type eltType) { return eltType.isF32(); }
763 static Type getElementType(MLIRContext *ctx) { return Float32Type::get(ctx); }
764 static void printElement(raw_ostream &os, float value) { os << value; }
765
766 /// Parse a double and cast it to a float.
767 static ParseResult parseElement(AsmParser &parser, float &value) {
768 double doubleVal;
769 if (parser.parseFloat(doubleVal))
770 return failure();
771 value = doubleVal;
772 return success();
773 }
774};
775
776/// Specialization for 64-bit floats.
777template <>
778struct DenseArrayAttrUtil<double> {
779 static bool checkElementType(Type eltType) { return eltType.isF64(); }
780 static Type getElementType(MLIRContext *ctx) { return Float64Type::get(ctx); }
781 static void printElement(raw_ostream &os, float value) { os << value; }
782 static ParseResult parseElement(AsmParser &parser, double &value) {
783 return parser.parseFloat(value);
784 }
785};
786} // namespace
787
788template <typename T>
790 print(printer.getStream());
791}
792
793template <typename T>
795 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
796 DenseArrayAttrUtil<T>::printElement(os, value);
797 });
798}
799
800template <typename T>
802 os << "[";
804 os << "]";
805}
806
807/// Parse a DenseArrayAttr without the braces: `1, 2, 3`
808template <typename T>
810 Type odsType) {
811 SmallVector<T> data;
812 if (failed(parser.parseCommaSeparatedList([&]() {
813 T value;
814 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
815 return failure();
816 data.push_back(value);
817 return success();
818 })))
819 return {};
820 return get(parser.getContext(), data);
821}
822
823/// Parse a DenseArrayAttr: `[ 1, 2, 3 ]`
824template <typename T>
826 if (parser.parseLSquare())
827 return {};
828 // Handle empty list case.
829 if (succeeded(parser.parseOptionalRSquare()))
830 return get(parser.getContext(), {});
831 Attribute result = parseWithoutBraces(parser, odsType);
832 if (parser.parseRSquare())
833 return {};
834 return result;
835}
836
837/// Conversion from DenseArrayAttr<T> to ArrayRef<T>.
838template <typename T>
841 assert((raw.size() % sizeof(T)) == 0);
842 return ArrayRef<T>(reinterpret_cast<const T *>(raw.data()),
843 raw.size() / sizeof(T));
844}
845
846/// Builds a DenseArrayAttr<T> from an ArrayRef<T>.
847template <typename T>
849 ArrayRef<T> content) {
850 Type elementType = DenseArrayAttrUtil<T>::getElementType(context);
851 auto rawArray = ArrayRef<char>(reinterpret_cast<const char *>(content.data()),
852 content.size() * sizeof(T));
853 return llvm::cast<DenseArrayAttrImpl<T>>(
854 Base::get(context, elementType, content.size(), rawArray));
855}
856
857template <typename T>
859 if (auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
860 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
861 return false;
862}
863
864namespace mlir {
865namespace detail {
866// Explicit instantiation for all the supported DenseArrayAttr.
867template class DenseArrayAttrImpl<bool>;
868template class DenseArrayAttrImpl<int8_t>;
869template class DenseArrayAttrImpl<int16_t>;
870template class DenseArrayAttrImpl<int32_t>;
871template class DenseArrayAttrImpl<int64_t>;
872template class DenseArrayAttrImpl<float>;
873template class DenseArrayAttrImpl<double>;
874} // namespace detail
875} // namespace mlir
876
877//===----------------------------------------------------------------------===//
878// DenseElementsAttr
879//===----------------------------------------------------------------------===//
880
881/// Method for support type inquiry through isa, cast and dyn_cast.
883 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
884}
885
887 ArrayRef<Attribute> values) {
888 assert(hasSameNumElementsOrSplat(type, values));
889 Type eltType = type.getElementType();
890
891 // Take care complex type case first.
892 if (auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
893 if (complexType.getElementType().isIntOrIndex()) {
894 SmallVector<std::complex<APInt>> complexValues;
895 complexValues.reserve(values.size());
896 for (Attribute attr : values) {
897 assert(llvm::isa<ArrayAttr>(attr) && "expected ArrayAttr for complex");
898 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
899 assert(arrayAttr.size() == 2 && "expected 2 element for complex");
900 auto attr0 = arrayAttr[0];
901 auto attr1 = arrayAttr[1];
902 complexValues.push_back(
903 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
904 llvm::cast<IntegerAttr>(attr1).getValue()));
905 }
906 return DenseElementsAttr::get(type, complexValues);
907 }
908 // Must be float.
910 complexValues.reserve(values.size());
911 for (Attribute attr : values) {
912 assert(llvm::isa<ArrayAttr>(attr) && "expected ArrayAttr for complex");
913 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
914 assert(arrayAttr.size() == 2 && "expected 2 element for complex");
915 auto attr0 = arrayAttr[0];
916 auto attr1 = arrayAttr[1];
917 complexValues.push_back(
918 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
919 llvm::cast<FloatAttr>(attr1).getValue()));
920 }
921 return DenseElementsAttr::get(type, complexValues);
922 }
923
924 // If the element type is not based on int/float/index, assume it is a string
925 // type.
926 if (!eltType.isIntOrIndexOrFloat()) {
927 SmallVector<StringRef, 8> stringValues;
928 stringValues.reserve(values.size());
929 for (Attribute attr : values) {
930 assert(llvm::isa<StringAttr>(attr) &&
931 "expected string value for non integer/index/float element");
932 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
933 }
934 return get(type, stringValues);
935 }
936
937 // Otherwise, get the raw storage width to use for the allocation.
938 size_t bitWidth = getDenseElementBitWidth(eltType);
939 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
940
941 // Compress the attribute values into a character buffer.
943 llvm::divideCeil(storageBitWidth * values.size(), CHAR_BIT));
944 APInt intVal;
945 for (unsigned i = 0, e = values.size(); i < e; ++i) {
946 if (auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
947 assert(floatAttr.getType() == eltType &&
948 "expected float attribute type to equal element type");
949 intVal = floatAttr.getValue().bitcastToAPInt();
950 } else if (auto intAttr = llvm::dyn_cast<IntegerAttr>(values[i])) {
951 assert(intAttr.getType() == eltType &&
952 "expected integer attribute type to equal element type");
953 intVal = intAttr.getValue();
954 } else {
955 // Unsupported attribute type.
956 return {};
957 }
958
959 assert(intVal.getBitWidth() == bitWidth &&
960 "expected value to have same bitwidth as element type");
961 writeBits(data.data(), i * storageBitWidth, intVal);
962 }
963
964 return DenseIntOrFPElementsAttr::getRaw(type, data);
965}
966
968 ArrayRef<bool> values) {
969 assert(hasSameNumElementsOrSplat(type, values));
970 assert(type.getElementType().isInteger(1));
971 return DenseIntOrFPElementsAttr::getRaw(
972 type, ArrayRef<char>(reinterpret_cast<const char *>(values.data()),
973 values.size()));
974}
975
977 ArrayRef<StringRef> values) {
978 assert(!type.getElementType().isIntOrFloat());
979 return DenseStringElementsAttr::get(type, values);
980}
981
982/// Constructs a dense integer elements attribute from an array of APInt
983/// values. Each APInt value is expected to have the same bitwidth as the
984/// element type of 'type'.
986 ArrayRef<APInt> values) {
987 assert(type.getElementType().isIntOrIndex());
988 assert(hasSameNumElementsOrSplat(type, values));
989 size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
990 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
991}
993 ArrayRef<std::complex<APInt>> values) {
994 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
995 assert(llvm::isa<IntegerType>(complex.getElementType()));
996 assert(hasSameNumElementsOrSplat(type, values));
997 size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
998 ArrayRef<APInt> intVals(reinterpret_cast<const APInt *>(values.data()),
999 values.size() * 2);
1000 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1001}
1002
1003// Constructs a dense float elements attribute from an array of APFloat
1004// values. Each APFloat value is expected to have the same bitwidth as the
1005// element type of 'type'.
1007 ArrayRef<APFloat> values) {
1008 assert(llvm::isa<FloatType>(type.getElementType()));
1009 assert(hasSameNumElementsOrSplat(type, values));
1010 size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
1011 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1012}
1015 ArrayRef<std::complex<APFloat>> values) {
1016 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1017 assert(llvm::isa<FloatType>(complex.getElementType()));
1018 assert(hasSameNumElementsOrSplat(type, values));
1019 ArrayRef<APFloat> apVals(reinterpret_cast<const APFloat *>(values.data()),
1020 values.size() * 2);
1021 size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
1022 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1023}
1024
1025/// Construct a dense elements attribute from a raw buffer representing the
1026/// data for this attribute. Users should generally not use this methods as
1027/// the expected buffer format may not be a form the user expects.
1030 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1031}
1032
1033/// Returns true if the given buffer is a valid raw buffer for the given type.
1035 ArrayRef<char> rawBuffer) {
1036 size_t storageWidth = getDenseElementStorageWidth(type.getElementType());
1037 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1038 int64_t numElements = type.getNumElements();
1039
1040 // The raw buffer is valid if it has a single element (splat) or the right
1041 // number of elements.
1042 return rawBufferWidth == storageWidth ||
1043 rawBufferWidth == storageWidth * numElements;
1044}
1045
1046/// Check the information for a C++ data type, check if this type is valid for
1047/// the current attribute. This method is used to verify specific type
1048/// invariants that the templatized 'getValues' method cannot.
1049static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt,
1050 bool isSigned) {
1051 // Make sure that the data element size is the same as the type element width.
1052 auto denseEltBitWidth = getDenseElementBitWidth(type);
1053 auto dataSize = static_cast<size_t>(dataEltSize * CHAR_BIT);
1054 if (denseEltBitWidth != dataSize) {
1055 LDBG() << "expected dense element bit width " << denseEltBitWidth
1056 << " to match data size " << dataSize << " for type " << type;
1057 return false;
1058 }
1059
1060 // Check that the element type is either float or integer or index.
1061 if (!isInt) {
1062 bool valid = llvm::isa<FloatType>(type);
1063 if (!valid)
1064 LDBG() << "expected float type when isInt is false, but found " << type;
1065 return valid;
1066 }
1067 if (type.isIndex())
1068 return true;
1069
1070 auto intType = llvm::dyn_cast<IntegerType>(type);
1071 if (!intType) {
1072 LDBG() << "expected integer type when isInt is true, but found " << type;
1073 return false;
1074 }
1075
1076 // Make sure signedness semantics is consistent.
1077 if (intType.isSignless())
1078 return true;
1079
1080 bool valid = intType.isSigned() == isSigned;
1081 if (!valid)
1082 LDBG() << "expected signedness " << isSigned << " to match type " << type;
1083 return valid;
1084}
1085
1086/// Defaults down the subclass implementation.
1088 ArrayRef<char> data,
1089 int64_t dataEltSize,
1090 bool isInt, bool isSigned) {
1091 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1092 isSigned);
1093}
1095 ArrayRef<char> data,
1096 int64_t dataEltSize,
1097 bool isInt,
1098 bool isSigned) {
1099 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1100 isInt, isSigned);
1101}
1102
1104 bool isSigned) const {
1105 return ::isValidIntOrFloat(getElementType(), dataEltSize, isInt, isSigned);
1106}
1107bool DenseElementsAttr::isValidComplex(int64_t dataEltSize, bool isInt,
1108 bool isSigned) const {
1109 return ::isValidIntOrFloat(
1110 llvm::cast<ComplexType>(getElementType()).getElementType(),
1111 dataEltSize / 2, isInt, isSigned);
1112}
1113
1114/// Returns true if this attribute corresponds to a splat, i.e. if all element
1115/// values are the same.
1117 // Splat iff the data array has exactly one element.
1118 if (isa<DenseStringElementsAttr>(*this))
1119 return getRawStringData().size() == 1;
1120 // FP/Int case.
1121 size_t storageSize = llvm::divideCeil(
1123 return getRawData().size() == storageSize;
1124}
1125
1126/// Return if the given complex type has an integer element type.
1127static bool isComplexOfIntType(Type type) {
1128 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).getElementType());
1129}
1130
1139
1142 auto eltTy = llvm::dyn_cast<FloatType>(getElementType());
1143 if (!eltTy)
1144 return failure();
1145 const auto &elementSemantics = eltTy.getFloatSemantics();
1147 getType(), FloatElementIterator(elementSemantics, raw_int_begin()),
1148 FloatElementIterator(elementSemantics, raw_int_end()));
1149}
1150
1153 auto complexTy = llvm::dyn_cast<ComplexType>(getElementType());
1154 if (!complexTy)
1155 return failure();
1156 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1157 if (!eltTy)
1158 return failure();
1159 const auto &semantics = eltTy.getFloatSemantics();
1161 getType(), {semantics, {*this, 0}},
1162 {semantics, {*this, static_cast<size_t>(getNumElements())}});
1163}
1164
1165/// Return the raw storage data held by this attribute.
1169
1173
1174/// Return a new DenseElementsAttr that has the same data as the current
1175/// attribute, but has been reshaped to 'newType'. The new type must have the
1176/// same total number of elements as well as element type.
1178 ShapedType curType = getType();
1179 if (curType == newType)
1180 return *this;
1181
1182 assert(newType.getElementType() == curType.getElementType() &&
1183 "expected the same element type");
1184 assert(newType.getNumElements() == curType.getNumElements() &&
1185 "expected the same number of elements");
1186 return DenseIntOrFPElementsAttr::getRaw(newType, getRawData());
1187}
1188
1190 assert(isSplat() && "expected a splat type");
1191
1192 ShapedType curType = getType();
1193 if (curType == newType)
1194 return *this;
1195
1196 assert(newType.getElementType() == curType.getElementType() &&
1197 "expected the same element type");
1198 return DenseIntOrFPElementsAttr::getRaw(newType, getRawData());
1199}
1200
1201/// Return a new DenseElementsAttr that has the same data as the current
1202/// attribute, but has bitcast elements such that it is now 'newType'. The new
1203/// type must have the same shape and element types of the same bitwidth as the
1204/// current type.
1206 ShapedType curType = getType();
1207 Type curElType = curType.getElementType();
1208 if (curElType == newElType)
1209 return *this;
1210
1211 assert(getDenseElementBitWidth(newElType) ==
1212 getDenseElementBitWidth(curElType) &&
1213 "expected element types with the same bitwidth");
1214 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1215 getRawData());
1216}
1217
1220 function_ref<APInt(const APInt &)> mapping) const {
1221 return llvm::cast<DenseIntElementsAttr>(*this).mapValues(newElementType,
1222 mapping);
1223}
1224
1226 Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1227 return llvm::cast<DenseFPElementsAttr>(*this).mapValues(newElementType,
1228 mapping);
1229}
1230
1231ShapedType DenseElementsAttr::getType() const {
1232 return static_cast<const DenseElementsAttributeStorage *>(impl)->type;
1233}
1234
1236 return getType().getElementType();
1237}
1238
1240 return getType().getNumElements();
1241}
1242
1243//===----------------------------------------------------------------------===//
1244// DenseIntOrFPElementsAttr
1245//===----------------------------------------------------------------------===//
1246
1247/// Utility method to write a range of APInt values to a buffer.
1248template <typename APRangeT>
1249static void writeAPIntsToBuffer(size_t storageWidth,
1251 APRangeT &&values) {
1252 size_t numValues = llvm::size(values);
1253 data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1254 size_t offset = 0;
1255 for (auto it = values.begin(), e = values.end(); it != e;
1256 ++it, offset += storageWidth) {
1257 assert((*it).getBitWidth() <= storageWidth);
1258 writeBits(data.data(), offset, *it);
1259 }
1260}
1261
1262/// Constructs a dense elements attribute from an array of raw APFloat values.
1263/// Each APFloat value is expected to have the same bitwidth as the element
1264/// type of 'type'. 'type' must be a vector or tensor with static shape.
1265DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1266 size_t storageWidth,
1267 ArrayRef<APFloat> values) {
1268 SmallVector<char> data;
1269 auto unwrapFloat = [](const APFloat &val) { return val.bitcastToAPInt(); };
1270 writeAPIntsToBuffer(storageWidth, data, llvm::map_range(values, unwrapFloat));
1271 return DenseIntOrFPElementsAttr::getRaw(type, data);
1272}
1273
1274/// Constructs a dense elements attribute from an array of raw APInt values.
1275/// Each APInt value is expected to have the same bitwidth as the element type
1276/// of 'type'.
1277DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1278 size_t storageWidth,
1279 ArrayRef<APInt> values) {
1280 SmallVector<char> data;
1281 writeAPIntsToBuffer(storageWidth, data, values);
1282 return DenseIntOrFPElementsAttr::getRaw(type, data);
1283}
1284
1285DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1286 ArrayRef<char> data) {
1287 assert(type.hasStaticShape() && "type must have static shape");
1288 assert(isValidRawBuffer(type, data));
1289 return Base::get(type.getContext(), type, data);
1290}
1291
1292/// Overload of the raw 'get' method that asserts that the given type is of
1293/// complex type. This method is used to verify type invariants that the
1294/// templatized 'get' method cannot.
1295DenseElementsAttr DenseIntOrFPElementsAttr::getRawComplex(ShapedType type,
1296 ArrayRef<char> data,
1297 int64_t dataEltSize,
1298 bool isInt,
1299 bool isSigned) {
1300 assert(::isValidIntOrFloat(
1301 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1302 dataEltSize / 2, isInt, isSigned) &&
1303 "Try re-running with -debug-only=builtinattributes");
1304
1305 int64_t numElements = data.size() / dataEltSize;
1306 (void)numElements;
1307 assert(numElements == 1 || numElements == type.getNumElements());
1308 return getRaw(type, data);
1309}
1310
1311/// Overload of the 'getRaw' method that asserts that the given type is of
1312/// integer type. This method is used to verify type invariants that the
1313/// templatized 'get' method cannot.
1314DenseElementsAttr
1315DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
1316 int64_t dataEltSize, bool isInt,
1317 bool isSigned) {
1318 assert(::isValidIntOrFloat(type.getElementType(), dataEltSize, isInt,
1319 isSigned) &&
1320 "Try re-running with -debug-only=builtinattributes");
1321
1322 int64_t numElements = data.size() / dataEltSize;
1323 assert(numElements == 1 || numElements == type.getNumElements());
1324 (void)numElements;
1325 return getRaw(type, data);
1326}
1327
1328void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1329 const char *inRawData, char *outRawData, size_t elementBitWidth,
1330 size_t numElements) {
1331 using llvm::support::ulittle16_t;
1332 using llvm::support::ulittle32_t;
1333 using llvm::support::ulittle64_t;
1334
1335 assert(llvm::endianness::native == llvm::endianness::big);
1336 // NOLINT to avoid warning message about replacing by static_assert()
1337
1338 // Following std::copy_n always converts endianness on BE machine.
1339 switch (elementBitWidth) {
1340 case 16: {
1341 const ulittle16_t *inRawDataPos =
1342 reinterpret_cast<const ulittle16_t *>(inRawData);
1343 uint16_t *outDataPos = reinterpret_cast<uint16_t *>(outRawData);
1344 std::copy_n(inRawDataPos, numElements, outDataPos);
1345 break;
1346 }
1347 case 32: {
1348 const ulittle32_t *inRawDataPos =
1349 reinterpret_cast<const ulittle32_t *>(inRawData);
1350 uint32_t *outDataPos = reinterpret_cast<uint32_t *>(outRawData);
1351 std::copy_n(inRawDataPos, numElements, outDataPos);
1352 break;
1353 }
1354 case 64: {
1355 const ulittle64_t *inRawDataPos =
1356 reinterpret_cast<const ulittle64_t *>(inRawData);
1357 uint64_t *outDataPos = reinterpret_cast<uint64_t *>(outRawData);
1358 std::copy_n(inRawDataPos, numElements, outDataPos);
1359 break;
1360 }
1361 default: {
1362 size_t nBytes = elementBitWidth / CHAR_BIT;
1363 for (size_t i = 0; i < nBytes; i++)
1364 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1365 break;
1366 }
1367 }
1368}
1369
1370void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1371 ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1372 ShapedType type) {
1373 size_t numElements = type.getNumElements();
1374 Type elementType = type.getElementType();
1375 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1376 elementType = complexTy.getElementType();
1377 numElements = numElements * 2;
1378 }
1379 size_t elementBitWidth = getDenseElementStorageWidth(elementType);
1380 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1381 inRawData.size() <= outRawData.size());
1382 if (elementBitWidth <= CHAR_BIT)
1383 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1384 else
1385 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1386 elementBitWidth, numElements);
1387}
1388
1389//===----------------------------------------------------------------------===//
1390// DenseFPElementsAttr
1391//===----------------------------------------------------------------------===//
1392
1393template <typename Fn, typename Attr>
1394static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType,
1395 Type newElementType,
1397 size_t bitWidth = getDenseElementBitWidth(newElementType);
1398 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
1399
1400 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1401
1402 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1403 data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1404
1405 // Functor used to process a single element value of the attribute.
1406 auto processElt = [&](decltype(*attr.begin()) value, size_t index) {
1407 auto newInt = mapping(value);
1408 assert(newInt.getBitWidth() == bitWidth);
1409 writeBits(data.data(), index * storageBitWidth, newInt);
1410 };
1411
1412 // Check for the splat case.
1413 if (attr.isSplat()) {
1414 processElt(*attr.begin(), /*index=*/0);
1415 return newArrayType;
1416 }
1417
1418 // Otherwise, process all of the element values.
1419 uint64_t elementIdx = 0;
1420 for (auto value : attr)
1421 processElt(value, elementIdx++);
1422 return newArrayType;
1423}
1424
1426 Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1427 llvm::SmallVector<char, 8> elementData;
1428 auto newArrayType =
1429 mappingHelper(mapping, *this, getType(), newElementType, elementData);
1430
1431 return getRaw(newArrayType, elementData);
1432}
1433
1434/// Method for supporting type inquiry through isa, cast and dyn_cast.
1436 if (auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1437 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1438 return false;
1439}
1440
1441//===----------------------------------------------------------------------===//
1442// DenseIntElementsAttr
1443//===----------------------------------------------------------------------===//
1444
1446 Type newElementType, function_ref<APInt(const APInt &)> mapping) const {
1447 llvm::SmallVector<char, 8> elementData;
1448 auto newArrayType =
1449 mappingHelper(mapping, *this, getType(), newElementType, elementData);
1450 return getRaw(newArrayType, elementData);
1451}
1452
1453/// Method for supporting type inquiry through isa, cast and dyn_cast.
1455 if (auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1456 return denseAttr.getType().getElementType().isIntOrIndex();
1457 return false;
1458}
1459
1460//===----------------------------------------------------------------------===//
1461// DenseResourceElementsAttr
1462//===----------------------------------------------------------------------===//
1463
1464DenseResourceElementsAttr
1465DenseResourceElementsAttr::get(ShapedType type,
1467 return Base::get(type.getContext(), type, handle);
1468}
1469
1470DenseResourceElementsAttr DenseResourceElementsAttr::get(ShapedType type,
1471 StringRef blobName,
1472 AsmResourceBlob blob) {
1473 // Extract the builtin dialect resource manager from context and construct a
1474 // handle by inserting a new resource using the provided blob.
1475 auto &manager =
1477 return get(type, manager.insert(blobName, std::move(blob)));
1478}
1479
1480ArrayRef<char> DenseResourceElementsAttr::getData() {
1481 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1482 return blob->getDataAs<char>();
1483 return {};
1484}
1485
1486//===----------------------------------------------------------------------===//
1487// DenseResourceElementsAttrBase
1488//===----------------------------------------------------------------------===//
1489
1490namespace {
1491/// Instantiations of this class provide utilities for interacting with native
1492/// data types in the context of DenseResourceElementsAttr.
1493template <typename T>
1494struct DenseResourceAttrUtil;
1495template <size_t width, bool isSigned>
1496struct DenseResourceElementsAttrIntUtil {
1497 static bool checkElementType(Type eltType) {
1498 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1499 if (!type || type.getWidth() != width)
1500 return false;
1501 return isSigned ? !type.isUnsigned() : !type.isSigned();
1502 }
1503};
1504template <>
1505struct DenseResourceAttrUtil<bool> {
1506 static bool checkElementType(Type eltType) {
1507 return eltType.isSignlessInteger(1);
1508 }
1509};
1510template <>
1511struct DenseResourceAttrUtil<int8_t>
1512 : public DenseResourceElementsAttrIntUtil<8, true> {};
1513template <>
1514struct DenseResourceAttrUtil<uint8_t>
1515 : public DenseResourceElementsAttrIntUtil<8, false> {};
1516template <>
1517struct DenseResourceAttrUtil<int16_t>
1518 : public DenseResourceElementsAttrIntUtil<16, true> {};
1519template <>
1520struct DenseResourceAttrUtil<uint16_t>
1521 : public DenseResourceElementsAttrIntUtil<16, false> {};
1522template <>
1523struct DenseResourceAttrUtil<int32_t>
1524 : public DenseResourceElementsAttrIntUtil<32, true> {};
1525template <>
1526struct DenseResourceAttrUtil<uint32_t>
1527 : public DenseResourceElementsAttrIntUtil<32, false> {};
1528template <>
1529struct DenseResourceAttrUtil<int64_t>
1530 : public DenseResourceElementsAttrIntUtil<64, true> {};
1531template <>
1532struct DenseResourceAttrUtil<uint64_t>
1533 : public DenseResourceElementsAttrIntUtil<64, false> {};
1534template <>
1535struct DenseResourceAttrUtil<float> {
1536 static bool checkElementType(Type eltType) { return eltType.isF32(); }
1537};
1538template <>
1539struct DenseResourceAttrUtil<double> {
1540 static bool checkElementType(Type eltType) { return eltType.isF64(); }
1541};
1542} // namespace
1543
1544template <typename T>
1545DenseResourceElementsAttrBase<T>
1546DenseResourceElementsAttrBase<T>::get(ShapedType type, StringRef blobName,
1547 AsmResourceBlob blob) {
1548 // Check that the blob is in the form we were expecting.
1549 assert(blob.getDataAlignment() == alignof(T) &&
1550 "alignment mismatch between expected alignment and blob alignment");
1551 assert(((blob.getData().size() % sizeof(T)) == 0) &&
1552 "size mismatch between expected element width and blob size");
1553 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1554 "invalid shape element type for provided type `T`");
1555 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1556 DenseResourceElementsAttr::get(type, blobName, std::move(blob)));
1557}
1558
1559template <typename T>
1560std::optional<ArrayRef<T>>
1562 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1563 return blob->template getDataAs<T>();
1564 return std::nullopt;
1565}
1566
1567template <typename T>
1569 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1570 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1571 resourceAttr.getElementType());
1572}
1573
1574namespace mlir {
1575namespace detail {
1576// Explicit instantiation for all the supported DenseResourceElementsAttr.
1588} // namespace detail
1589} // namespace mlir
1590
1591//===----------------------------------------------------------------------===//
1592// SparseElementsAttr
1593//===----------------------------------------------------------------------===//
1594
1595/// Get a zero APFloat for the given sparse attribute.
1596APFloat SparseElementsAttr::getZeroAPFloat() const {
1597 auto eltType = llvm::cast<FloatType>(getElementType());
1598 return APFloat(eltType.getFloatSemantics());
1599}
1600
1601/// Get a zero APInt for the given sparse attribute.
1602APInt SparseElementsAttr::getZeroAPInt() const {
1603 auto eltType = llvm::cast<IntegerType>(getElementType());
1604 return APInt::getZero(eltType.getWidth());
1605}
1606
1607/// Get a zero attribute for the given attribute type.
1608Attribute SparseElementsAttr::getZeroAttr() const {
1609 auto eltType = getElementType();
1610
1611 // Handle floating point elements.
1612 if (llvm::isa<FloatType>(eltType))
1613 return FloatAttr::get(eltType, 0);
1614
1615 // Handle complex elements.
1616 if (auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1617 auto eltType = complexTy.getElementType();
1618 Attribute zero;
1619 if (llvm::isa<FloatType>(eltType))
1620 zero = FloatAttr::get(eltType, 0);
1621 else // must be integer
1622 zero = IntegerAttr::get(eltType, 0);
1623 return ArrayAttr::get(complexTy.getContext(),
1624 ArrayRef<Attribute>{zero, zero});
1625 }
1626
1627 // Handle string type.
1628 if (llvm::isa<DenseStringElementsAttr>(getValues()))
1629 return StringAttr::get("", eltType);
1630
1631 // Otherwise, this is an integer.
1632 return IntegerAttr::get(eltType, 0);
1633}
1634
1635/// Flatten, and return, all of the sparse indices in this attribute in
1636/// row-major order.
1637SmallVector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices() const {
1638 SmallVector<ptrdiff_t> flatSparseIndices;
1639
1640 // The sparse indices are 64-bit integers, so we can reinterpret the raw data
1641 // as a 1-D index array.
1642 auto sparseIndices = getIndices();
1643 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1644 if (sparseIndices.isSplat()) {
1645 SmallVector<uint64_t, 8> indices(getType().getRank(),
1646 *sparseIndexValues.begin());
1647 flatSparseIndices.push_back(getFlattenedIndex(indices));
1648 return flatSparseIndices;
1649 }
1650
1651 // Otherwise, reinterpret each index as an ArrayRef when flattening.
1652 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1653 size_t rank = getType().getRank();
1654 for (size_t i = 0, e = numSparseIndices; i != e; ++i)
1655 flatSparseIndices.push_back(getFlattenedIndex(
1656 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1657 return flatSparseIndices;
1658}
1659
1660LogicalResult
1661SparseElementsAttr::verify(function_ref<InFlightDiagnostic()> emitError,
1662 ShapedType type, DenseIntElementsAttr sparseIndices,
1663 DenseElementsAttr values) {
1664 ShapedType valuesType = values.getType();
1665 if (valuesType.getRank() != 1)
1666 return emitError() << "expected 1-d tensor for sparse element values";
1667
1668 // Verify the indices and values shape.
1669 ShapedType indicesType = sparseIndices.getType();
1670 auto emitShapeError = [&]() {
1671 return emitError() << "expected shape ([" << type.getShape()
1672 << "]); inferred shape of indices literal (["
1673 << indicesType.getShape()
1674 << "]); inferred shape of values literal (["
1675 << valuesType.getShape() << "])";
1676 };
1677 // Verify indices shape.
1678 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1679 if (indicesRank == 2) {
1680 if (indicesType.getDimSize(1) != static_cast<int64_t>(rank))
1681 return emitShapeError();
1682 } else if (indicesRank != 1 || rank != 1) {
1683 return emitShapeError();
1684 }
1685 // Verify the values shape.
1686 int64_t numSparseIndices = indicesType.getDimSize(0);
1687 if (numSparseIndices != valuesType.getDimSize(0))
1688 return emitShapeError();
1689
1690 // Verify that the sparse indices are within the value shape.
1691 auto emitIndexError = [&](unsigned indexNum, ArrayRef<uint64_t> index) {
1692 return emitError()
1693 << "sparse index #" << indexNum
1694 << " is not contained within the value shape, with index=[" << index
1695 << "], and type=" << type;
1696 };
1697
1698 // Handle the case where the index values are a splat.
1699 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1700 if (sparseIndices.isSplat()) {
1701 SmallVector<uint64_t> indices(rank, *sparseIndexValues.begin());
1702 if (!ElementsAttr::isValidIndex(type, indices))
1703 return emitIndexError(0, indices);
1704 return success();
1705 }
1706
1707 // Otherwise, reinterpret each index as an ArrayRef.
1708 for (size_t i = 0, e = numSparseIndices; i != e; ++i) {
1709 ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1710 rank);
1711 if (!ElementsAttr::isValidIndex(type, index))
1712 return emitIndexError(i, index);
1713 }
1714
1715 return success();
1716}
1717
1718//===----------------------------------------------------------------------===//
1719// DistinctAttr
1720//===----------------------------------------------------------------------===//
1721
1723 return Base::get(referencedAttr.getContext(), referencedAttr);
1724}
1725
1727 return getImpl()->referencedAttr;
1728}
1729
1730//===----------------------------------------------------------------------===//
1731// Attribute Utilities
1732//===----------------------------------------------------------------------===//
1733
1735 int64_t offset,
1736 MLIRContext *context) {
1737 AffineExpr expr;
1738 unsigned nSymbols = 0;
1739
1740 // AffineExpr for offset.
1741 // Static case.
1742 if (ShapedType::isStatic(offset)) {
1743 auto cst = getAffineConstantExpr(offset, context);
1744 expr = cst;
1745 } else {
1746 // Dynamic case, new symbol for the offset.
1747 auto sym = getAffineSymbolExpr(nSymbols++, context);
1748 expr = sym;
1749 }
1750
1751 // AffineExpr for strides.
1752 for (const auto &en : llvm::enumerate(strides)) {
1753 auto dim = en.index();
1754 auto stride = en.value();
1755 auto d = getAffineDimExpr(dim, context);
1756 AffineExpr mult;
1757 // Static case.
1758 if (ShapedType::isStatic(stride))
1759 mult = getAffineConstantExpr(stride, context);
1760 else
1761 // Dynamic case, new symbol for each new stride.
1762 mult = getAffineSymbolExpr(nSymbols++, context);
1763 expr = expr + d * mult;
1764 }
1765
1766 return AffineMap::get(strides.size(), nSymbols, expr);
1767}
return success()
static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt, bool isSigned)
Check the information for a C++ data type, check if this type is valid for the current attribute.
static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes, char *result)
Copy actual numBytes data from value (APInt) to char array(result) for BE format.
static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType, Type newElementType, llvm::SmallVectorImpl< char > &data)
static bool hasSameNumElementsOrSplat(ShapedType type, const Values &values)
Returns true if 'values' corresponds to a splat, i.e.
static void writeAPIntsToBuffer(size_t storageWidth, SmallVectorImpl< char > &data, APRangeT &&values)
Utility method to write a range of APInt values to a buffer.
static void writeBits(char *rawData, size_t bitPos, APInt value)
Writes value to the bit position bitPos in array rawData.
static bool dictionaryAttrSort(ArrayRef< NamedAttribute > value, SmallVectorImpl< NamedAttribute > &storage)
Helper function that does either an in place sort or sorts from source array into destination.
static std::optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
static size_t getDenseElementStorageWidth(size_t origWidth)
Get the bitwidth of a dense element type within the buffer.
static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes, APInt &result)
Copy numBytes data from inArray(char array) to result(APINT) for BE format.
static bool isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth)
Reads the next bitWidth bits from the bit position bitPos in array rawData.
static Type getElementType(Type type)
Determine the element type of type.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
b getContext())
Base type for affine expression.
Definition AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
MLIRContext * getContext() const
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalRSquare()=0
Parse a ] token if present.
virtual ParseResult parseFloat(double &result)=0
Parse a floating point value from the stream.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
This class represents a processed binary blob of data.
Definition AsmState.h:91
size_t getDataAlignment() const
Return the alignment of the underlying data.
Definition AsmState.h:142
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
Definition AsmState.h:145
Attributes are known-constant values of operations.
Definition Attributes.h:25
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
MLIRContext * getContext() const
Return the context this attribute belongs to.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
Definition Attributes.h:75
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
static bool classof(Attribute attr)
Methods for support type inquiry through isa, cast, and dyn_cast.
constexpr Attribute()=default
bool getValue() const
Return the boolean value of this attribute.
Attribute operator*() const
Accesses the Attribute value at this iterator position.
A utility iterator that allows walking over the internal bool values.
bool operator*() const
Accesses the bool value at this iterator position.
Iterator for walking over complex APFloat values.
A utility iterator that allows walking over the internal raw complex APInt values.
std::complex< APInt > operator*() const
Accesses the raw std::complex<APInt> value at this iterator position.
Iterator for walking over APFloat values.
A utility iterator that allows walking over the internal raw APInt values.
APInt operator*() const
Accesses the raw APInt value at this iterator position.
An attribute that represents a reference to a dense vector or tensor object.
ArrayRef< StringRef > getRawStringData() const
Return the raw StringRef data held by this attribute.
IntElementIterator raw_int_begin() const
Iterators to various elements that require out-of-line definition.
static DenseElementsAttr getRawIntOrFloat(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw 'get' method that asserts that the given type is of integer or floating-point typ...
static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw 'get' method that asserts that the given type is of complex type.
static bool classof(Attribute attr)
Method for support type inquiry through isa, cast and dyn_cast.
bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
detail::ElementsAttrRange< IteratorT > iterator_range_impl
The iterator range over the given iterator type T.
int64_t getNumElements() const
Returns the number of elements held by this attribute.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Returns true if the given buffer is a valid raw buffer for the given type.
int64_t size() const
Returns the number of elements held by this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
constexpr Attribute()=default
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each int value to a new underlying APInt.
Type getElementType() const
Return the element type of this DenseElementsAttr.
FailureOr< iterator_range_impl< ComplexFloatElementIterator > > tryGetComplexFloatValues() const
IntElementIterator raw_int_end() const
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
FailureOr< iterator_range_impl< FloatElementIterator > > tryGetFloatValues() const
DenseElementsAttr bitcast(Type newElType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has bitcast eleme...
bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr reshape(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has been reshaped...
FailureOr< iterator_range_impl< ComplexIntElementIterator > > tryGetComplexIntValues() const
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APFloat &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition Dialect.h:38
static bool isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
Definition Dialect.cpp:95
An attribute that associates a referenced attribute with a unique identifier.
static DistinctAttr create(Attribute referencedAttr)
Creates a distinct attribute that associates a referenced attribute with a unique identifier.
Attribute getReferencedAttr() const
Returns the referenced attribute.
A symbol reference with a reference path containing a single element.
This class represents a diagnostic that is inflight and set to be reported.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
NamedAttribute represents a combination of a name and an Attribute value.
Definition Attributes.h:164
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
AttrClass getAttrOfType(StringAttr name)
Definition Operation.h:550
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition SymbolTable.h:76
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isF64() const
Definition Types.cpp:41
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition Types.cpp:35
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
Definition Types.cpp:66
bool isIndex() const
Definition Types.cpp:56
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
Definition Types.cpp:122
bool isF32() const
Definition Types.cpp:40
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition Types.cpp:124
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
static bool classof(Attribute attr)
Support for isa<>/cast<>.
void print(AsmPrinter &printer) const
Print the short form [42, 100, -1] without any type prefix.
static Attribute parse(AsmParser &parser, Type type)
Parse the short form [42, 100, -1] without any type prefix.
static Attribute parseWithoutBraces(AsmParser &parser, Type type)
Parse the short form 42, 100, -1 without any type prefix or braces.
void printWithoutBraces(raw_ostream &os) const
Print the short form 42, 100, -1 without any braces or type prefix.
Impl iterator for indexed DenseElementsAttr iterators that records a data pointer and data index that...
Base class for DenseResourceElementsAttr that is instantiated and specialized for each supported elem...
static bool classof(Attribute attr)
Support for isa<>/cast<>.
static DenseResourceElementsAttrBase< T > get(ShapedType type, StringRef blobName, AsmResourceBlob blob)
A builder that inserts a new resource using the provided blob.
std::optional< ArrayRef< T > > tryGetAsArrayRef() const
Return the data of this attribute as an ArrayRef<T> if it is present, returns std::nullopt otherwise.
static ConcreteT get(MLIRContext *ctx, Args &&...args)
Get or create a new ConcreteT instance within the ctx.
AttrTypeReplacer.
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
Definition Utils.cpp:18
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:305
DialectResourceBlobHandle< BuiltinDialect > DenseResourceElementsHandle
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
AffineMap makeStridedLinearLayoutMap(ArrayRef< int64_t > strides, int64_t offset, MLIRContext *context)
Given a list of strides (in which ShapedType::kDynamic represents a dynamic value),...
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
llvm::function_ref< Fn > function_ref
Definition LLVM.h:144
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object containing strings.