MLIR 22.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
458
459/// Get the bitwidth of a dense element type within the buffer.
460/// DenseElementsAttr requires bitwidths greater than 1 to be aligned by 8.
461static size_t getDenseElementStorageWidth(size_t origWidth) {
462 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
463}
464static size_t getDenseElementStorageWidth(Type elementType) {
466}
467
468/// Set a bit to a specific value.
469static void setBit(char *rawData, size_t bitPos, bool value) {
470 if (value)
471 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
472 else
473 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
474}
475
476/// Return the value of the specified bit.
477static bool getBit(const char *rawData, size_t bitPos) {
478 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
479}
480
481/// Copy actual `numBytes` data from `value` (APInt) to char array(`result`) for
482/// BE format.
483static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes,
484 char *result) {
485 assert(llvm::endianness::native == llvm::endianness::big);
486 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
487
488 // Copy the words filled with data.
489 // For example, when `value` has 2 words, the first word is filled with data.
490 // `value` (10 bytes, BE):|abcdefgh|------ij| ==> `result` (BE):|abcdefgh|--|
491 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
492 std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
493 numFilledWords, result);
494 // Convert last word of APInt to LE format and store it in char
495 // array(`valueLE`).
496 // ex. last word of `value` (BE): |------ij| ==> `valueLE` (LE): |ji------|
497 size_t lastWordPos = numFilledWords;
498 SmallVector<char, 8> valueLE(APInt::APINT_WORD_SIZE);
499 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
500 reinterpret_cast<const char *>(value.getRawData()) + lastWordPos,
501 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
502 // Extract actual APInt data from `valueLE`, convert endianness to BE format,
503 // and store it in `result`.
504 // ex. `valueLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|ij|
505 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
506 valueLE.begin(), result + lastWordPos,
507 (numBytes - lastWordPos) * CHAR_BIT, 1);
508}
509
510/// Copy `numBytes` data from `inArray`(char array) to `result`(APINT) for BE
511/// format.
512static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes,
513 APInt &result) {
514 assert(llvm::endianness::native == llvm::endianness::big);
515 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
516
517 // Copy the data that fills the word of `result` from `inArray`.
518 // For example, when `result` has 2 words, the first word will be filled with
519 // data. So, the first 8 bytes are copied from `inArray` here.
520 // `inArray` (10 bytes, BE): |abcdefgh|ij|
521 // ==> `result` (2 words, BE): |abcdefgh|--------|
522 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
523 std::copy_n(
524 inArray, numFilledWords,
525 const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())));
526
527 // Convert array data which will be last word of `result` to LE format, and
528 // store it in char array(`inArrayLE`).
529 // ex. `inArray` (last two bytes, BE): |ij| ==> `inArrayLE` (LE): |ji------|
530 size_t lastWordPos = numFilledWords;
531 SmallVector<char, 8> inArrayLE(APInt::APINT_WORD_SIZE);
532 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
533 inArray + lastWordPos, inArrayLE.begin(),
534 (numBytes - lastWordPos) * CHAR_BIT, 1);
535
536 // Convert `inArrayLE` to BE format, and store it in last word of `result`.
537 // ex. `inArrayLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|------ij|
538 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
539 inArrayLE.begin(),
540 const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())) +
541 lastWordPos,
542 APInt::APINT_BITS_PER_WORD, 1);
543}
544
545/// Writes value to the bit position `bitPos` in array `rawData`.
546static void writeBits(char *rawData, size_t bitPos, APInt value) {
547 size_t bitWidth = value.getBitWidth();
548
549 // If the bitwidth is 1 we just toggle the specific bit.
550 if (bitWidth == 1)
551 return setBit(rawData, bitPos, value.isOne());
552
553 // Otherwise, the bit position is guaranteed to be byte aligned.
554 assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
555 if (llvm::endianness::native == llvm::endianness::big) {
556 // Copy from `value` to `rawData + (bitPos / CHAR_BIT)`.
557 // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
558 // work correctly in BE format.
559 // ex. `value` (2 words including 10 bytes)
560 // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------|
561 copyAPIntToArrayForBEmachine(value, llvm::divideCeil(bitWidth, CHAR_BIT),
562 rawData + (bitPos / CHAR_BIT));
563 } else {
564 std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
565 llvm::divideCeil(bitWidth, CHAR_BIT),
566 rawData + (bitPos / CHAR_BIT));
567 }
568}
569
570/// Reads the next `bitWidth` bits from the bit position `bitPos` in array
571/// `rawData`.
572static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth) {
573 // Handle a boolean bit position.
574 if (bitWidth == 1)
575 return APInt(1, getBit(rawData, bitPos) ? 1 : 0);
576
577 // Otherwise, the bit position must be 8-bit aligned.
578 assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
579 APInt result(bitWidth, 0);
580 if (llvm::endianness::native == llvm::endianness::big) {
581 // Copy from `rawData + (bitPos / CHAR_BIT)` to `result`.
582 // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
583 // work correctly in BE format.
584 // ex. `result` (2 words including 10 bytes)
585 // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------| This function
586 copyArrayToAPIntForBEmachine(rawData + (bitPos / CHAR_BIT),
587 llvm::divideCeil(bitWidth, CHAR_BIT), result);
588 } else {
589 std::copy_n(rawData + (bitPos / CHAR_BIT),
590 llvm::divideCeil(bitWidth, CHAR_BIT),
591 const_cast<char *>(
592 reinterpret_cast<const char *>(result.getRawData())));
593 }
594 return result;
595}
596
597/// Returns true if 'values' corresponds to a splat, i.e. one element, or has
598/// the same element count as 'type'.
599template <typename Values>
600static bool hasSameNumElementsOrSplat(ShapedType type, const Values &values) {
601 return (values.size() == 1) ||
602 (type.getNumElements() == static_cast<int64_t>(values.size()));
603}
604
605//===----------------------------------------------------------------------===//
606// DenseElementsAttr Iterators
607//===----------------------------------------------------------------------===//
608
609//===----------------------------------------------------------------------===//
610// AttributeElementIterator
611//===----------------------------------------------------------------------===//
612
613DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
614 DenseElementsAttr attr, size_t index)
615 : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
617 attr.getAsOpaquePointer(), index) {}
618
620 auto owner = llvm::cast<DenseElementsAttr>(getFromOpaquePointer(base));
621 Type eltTy = owner.getElementType();
622 if (llvm::dyn_cast<IntegerType>(eltTy))
623 return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
624 if (llvm::isa<IndexType>(eltTy))
625 return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
626 if (auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
627 IntElementIterator intIt(owner, index);
628 FloatElementIterator floatIt(floatEltTy.getFloatSemantics(), intIt);
629 return FloatAttr::get(eltTy, *floatIt);
630 }
631 if (auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
632 auto complexEltTy = complexTy.getElementType();
633 ComplexIntElementIterator complexIntIt(owner, index);
634 if (llvm::isa<IntegerType>(complexEltTy)) {
635 auto value = *complexIntIt;
636 auto real = IntegerAttr::get(complexEltTy, value.real());
637 auto imag = IntegerAttr::get(complexEltTy, value.imag());
638 return ArrayAttr::get(complexTy.getContext(),
639 ArrayRef<Attribute>{real, imag});
640 }
641
642 ComplexFloatElementIterator complexFloatIt(
643 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
644 auto value = *complexFloatIt;
645 auto real = FloatAttr::get(complexEltTy, value.real());
646 auto imag = FloatAttr::get(complexEltTy, value.imag());
647 return ArrayAttr::get(complexTy.getContext(),
648 ArrayRef<Attribute>{real, imag});
649 }
650 if (llvm::isa<DenseStringElementsAttr>(owner)) {
651 ArrayRef<StringRef> vals = owner.getRawStringData();
652 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
653 }
654 llvm_unreachable("unexpected element type");
655}
656
657//===----------------------------------------------------------------------===//
658// BoolElementIterator
659//===----------------------------------------------------------------------===//
660
661DenseElementsAttr::BoolElementIterator::BoolElementIterator(
662 DenseElementsAttr attr, size_t dataIndex)
664 attr.getRawData().data(), attr.isSplat(), dataIndex) {}
665
669
670//===----------------------------------------------------------------------===//
671// IntElementIterator
672//===----------------------------------------------------------------------===//
673
674DenseElementsAttr::IntElementIterator::IntElementIterator(
675 DenseElementsAttr attr, size_t dataIndex)
677 attr.getRawData().data(), attr.isSplat(), dataIndex),
678 bitWidth(getDenseElementBitWidth(attr.getElementType())) {}
679
681 return readBits(getData(),
683 bitWidth);
684}
685
686//===----------------------------------------------------------------------===//
687// ComplexIntElementIterator
688//===----------------------------------------------------------------------===//
689
690DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
691 DenseElementsAttr attr, size_t dataIndex)
693 std::complex<APInt>, std::complex<APInt>,
694 std::complex<APInt>>(
695 attr.getRawData().data(), attr.isSplat(), dataIndex) {
696 auto complexType = llvm::cast<ComplexType>(attr.getElementType());
697 bitWidth = getDenseElementBitWidth(complexType.getElementType());
698}
699
700std::complex<APInt>
702 size_t storageWidth = getDenseElementStorageWidth(bitWidth);
703 size_t offset = getDataIndex() * storageWidth * 2;
704 return {readBits(getData(), offset, bitWidth),
705 readBits(getData(), offset + storageWidth, bitWidth)};
706}
707
708//===----------------------------------------------------------------------===//
709// DenseArrayAttr
710//===----------------------------------------------------------------------===//
711
712LogicalResult
713DenseArrayAttr::verify(function_ref<InFlightDiagnostic()> emitError,
714 Type elementType, int64_t size, ArrayRef<char> rawData) {
715 if (!elementType.isIntOrIndexOrFloat())
716 return emitError() << "expected integer or floating point element type";
717 int64_t dataSize = rawData.size();
718 int64_t elementSize =
719 llvm::divideCeil(elementType.getIntOrFloatBitWidth(), CHAR_BIT);
720 if (size * elementSize != dataSize) {
721 return emitError() << "expected data size (" << size << " elements, "
722 << elementSize
723 << " bytes each) does not match: " << dataSize
724 << " bytes";
725 }
726 return success();
727}
728
729namespace {
730/// Instantiations of this class provide utilities for interacting with native
731/// data types in the context of DenseArrayAttr.
732template <size_t width,
733 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
734struct DenseArrayAttrIntUtil {
735 static bool checkElementType(Type eltType) {
736 auto type = llvm::dyn_cast<IntegerType>(eltType);
737 if (!type || type.getWidth() != width)
738 return false;
739 return type.getSignedness() == signedness;
740 }
741
742 static Type getElementType(MLIRContext *ctx) {
743 return IntegerType::get(ctx, width, signedness);
744 }
745
746 template <typename T>
747 static void printElement(raw_ostream &os, T value) {
748 os << value;
749 }
750
751 template <typename T>
752 static ParseResult parseElement(AsmParser &parser, T &value) {
753 return parser.parseInteger(value);
754 }
755};
756template <typename T>
757struct DenseArrayAttrUtil;
758
759/// Specialization for boolean elements to print 'true' and 'false' literals for
760/// elements.
761template <>
762struct DenseArrayAttrUtil<bool> : public DenseArrayAttrIntUtil<1> {
763 static void printElement(raw_ostream &os, bool value) {
764 os << (value ? "true" : "false");
765 }
766};
767
768/// Specialization for 8-bit integers to ensure values are printed as integers
769/// and not characters.
770template <>
771struct DenseArrayAttrUtil<int8_t> : public DenseArrayAttrIntUtil<8> {
772 static void printElement(raw_ostream &os, int8_t value) {
773 os << static_cast<int>(value);
774 }
775};
776template <>
777struct DenseArrayAttrUtil<int16_t> : public DenseArrayAttrIntUtil<16> {};
778template <>
779struct DenseArrayAttrUtil<int32_t> : public DenseArrayAttrIntUtil<32> {};
780template <>
781struct DenseArrayAttrUtil<int64_t> : public DenseArrayAttrIntUtil<64> {};
782
783/// Specialization for 32-bit floats.
784template <>
785struct DenseArrayAttrUtil<float> {
786 static bool checkElementType(Type eltType) { return eltType.isF32(); }
787 static Type getElementType(MLIRContext *ctx) { return Float32Type::get(ctx); }
788 static void printElement(raw_ostream &os, float value) { os << value; }
789
790 /// Parse a double and cast it to a float.
791 static ParseResult parseElement(AsmParser &parser, float &value) {
792 double doubleVal;
793 if (parser.parseFloat(doubleVal))
794 return failure();
795 value = doubleVal;
796 return success();
797 }
798};
799
800/// Specialization for 64-bit floats.
801template <>
802struct DenseArrayAttrUtil<double> {
803 static bool checkElementType(Type eltType) { return eltType.isF64(); }
804 static Type getElementType(MLIRContext *ctx) { return Float64Type::get(ctx); }
805 static void printElement(raw_ostream &os, float value) { os << value; }
806 static ParseResult parseElement(AsmParser &parser, double &value) {
807 return parser.parseFloat(value);
808 }
809};
810} // namespace
811
812template <typename T>
814 print(printer.getStream());
815}
816
817template <typename T>
819 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
820 DenseArrayAttrUtil<T>::printElement(os, value);
821 });
822}
823
824template <typename T>
826 os << "[";
828 os << "]";
829}
830
831/// Parse a DenseArrayAttr without the braces: `1, 2, 3`
832template <typename T>
834 Type odsType) {
835 SmallVector<T> data;
836 if (failed(parser.parseCommaSeparatedList([&]() {
837 T value;
838 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
839 return failure();
840 data.push_back(value);
841 return success();
842 })))
843 return {};
844 return get(parser.getContext(), data);
845}
846
847/// Parse a DenseArrayAttr: `[ 1, 2, 3 ]`
848template <typename T>
850 if (parser.parseLSquare())
851 return {};
852 // Handle empty list case.
853 if (succeeded(parser.parseOptionalRSquare()))
854 return get(parser.getContext(), {});
855 Attribute result = parseWithoutBraces(parser, odsType);
856 if (parser.parseRSquare())
857 return {};
858 return result;
859}
860
861/// Conversion from DenseArrayAttr<T> to ArrayRef<T>.
862template <typename T>
865 assert((raw.size() % sizeof(T)) == 0);
866 return ArrayRef<T>(reinterpret_cast<const T *>(raw.data()),
867 raw.size() / sizeof(T));
868}
869
870/// Builds a DenseArrayAttr<T> from an ArrayRef<T>.
871template <typename T>
873 ArrayRef<T> content) {
874 Type elementType = DenseArrayAttrUtil<T>::getElementType(context);
875 auto rawArray = ArrayRef<char>(reinterpret_cast<const char *>(content.data()),
876 content.size() * sizeof(T));
877 return llvm::cast<DenseArrayAttrImpl<T>>(
878 Base::get(context, elementType, content.size(), rawArray));
879}
880
881template <typename T>
883 if (auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
884 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
885 return false;
886}
887
888namespace mlir {
889namespace detail {
890// Explicit instantiation for all the supported DenseArrayAttr.
891template class DenseArrayAttrImpl<bool>;
892template class DenseArrayAttrImpl<int8_t>;
893template class DenseArrayAttrImpl<int16_t>;
894template class DenseArrayAttrImpl<int32_t>;
895template class DenseArrayAttrImpl<int64_t>;
896template class DenseArrayAttrImpl<float>;
897template class DenseArrayAttrImpl<double>;
898} // namespace detail
899} // namespace mlir
900
901//===----------------------------------------------------------------------===//
902// DenseElementsAttr
903//===----------------------------------------------------------------------===//
904
905/// Method for support type inquiry through isa, cast and dyn_cast.
907 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
908}
909
911 ArrayRef<Attribute> values) {
912 assert(hasSameNumElementsOrSplat(type, values));
913
914 Type eltType = type.getElementType();
915
916 // Take care complex type case first.
917 if (auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
918 if (complexType.getElementType().isIntOrIndex()) {
919 SmallVector<std::complex<APInt>> complexValues;
920 complexValues.reserve(values.size());
921 for (Attribute attr : values) {
922 assert(llvm::isa<ArrayAttr>(attr) && "expected ArrayAttr for complex");
923 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
924 assert(arrayAttr.size() == 2 && "expected 2 element for complex");
925 auto attr0 = arrayAttr[0];
926 auto attr1 = arrayAttr[1];
927 complexValues.push_back(
928 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
929 llvm::cast<IntegerAttr>(attr1).getValue()));
930 }
931 return DenseElementsAttr::get(type, complexValues);
932 }
933 // Must be float.
935 complexValues.reserve(values.size());
936 for (Attribute attr : values) {
937 assert(llvm::isa<ArrayAttr>(attr) && "expected ArrayAttr for complex");
938 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
939 assert(arrayAttr.size() == 2 && "expected 2 element for complex");
940 auto attr0 = arrayAttr[0];
941 auto attr1 = arrayAttr[1];
942 complexValues.push_back(
943 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
944 llvm::cast<FloatAttr>(attr1).getValue()));
945 }
946 return DenseElementsAttr::get(type, complexValues);
947 }
948
949 // If the element type is not based on int/float/index, assume it is a string
950 // type.
951 if (!eltType.isIntOrIndexOrFloat()) {
952 SmallVector<StringRef, 8> stringValues;
953 stringValues.reserve(values.size());
954 for (Attribute attr : values) {
955 assert(llvm::isa<StringAttr>(attr) &&
956 "expected string value for non integer/index/float element");
957 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
958 }
959 return get(type, stringValues);
960 }
961
962 // Otherwise, get the raw storage width to use for the allocation.
963 size_t bitWidth = getDenseElementBitWidth(eltType);
964 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
965
966 // Compress the attribute values into a character buffer.
968 llvm::divideCeil(storageBitWidth * values.size(), CHAR_BIT));
969 APInt intVal;
970 for (unsigned i = 0, e = values.size(); i < e; ++i) {
971 if (auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
972 assert(floatAttr.getType() == eltType &&
973 "expected float attribute type to equal element type");
974 intVal = floatAttr.getValue().bitcastToAPInt();
975 } else {
976 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
977 assert(intAttr.getType() == eltType &&
978 "expected integer attribute type to equal element type");
979 intVal = intAttr.getValue();
980 }
981
982 assert(intVal.getBitWidth() == bitWidth &&
983 "expected value to have same bitwidth as element type");
984 writeBits(data.data(), i * storageBitWidth, intVal);
985 }
986
987 // Handle the special encoding of splat of bool.
988 if (values.size() == 1 && eltType.isInteger(1))
989 data[0] = data[0] ? -1 : 0;
990
991 return DenseIntOrFPElementsAttr::getRaw(type, data);
992}
993
995 ArrayRef<bool> values) {
996 assert(hasSameNumElementsOrSplat(type, values));
997 assert(type.getElementType().isInteger(1));
998
999 SmallVector<char> buff(llvm::divideCeil(values.size(), CHAR_BIT));
1000
1001 if (!values.empty()) {
1002 bool isSplat = true;
1003 bool firstValue = values[0];
1004 for (int i = 0, e = values.size(); i != e; ++i) {
1005 isSplat &= values[i] == firstValue;
1006 setBit(buff.data(), i, values[i]);
1007 }
1008
1009 // Splat of bool is encoded as a byte with all-ones in it.
1010 if (isSplat) {
1011 buff.resize(1);
1012 buff[0] = values[0] ? -1 : 0;
1013 }
1014 }
1015
1016 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1017}
1018
1020 ArrayRef<StringRef> values) {
1021 assert(!type.getElementType().isIntOrFloat());
1022 return DenseStringElementsAttr::get(type, values);
1023}
1024
1025/// Constructs a dense integer elements attribute from an array of APInt
1026/// values. Each APInt value is expected to have the same bitwidth as the
1027/// element type of 'type'.
1029 ArrayRef<APInt> values) {
1030 assert(type.getElementType().isIntOrIndex());
1031 assert(hasSameNumElementsOrSplat(type, values));
1032 size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
1033 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1034}
1036 ArrayRef<std::complex<APInt>> values) {
1037 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1038 assert(llvm::isa<IntegerType>(complex.getElementType()));
1039 assert(hasSameNumElementsOrSplat(type, values));
1040 size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
1041 ArrayRef<APInt> intVals(reinterpret_cast<const APInt *>(values.data()),
1042 values.size() * 2);
1043 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1044}
1045
1046// Constructs a dense float elements attribute from an array of APFloat
1047// values. Each APFloat value is expected to have the same bitwidth as the
1048// element type of 'type'.
1050 ArrayRef<APFloat> values) {
1051 assert(llvm::isa<FloatType>(type.getElementType()));
1052 assert(hasSameNumElementsOrSplat(type, values));
1053 size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
1054 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1055}
1058 ArrayRef<std::complex<APFloat>> values) {
1059 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1060 assert(llvm::isa<FloatType>(complex.getElementType()));
1061 assert(hasSameNumElementsOrSplat(type, values));
1062 ArrayRef<APFloat> apVals(reinterpret_cast<const APFloat *>(values.data()),
1063 values.size() * 2);
1064 size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
1065 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1066}
1067
1068/// Construct a dense elements attribute from a raw buffer representing the
1069/// data for this attribute. Users should generally not use this methods as
1070/// the expected buffer format may not be a form the user expects.
1073 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1074}
1075
1076/// Returns true if the given buffer is a valid raw buffer for the given type.
1078 ArrayRef<char> rawBuffer,
1079 bool &detectedSplat) {
1080 size_t storageWidth = getDenseElementStorageWidth(type.getElementType());
1081 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1082 int64_t numElements = type.getNumElements();
1083
1084 // The initializer is always a splat if the result type has a single element.
1085 detectedSplat = numElements == 1;
1086
1087 // Storage width of 1 is special as it is packed by the bit.
1088 if (storageWidth == 1) {
1089 // Check for a splat, or a buffer equal to the number of elements which
1090 // consists of either all 0's or all 1's.
1091 if (rawBuffer.size() == 1) {
1092 auto rawByte = static_cast<uint8_t>(rawBuffer[0]);
1093 if (rawByte == 0 || rawByte == 0xff) {
1094 detectedSplat = true;
1095 return true;
1096 }
1097 }
1098
1099 // This is a valid non-splat buffer if it has the right size.
1100 return rawBufferWidth == llvm::alignTo<8>(numElements);
1101 }
1102
1103 // All other types are 8-bit aligned, so we can just check the buffer width
1104 // to know if only a single initializer element was passed in.
1105 if (rawBufferWidth == storageWidth) {
1106 detectedSplat = true;
1107 return true;
1108 }
1109
1110 // The raw buffer is valid if it has the right size.
1111 return rawBufferWidth == storageWidth * numElements;
1112}
1113
1114/// Check the information for a C++ data type, check if this type is valid for
1115/// the current attribute. This method is used to verify specific type
1116/// invariants that the templatized 'getValues' method cannot.
1117static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt,
1118 bool isSigned) {
1119 // Make sure that the data element size is the same as the type element width.
1120 auto denseEltBitWidth = getDenseElementBitWidth(type);
1121 auto dataSize = static_cast<size_t>(dataEltSize * CHAR_BIT);
1122 if (denseEltBitWidth != dataSize) {
1123 LDBG() << "expected dense element bit width " << denseEltBitWidth
1124 << " to match data size " << dataSize << " for type " << type;
1125 return false;
1126 }
1127
1128 // Check that the element type is either float or integer or index.
1129 if (!isInt) {
1130 bool valid = llvm::isa<FloatType>(type);
1131 if (!valid)
1132 LDBG() << "expected float type when isInt is false, but found " << type;
1133 return valid;
1134 }
1135 if (type.isIndex())
1136 return true;
1137
1138 auto intType = llvm::dyn_cast<IntegerType>(type);
1139 if (!intType) {
1140 LDBG() << "expected integer type when isInt is true, but found " << type;
1141 return false;
1142 }
1143
1144 // Make sure signedness semantics is consistent.
1145 if (intType.isSignless())
1146 return true;
1147
1148 bool valid = intType.isSigned() == isSigned;
1149 if (!valid)
1150 LDBG() << "expected signedness " << isSigned << " to match type " << type;
1151 return valid;
1152}
1153
1154/// Defaults down the subclass implementation.
1156 ArrayRef<char> data,
1157 int64_t dataEltSize,
1158 bool isInt, bool isSigned) {
1159 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1160 isSigned);
1161}
1163 ArrayRef<char> data,
1164 int64_t dataEltSize,
1165 bool isInt,
1166 bool isSigned) {
1167 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1168 isInt, isSigned);
1169}
1170
1172 bool isSigned) const {
1173 return ::isValidIntOrFloat(getElementType(), dataEltSize, isInt, isSigned);
1174}
1175bool DenseElementsAttr::isValidComplex(int64_t dataEltSize, bool isInt,
1176 bool isSigned) const {
1177 return ::isValidIntOrFloat(
1178 llvm::cast<ComplexType>(getElementType()).getElementType(),
1179 dataEltSize / 2, isInt, isSigned);
1180}
1181
1182/// Returns true if this attribute corresponds to a splat, i.e. if all element
1183/// values are the same.
1185 return static_cast<DenseElementsAttributeStorage *>(impl)->isSplat;
1186}
1187
1188/// Return if the given complex type has an integer element type.
1189static bool isComplexOfIntType(Type type) {
1190 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).getElementType());
1191}
1192
1201
1204 auto eltTy = llvm::dyn_cast<FloatType>(getElementType());
1205 if (!eltTy)
1206 return failure();
1207 const auto &elementSemantics = eltTy.getFloatSemantics();
1209 getType(), FloatElementIterator(elementSemantics, raw_int_begin()),
1210 FloatElementIterator(elementSemantics, raw_int_end()));
1211}
1212
1215 auto complexTy = llvm::dyn_cast<ComplexType>(getElementType());
1216 if (!complexTy)
1217 return failure();
1218 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1219 if (!eltTy)
1220 return failure();
1221 const auto &semantics = eltTy.getFloatSemantics();
1223 getType(), {semantics, {*this, 0}},
1224 {semantics, {*this, static_cast<size_t>(getNumElements())}});
1225}
1226
1227/// Return the raw storage data held by this attribute.
1231
1235
1236/// Return a new DenseElementsAttr that has the same data as the current
1237/// attribute, but has been reshaped to 'newType'. The new type must have the
1238/// same total number of elements as well as element type.
1240 ShapedType curType = getType();
1241 if (curType == newType)
1242 return *this;
1243
1244 assert(newType.getElementType() == curType.getElementType() &&
1245 "expected the same element type");
1246 assert(newType.getNumElements() == curType.getNumElements() &&
1247 "expected the same number of elements");
1248 return DenseIntOrFPElementsAttr::getRaw(newType, getRawData());
1249}
1250
1252 assert(isSplat() && "expected a splat type");
1253
1254 ShapedType curType = getType();
1255 if (curType == newType)
1256 return *this;
1257
1258 assert(newType.getElementType() == curType.getElementType() &&
1259 "expected the same element type");
1260 return DenseIntOrFPElementsAttr::getRaw(newType, getRawData());
1261}
1262
1263/// Return a new DenseElementsAttr that has the same data as the current
1264/// attribute, but has bitcast elements such that it is now 'newType'. The new
1265/// type must have the same shape and element types of the same bitwidth as the
1266/// current type.
1268 ShapedType curType = getType();
1269 Type curElType = curType.getElementType();
1270 if (curElType == newElType)
1271 return *this;
1272
1273 assert(getDenseElementBitWidth(newElType) ==
1274 getDenseElementBitWidth(curElType) &&
1275 "expected element types with the same bitwidth");
1276 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1277 getRawData());
1278}
1279
1282 function_ref<APInt(const APInt &)> mapping) const {
1283 return llvm::cast<DenseIntElementsAttr>(*this).mapValues(newElementType,
1284 mapping);
1285}
1286
1288 Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1289 return llvm::cast<DenseFPElementsAttr>(*this).mapValues(newElementType,
1290 mapping);
1291}
1292
1293ShapedType DenseElementsAttr::getType() const {
1294 return static_cast<const DenseElementsAttributeStorage *>(impl)->type;
1295}
1296
1298 return getType().getElementType();
1299}
1300
1302 return getType().getNumElements();
1303}
1304
1305//===----------------------------------------------------------------------===//
1306// DenseIntOrFPElementsAttr
1307//===----------------------------------------------------------------------===//
1308
1309/// Utility method to write a range of APInt values to a buffer.
1310template <typename APRangeT>
1311static void writeAPIntsToBuffer(size_t storageWidth,
1313 APRangeT &&values) {
1314 size_t numValues = llvm::size(values);
1315 data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1316 size_t offset = 0;
1317 for (auto it = values.begin(), e = values.end(); it != e;
1318 ++it, offset += storageWidth) {
1319 assert((*it).getBitWidth() <= storageWidth);
1320 writeBits(data.data(), offset, *it);
1321 }
1322
1323 // Handle the special encoding of splat of a boolean.
1324 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1325 data[0] = data[0] ? -1 : 0;
1326}
1327
1328/// Constructs a dense elements attribute from an array of raw APFloat values.
1329/// Each APFloat value is expected to have the same bitwidth as the element
1330/// type of 'type'. 'type' must be a vector or tensor with static shape.
1331DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1332 size_t storageWidth,
1333 ArrayRef<APFloat> values) {
1334 SmallVector<char> data;
1335 auto unwrapFloat = [](const APFloat &val) { return val.bitcastToAPInt(); };
1336 writeAPIntsToBuffer(storageWidth, data, llvm::map_range(values, unwrapFloat));
1337 return DenseIntOrFPElementsAttr::getRaw(type, data);
1338}
1339
1340/// Constructs a dense elements attribute from an array of raw APInt values.
1341/// Each APInt value is expected to have the same bitwidth as the element type
1342/// of 'type'.
1343DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1344 size_t storageWidth,
1345 ArrayRef<APInt> values) {
1346 SmallVector<char> data;
1347 writeAPIntsToBuffer(storageWidth, data, values);
1348 return DenseIntOrFPElementsAttr::getRaw(type, data);
1349}
1350
1351DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1352 ArrayRef<char> data) {
1353 assert(type.hasStaticShape() && "type must have static shape");
1354 bool isSplat = false;
1355 bool isValid = isValidRawBuffer(type, data, isSplat);
1356 assert(isValid);
1357 (void)isValid;
1358 return Base::get(type.getContext(), type, data, isSplat);
1359}
1360
1361/// Overload of the raw 'get' method that asserts that the given type is of
1362/// complex type. This method is used to verify type invariants that the
1363/// templatized 'get' method cannot.
1364DenseElementsAttr DenseIntOrFPElementsAttr::getRawComplex(ShapedType type,
1365 ArrayRef<char> data,
1366 int64_t dataEltSize,
1367 bool isInt,
1368 bool isSigned) {
1369 assert(::isValidIntOrFloat(
1370 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1371 dataEltSize / 2, isInt, isSigned) &&
1372 "Try re-running with -debug-only=builtinattributes");
1373
1374 int64_t numElements = data.size() / dataEltSize;
1375 (void)numElements;
1376 assert(numElements == 1 || numElements == type.getNumElements());
1377 return getRaw(type, data);
1378}
1379
1380/// Overload of the 'getRaw' method that asserts that the given type is of
1381/// integer type. This method is used to verify type invariants that the
1382/// templatized 'get' method cannot.
1383DenseElementsAttr
1384DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
1385 int64_t dataEltSize, bool isInt,
1386 bool isSigned) {
1387 assert(::isValidIntOrFloat(type.getElementType(), dataEltSize, isInt,
1388 isSigned) &&
1389 "Try re-running with -debug-only=builtinattributes");
1390
1391 int64_t numElements = data.size() / dataEltSize;
1392 assert(numElements == 1 || numElements == type.getNumElements());
1393 (void)numElements;
1394 return getRaw(type, data);
1395}
1396
1397void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1398 const char *inRawData, char *outRawData, size_t elementBitWidth,
1399 size_t numElements) {
1400 using llvm::support::ulittle16_t;
1401 using llvm::support::ulittle32_t;
1402 using llvm::support::ulittle64_t;
1403
1404 assert(llvm::endianness::native == llvm::endianness::big);
1405 // NOLINT to avoid warning message about replacing by static_assert()
1406
1407 // Following std::copy_n always converts endianness on BE machine.
1408 switch (elementBitWidth) {
1409 case 16: {
1410 const ulittle16_t *inRawDataPos =
1411 reinterpret_cast<const ulittle16_t *>(inRawData);
1412 uint16_t *outDataPos = reinterpret_cast<uint16_t *>(outRawData);
1413 std::copy_n(inRawDataPos, numElements, outDataPos);
1414 break;
1415 }
1416 case 32: {
1417 const ulittle32_t *inRawDataPos =
1418 reinterpret_cast<const ulittle32_t *>(inRawData);
1419 uint32_t *outDataPos = reinterpret_cast<uint32_t *>(outRawData);
1420 std::copy_n(inRawDataPos, numElements, outDataPos);
1421 break;
1422 }
1423 case 64: {
1424 const ulittle64_t *inRawDataPos =
1425 reinterpret_cast<const ulittle64_t *>(inRawData);
1426 uint64_t *outDataPos = reinterpret_cast<uint64_t *>(outRawData);
1427 std::copy_n(inRawDataPos, numElements, outDataPos);
1428 break;
1429 }
1430 default: {
1431 size_t nBytes = elementBitWidth / CHAR_BIT;
1432 for (size_t i = 0; i < nBytes; i++)
1433 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1434 break;
1435 }
1436 }
1437}
1438
1439void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1440 ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1441 ShapedType type) {
1442 size_t numElements = type.getNumElements();
1443 Type elementType = type.getElementType();
1444 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1445 elementType = complexTy.getElementType();
1446 numElements = numElements * 2;
1447 }
1448 size_t elementBitWidth = getDenseElementStorageWidth(elementType);
1449 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1450 inRawData.size() <= outRawData.size());
1451 if (elementBitWidth <= CHAR_BIT)
1452 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1453 else
1454 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1455 elementBitWidth, numElements);
1456}
1457
1458//===----------------------------------------------------------------------===//
1459// DenseFPElementsAttr
1460//===----------------------------------------------------------------------===//
1461
1462template <typename Fn, typename Attr>
1463static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType,
1464 Type newElementType,
1466 size_t bitWidth = getDenseElementBitWidth(newElementType);
1467 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
1468
1469 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1470
1471 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1472 data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1473
1474 // Functor used to process a single element value of the attribute.
1475 auto processElt = [&](decltype(*attr.begin()) value, size_t index) {
1476 auto newInt = mapping(value);
1477 assert(newInt.getBitWidth() == bitWidth);
1478 writeBits(data.data(), index * storageBitWidth, newInt);
1479 };
1480
1481 // Check for the splat case.
1482 if (attr.isSplat()) {
1483 if (bitWidth == 1) {
1484 // Handle the special encoding of splat of bool.
1485 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1486 } else {
1487 processElt(*attr.begin(), /*index=*/0);
1488 }
1489 return newArrayType;
1490 }
1491
1492 // Otherwise, process all of the element values.
1493 uint64_t elementIdx = 0;
1494 for (auto value : attr)
1495 processElt(value, elementIdx++);
1496 return newArrayType;
1497}
1498
1500 Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1501 llvm::SmallVector<char, 8> elementData;
1502 auto newArrayType =
1503 mappingHelper(mapping, *this, getType(), newElementType, elementData);
1504
1505 return getRaw(newArrayType, elementData);
1506}
1507
1508/// Method for supporting type inquiry through isa, cast and dyn_cast.
1510 if (auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1511 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1512 return false;
1513}
1514
1515//===----------------------------------------------------------------------===//
1516// DenseIntElementsAttr
1517//===----------------------------------------------------------------------===//
1518
1520 Type newElementType, function_ref<APInt(const APInt &)> mapping) const {
1521 llvm::SmallVector<char, 8> elementData;
1522 auto newArrayType =
1523 mappingHelper(mapping, *this, getType(), newElementType, elementData);
1524 return getRaw(newArrayType, elementData);
1525}
1526
1527/// Method for supporting type inquiry through isa, cast and dyn_cast.
1529 if (auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1530 return denseAttr.getType().getElementType().isIntOrIndex();
1531 return false;
1532}
1533
1534//===----------------------------------------------------------------------===//
1535// DenseResourceElementsAttr
1536//===----------------------------------------------------------------------===//
1537
1538DenseResourceElementsAttr
1539DenseResourceElementsAttr::get(ShapedType type,
1541 return Base::get(type.getContext(), type, handle);
1542}
1543
1544DenseResourceElementsAttr DenseResourceElementsAttr::get(ShapedType type,
1545 StringRef blobName,
1546 AsmResourceBlob blob) {
1547 // Extract the builtin dialect resource manager from context and construct a
1548 // handle by inserting a new resource using the provided blob.
1549 auto &manager =
1551 return get(type, manager.insert(blobName, std::move(blob)));
1552}
1553
1554ArrayRef<char> DenseResourceElementsAttr::getData() {
1555 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1556 return blob->getDataAs<char>();
1557 return {};
1558}
1559
1560//===----------------------------------------------------------------------===//
1561// DenseResourceElementsAttrBase
1562//===----------------------------------------------------------------------===//
1563
1564namespace {
1565/// Instantiations of this class provide utilities for interacting with native
1566/// data types in the context of DenseResourceElementsAttr.
1567template <typename T>
1568struct DenseResourceAttrUtil;
1569template <size_t width, bool isSigned>
1570struct DenseResourceElementsAttrIntUtil {
1571 static bool checkElementType(Type eltType) {
1572 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1573 if (!type || type.getWidth() != width)
1574 return false;
1575 return isSigned ? !type.isUnsigned() : !type.isSigned();
1576 }
1577};
1578template <>
1579struct DenseResourceAttrUtil<bool> {
1580 static bool checkElementType(Type eltType) {
1581 return eltType.isSignlessInteger(1);
1582 }
1583};
1584template <>
1585struct DenseResourceAttrUtil<int8_t>
1586 : public DenseResourceElementsAttrIntUtil<8, true> {};
1587template <>
1588struct DenseResourceAttrUtil<uint8_t>
1589 : public DenseResourceElementsAttrIntUtil<8, false> {};
1590template <>
1591struct DenseResourceAttrUtil<int16_t>
1592 : public DenseResourceElementsAttrIntUtil<16, true> {};
1593template <>
1594struct DenseResourceAttrUtil<uint16_t>
1595 : public DenseResourceElementsAttrIntUtil<16, false> {};
1596template <>
1597struct DenseResourceAttrUtil<int32_t>
1598 : public DenseResourceElementsAttrIntUtil<32, true> {};
1599template <>
1600struct DenseResourceAttrUtil<uint32_t>
1601 : public DenseResourceElementsAttrIntUtil<32, false> {};
1602template <>
1603struct DenseResourceAttrUtil<int64_t>
1604 : public DenseResourceElementsAttrIntUtil<64, true> {};
1605template <>
1606struct DenseResourceAttrUtil<uint64_t>
1607 : public DenseResourceElementsAttrIntUtil<64, false> {};
1608template <>
1609struct DenseResourceAttrUtil<float> {
1610 static bool checkElementType(Type eltType) { return eltType.isF32(); }
1611};
1612template <>
1613struct DenseResourceAttrUtil<double> {
1614 static bool checkElementType(Type eltType) { return eltType.isF64(); }
1615};
1616} // namespace
1617
1618template <typename T>
1619DenseResourceElementsAttrBase<T>
1620DenseResourceElementsAttrBase<T>::get(ShapedType type, StringRef blobName,
1621 AsmResourceBlob blob) {
1622 // Check that the blob is in the form we were expecting.
1623 assert(blob.getDataAlignment() == alignof(T) &&
1624 "alignment mismatch between expected alignment and blob alignment");
1625 assert(((blob.getData().size() % sizeof(T)) == 0) &&
1626 "size mismatch between expected element width and blob size");
1627 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1628 "invalid shape element type for provided type `T`");
1629 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1630 DenseResourceElementsAttr::get(type, blobName, std::move(blob)));
1631}
1632
1633template <typename T>
1634std::optional<ArrayRef<T>>
1636 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1637 return blob->template getDataAs<T>();
1638 return std::nullopt;
1639}
1640
1641template <typename T>
1643 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1644 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1645 resourceAttr.getElementType());
1646}
1647
1648namespace mlir {
1649namespace detail {
1650// Explicit instantiation for all the supported DenseResourceElementsAttr.
1662} // namespace detail
1663} // namespace mlir
1664
1665//===----------------------------------------------------------------------===//
1666// SparseElementsAttr
1667//===----------------------------------------------------------------------===//
1668
1669/// Get a zero APFloat for the given sparse attribute.
1670APFloat SparseElementsAttr::getZeroAPFloat() const {
1671 auto eltType = llvm::cast<FloatType>(getElementType());
1672 return APFloat(eltType.getFloatSemantics());
1673}
1674
1675/// Get a zero APInt for the given sparse attribute.
1676APInt SparseElementsAttr::getZeroAPInt() const {
1677 auto eltType = llvm::cast<IntegerType>(getElementType());
1678 return APInt::getZero(eltType.getWidth());
1679}
1680
1681/// Get a zero attribute for the given attribute type.
1682Attribute SparseElementsAttr::getZeroAttr() const {
1683 auto eltType = getElementType();
1684
1685 // Handle floating point elements.
1686 if (llvm::isa<FloatType>(eltType))
1687 return FloatAttr::get(eltType, 0);
1688
1689 // Handle complex elements.
1690 if (auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1691 auto eltType = complexTy.getElementType();
1692 Attribute zero;
1693 if (llvm::isa<FloatType>(eltType))
1694 zero = FloatAttr::get(eltType, 0);
1695 else // must be integer
1696 zero = IntegerAttr::get(eltType, 0);
1697 return ArrayAttr::get(complexTy.getContext(),
1698 ArrayRef<Attribute>{zero, zero});
1699 }
1700
1701 // Handle string type.
1702 if (llvm::isa<DenseStringElementsAttr>(getValues()))
1703 return StringAttr::get("", eltType);
1704
1705 // Otherwise, this is an integer.
1706 return IntegerAttr::get(eltType, 0);
1707}
1708
1709/// Flatten, and return, all of the sparse indices in this attribute in
1710/// row-major order.
1711SmallVector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices() const {
1712 SmallVector<ptrdiff_t> flatSparseIndices;
1713
1714 // The sparse indices are 64-bit integers, so we can reinterpret the raw data
1715 // as a 1-D index array.
1716 auto sparseIndices = getIndices();
1717 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1718 if (sparseIndices.isSplat()) {
1719 SmallVector<uint64_t, 8> indices(getType().getRank(),
1720 *sparseIndexValues.begin());
1721 flatSparseIndices.push_back(getFlattenedIndex(indices));
1722 return flatSparseIndices;
1723 }
1724
1725 // Otherwise, reinterpret each index as an ArrayRef when flattening.
1726 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1727 size_t rank = getType().getRank();
1728 for (size_t i = 0, e = numSparseIndices; i != e; ++i)
1729 flatSparseIndices.push_back(getFlattenedIndex(
1730 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1731 return flatSparseIndices;
1732}
1733
1734LogicalResult
1735SparseElementsAttr::verify(function_ref<InFlightDiagnostic()> emitError,
1736 ShapedType type, DenseIntElementsAttr sparseIndices,
1737 DenseElementsAttr values) {
1738 ShapedType valuesType = values.getType();
1739 if (valuesType.getRank() != 1)
1740 return emitError() << "expected 1-d tensor for sparse element values";
1741
1742 // Verify the indices and values shape.
1743 ShapedType indicesType = sparseIndices.getType();
1744 auto emitShapeError = [&]() {
1745 return emitError() << "expected shape ([" << type.getShape()
1746 << "]); inferred shape of indices literal (["
1747 << indicesType.getShape()
1748 << "]); inferred shape of values literal (["
1749 << valuesType.getShape() << "])";
1750 };
1751 // Verify indices shape.
1752 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1753 if (indicesRank == 2) {
1754 if (indicesType.getDimSize(1) != static_cast<int64_t>(rank))
1755 return emitShapeError();
1756 } else if (indicesRank != 1 || rank != 1) {
1757 return emitShapeError();
1758 }
1759 // Verify the values shape.
1760 int64_t numSparseIndices = indicesType.getDimSize(0);
1761 if (numSparseIndices != valuesType.getDimSize(0))
1762 return emitShapeError();
1763
1764 // Verify that the sparse indices are within the value shape.
1765 auto emitIndexError = [&](unsigned indexNum, ArrayRef<uint64_t> index) {
1766 return emitError()
1767 << "sparse index #" << indexNum
1768 << " is not contained within the value shape, with index=[" << index
1769 << "], and type=" << type;
1770 };
1771
1772 // Handle the case where the index values are a splat.
1773 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1774 if (sparseIndices.isSplat()) {
1775 SmallVector<uint64_t> indices(rank, *sparseIndexValues.begin());
1776 if (!ElementsAttr::isValidIndex(type, indices))
1777 return emitIndexError(0, indices);
1778 return success();
1779 }
1780
1781 // Otherwise, reinterpret each index as an ArrayRef.
1782 for (size_t i = 0, e = numSparseIndices; i != e; ++i) {
1783 ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1784 rank);
1785 if (!ElementsAttr::isValidIndex(type, index))
1786 return emitIndexError(i, index);
1787 }
1788
1789 return success();
1790}
1791
1792//===----------------------------------------------------------------------===//
1793// DistinctAttr
1794//===----------------------------------------------------------------------===//
1795
1797 return Base::get(referencedAttr.getContext(), referencedAttr);
1798}
1799
1801 return getImpl()->referencedAttr;
1802}
1803
1804//===----------------------------------------------------------------------===//
1805// Attribute Utilities
1806//===----------------------------------------------------------------------===//
1807
1809 int64_t offset,
1810 MLIRContext *context) {
1811 AffineExpr expr;
1812 unsigned nSymbols = 0;
1813
1814 // AffineExpr for offset.
1815 // Static case.
1816 if (ShapedType::isStatic(offset)) {
1817 auto cst = getAffineConstantExpr(offset, context);
1818 expr = cst;
1819 } else {
1820 // Dynamic case, new symbol for the offset.
1821 auto sym = getAffineSymbolExpr(nSymbols++, context);
1822 expr = sym;
1823 }
1824
1825 // AffineExpr for strides.
1826 for (const auto &en : llvm::enumerate(strides)) {
1827 auto dim = en.index();
1828 auto stride = en.value();
1829 auto d = getAffineDimExpr(dim, context);
1830 AffineExpr mult;
1831 // Static case.
1832 if (ShapedType::isStatic(stride))
1833 mult = getAffineConstantExpr(stride, context);
1834 else
1835 // Dynamic case, new symbol for each new stride.
1836 mult = getAffineSymbolExpr(nSymbols++, context);
1837 expr = expr + d * mult;
1838 }
1839
1840 return AffineMap::get(strides.size(), nSymbols, expr);
1841}
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 void setBit(char *rawData, size_t bitPos, bool value)
Set a bit to a specific value.
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 getBit(const char *rawData, size_t bitPos)
Return the value of the specified bit.
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.
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
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer, bool &detectedSplat)
Returns true if the given buffer is a valid raw buffer for the given type.
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:64
bool isIndex() const
Definition Types.cpp:54
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
Definition Types.cpp:120
bool isF32() const
Definition Types.cpp:40
bool isInteger() const
Return true if this is an integer type (with the specified width).
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:122
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:304
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:152
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.
static const char kSplatTrue
The values used to denote a boolean splat value.
An attribute representing a reference to a dense vector or tensor object containing strings.