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