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