MLIR  21.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"
12 #include "mlir/IR/BuiltinDialect.h"
13 #include "mlir/IR/Dialect.h"
15 #include "mlir/IR/IntegerSet.h"
17 #include "mlir/IR/Operation.h"
18 #include "mlir/IR/SymbolTable.h"
19 #include "mlir/IR/Types.h"
20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/ADT/Sequence.h"
22 #include "llvm/ADT/TypeSwitch.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/Endian.h"
25 #include <optional>
26 
27 #define DEBUG_TYPE "builtinattributes"
28 
29 using namespace mlir;
30 using 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 
43 void 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.
59 template <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.
101 static 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(),
111  [](NamedAttribute l, NamedAttribute r) {
112  return l.getName() == r.getName();
113  });
114  return it != value.end() ? *it : none;
115 }
116 
117 bool 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 
125 bool 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 
132 std::optional<NamedAttribute>
133 DictionaryAttr::findDuplicate(SmallVectorImpl<NamedAttribute> &array,
134  bool isSorted) {
135  if (!isSorted)
136  dictionaryAttrSort</*inPlace=*/true>(array, array);
137  return findDuplicateElement(array);
138 }
139 
140 DictionaryAttr DictionaryAttr::get(MLIRContext *context,
141  ArrayRef<NamedAttribute> value) {
142  if (value.empty())
143  return DictionaryAttr::getEmpty(context);
144 
145  // We need to sort the element list to canonicalize it.
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.
155 DictionaryAttr DictionaryAttr::getWithSorted(MLIRContext *context,
156  ArrayRef<NamedAttribute> value) {
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.
169 Attribute DictionaryAttr::get(StringRef name) const {
170  auto it = impl::findAttrSorted(begin(), end(), name);
171  return it.second ? it.first->getValue() : Attribute();
172 }
173 Attribute 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.
179 std::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 }
183 std::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.
189 bool DictionaryAttr::contains(StringRef name) const {
190  return impl::findAttrSorted(begin(), end(), name).second;
191 }
192 bool DictionaryAttr::contains(StringAttr name) const {
193  return impl::findAttrSorted(begin(), end(), name).second;
194 }
195 
196 DictionaryAttr::iterator DictionaryAttr::begin() const {
197  return getValue().begin();
198 }
199 DictionaryAttr::iterator DictionaryAttr::end() const {
200  return getValue().end();
201 }
202 size_t DictionaryAttr::size() const { return getValue().size(); }
203 
204 DictionaryAttr DictionaryAttr::getEmptyUnchecked(MLIRContext *context) {
205  return Base::get(context, ArrayRef<NamedAttribute>());
206 }
207 
208 //===----------------------------------------------------------------------===//
209 // StridedLayoutAttr
210 //===----------------------------------------------------------------------===//
211 
212 /// Prints a strided layout attribute.
213 void 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.
234 bool StridedLayoutAttr::hasStaticLayout() const {
235  return !ShapedType::isDynamic(getOffset()) &&
236  !ShapedType::isDynamicShape(getStrides());
237 }
238 
239 /// Returns the strided layout as an affine map.
240 AffineMap StridedLayoutAttr::getAffineMap() const {
241  return makeStridedLinearLayoutMap(getStrides(), getOffset(), getContext());
242 }
243 
244 /// Checks that the type-agnostic strided layout invariants are satisfied.
245 LogicalResult
247  int64_t offset, ArrayRef<int64_t> strides) {
248  return success();
249 }
250 
251 /// Checks that the type-specific strided layout invariants are satisfied.
252 LogicalResult StridedLayoutAttr::verifyLayout(
253  ArrayRef<int64_t> shape,
255  if (shape.size() != getStrides().size())
256  return emitError() << "expected the number of strides to match the rank";
257 
258  return success();
259 }
260 
261 //===----------------------------------------------------------------------===//
262 // StringAttr
263 //===----------------------------------------------------------------------===//
264 
265 StringAttr StringAttr::getEmptyStringAttrUnchecked(MLIRContext *context) {
266  return Base::get(context, "", NoneType::get(context));
267 }
268 
269 /// Twine support for StringAttr.
270 StringAttr StringAttr::get(MLIRContext *context, const Twine &twine) {
271  // Fast-path empty twine.
272  if (twine.isTriviallyEmpty())
273  return get(context);
274  SmallVector<char, 32> tempStr;
275  return Base::get(context, twine.toStringRef(tempStr), NoneType::get(context));
276 }
277 
278 /// Twine support for StringAttr.
279 StringAttr StringAttr::get(const Twine &twine, Type type) {
280  SmallVector<char, 32> tempStr;
281  return Base::get(type.getContext(), twine.toStringRef(tempStr), type);
282 }
283 
284 StringRef StringAttr::getValue() const { return getImpl()->value; }
285 
286 Type StringAttr::getType() const { return getImpl()->type; }
287 
288 Dialect *StringAttr::getReferencedDialect() const {
289  return getImpl()->referencedDialect;
290 }
291 
292 //===----------------------------------------------------------------------===//
293 // FloatAttr
294 //===----------------------------------------------------------------------===//
295 
296 double FloatAttr::getValueAsDouble() const {
297  return getValueAsDouble(getValue());
298 }
299 double FloatAttr::getValueAsDouble(APFloat value) {
300  if (&value.getSemantics() != &APFloat::IEEEdouble()) {
301  bool losesInfo = false;
302  value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
303  &losesInfo);
304  }
305  return value.convertToDouble();
306 }
307 
309  Type type, APFloat value) {
310  // Verify that the type is correct.
311  if (!llvm::isa<FloatType>(type))
312  return emitError() << "expected floating point type";
313 
314  // Verify that the type semantics match that of the value.
315  if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
316  &value.getSemantics()) {
317  return emitError()
318  << "FloatAttr type doesn't match the type implied by its value";
319  }
320  return success();
321 }
322 
323 //===----------------------------------------------------------------------===//
324 // SymbolRefAttr
325 //===----------------------------------------------------------------------===//
326 
327 SymbolRefAttr SymbolRefAttr::get(MLIRContext *ctx, StringRef value,
328  ArrayRef<FlatSymbolRefAttr> nestedRefs) {
329  return get(StringAttr::get(ctx, value), nestedRefs);
330 }
331 
332 FlatSymbolRefAttr SymbolRefAttr::get(MLIRContext *ctx, StringRef value) {
333  return llvm::cast<FlatSymbolRefAttr>(get(ctx, value, {}));
334 }
335 
336 FlatSymbolRefAttr SymbolRefAttr::get(StringAttr value) {
337  return llvm::cast<FlatSymbolRefAttr>(get(value, {}));
338 }
339 
341  auto symName =
342  symbol->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
343  assert(symName && "value does not have a valid symbol name");
344  return SymbolRefAttr::get(symName);
345 }
346 
347 StringAttr SymbolRefAttr::getLeafReference() const {
348  ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences();
349  return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
350 }
351 
352 //===----------------------------------------------------------------------===//
353 // IntegerAttr
354 //===----------------------------------------------------------------------===//
355 
356 int64_t IntegerAttr::getInt() const {
357  assert((getType().isIndex() || getType().isSignlessInteger()) &&
358  "must be signless integer");
359  return getValue().getSExtValue();
360 }
361 
362 int64_t IntegerAttr::getSInt() const {
363  assert(getType().isSignedInteger() && "must be signed integer");
364  return getValue().getSExtValue();
365 }
366 
367 uint64_t IntegerAttr::getUInt() const {
368  assert(getType().isUnsignedInteger() && "must be unsigned integer");
369  return getValue().getZExtValue();
370 }
371 
372 /// Return the value as an APSInt which carries the signed from the type of
373 /// the attribute. This traps on signless integers types!
374 APSInt IntegerAttr::getAPSInt() const {
375  assert(!getType().isSignlessInteger() &&
376  "Signless integers don't carry a sign for APSInt");
377  return APSInt(getValue(), getType().isUnsignedInteger());
378 }
379 
381  Type type, APInt value) {
382  if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
383  if (integerType.getWidth() != value.getBitWidth())
384  return emitError() << "integer type bit width (" << integerType.getWidth()
385  << ") doesn't match value bit width ("
386  << value.getBitWidth() << ")";
387  return success();
388  }
389  if (llvm::isa<IndexType>(type)) {
390  if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
391  return emitError()
392  << "value bit width (" << value.getBitWidth()
393  << ") doesn't match index type internal storage bit width ("
394  << IndexType::kInternalStorageBitWidth << ")";
395  return success();
396  }
397  return emitError() << "expected integer or index type";
398 }
399 
400 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type, bool value) {
401  auto attr = Base::get(type.getContext(), type, APInt(/*numBits=*/1, value));
402  return llvm::cast<BoolAttr>(attr);
403 }
404 
405 //===----------------------------------------------------------------------===//
406 // BoolAttr
407 //===----------------------------------------------------------------------===//
408 
409 bool BoolAttr::getValue() const {
410  auto *storage = reinterpret_cast<IntegerAttrStorage *>(impl);
411  return storage->value.getBoolValue();
412 }
413 
415  IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
416  return intAttr && intAttr.getType().isSignlessInteger(1);
417 }
418 
419 //===----------------------------------------------------------------------===//
420 // OpaqueAttr
421 //===----------------------------------------------------------------------===//
422 
424  StringAttr dialect, StringRef attrData,
425  Type type) {
426  if (!Dialect::isValidNamespace(dialect.strref()))
427  return emitError() << "invalid dialect namespace '" << dialect << "'";
428 
429  // Check that the dialect is actually registered.
430  MLIRContext *context = dialect.getContext();
431  if (!context->allowsUnregisteredDialects() &&
432  !context->getLoadedDialect(dialect.strref())) {
433  return emitError()
434  << "#" << dialect << "<\"" << attrData << "\"> : " << type
435  << " attribute created with unregistered dialect. If this is "
436  "intended, please call allowUnregisteredDialects() on the "
437  "MLIRContext, or use -allow-unregistered-dialect with "
438  "the MLIR opt tool used";
439  }
440 
441  return success();
442 }
443 
444 //===----------------------------------------------------------------------===//
445 // DenseElementsAttr Utilities
446 //===----------------------------------------------------------------------===//
447 
450 
451 /// Get the bitwidth of a dense element type within the buffer.
452 /// DenseElementsAttr requires bitwidths greater than 1 to be aligned by 8.
453 static size_t getDenseElementStorageWidth(size_t origWidth) {
454  return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
455 }
456 static size_t getDenseElementStorageWidth(Type elementType) {
458 }
459 
460 /// Set a bit to a specific value.
461 static void setBit(char *rawData, size_t bitPos, bool value) {
462  if (value)
463  rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
464  else
465  rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
466 }
467 
468 /// Return the value of the specified bit.
469 static bool getBit(const char *rawData, size_t bitPos) {
470  return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
471 }
472 
473 /// Copy actual `numBytes` data from `value` (APInt) to char array(`result`) for
474 /// BE format.
475 static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes,
476  char *result) {
477  assert(llvm::endianness::native == llvm::endianness::big);
478  assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
479 
480  // Copy the words filled with data.
481  // For example, when `value` has 2 words, the first word is filled with data.
482  // `value` (10 bytes, BE):|abcdefgh|------ij| ==> `result` (BE):|abcdefgh|--|
483  size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
484  std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
485  numFilledWords, result);
486  // Convert last word of APInt to LE format and store it in char
487  // array(`valueLE`).
488  // ex. last word of `value` (BE): |------ij| ==> `valueLE` (LE): |ji------|
489  size_t lastWordPos = numFilledWords;
490  SmallVector<char, 8> valueLE(APInt::APINT_WORD_SIZE);
491  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
492  reinterpret_cast<const char *>(value.getRawData()) + lastWordPos,
493  valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
494  // Extract actual APInt data from `valueLE`, convert endianness to BE format,
495  // and store it in `result`.
496  // ex. `valueLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|ij|
497  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
498  valueLE.begin(), result + lastWordPos,
499  (numBytes - lastWordPos) * CHAR_BIT, 1);
500 }
501 
502 /// Copy `numBytes` data from `inArray`(char array) to `result`(APINT) for BE
503 /// format.
504 static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes,
505  APInt &result) {
506  assert(llvm::endianness::native == llvm::endianness::big);
507  assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
508 
509  // Copy the data that fills the word of `result` from `inArray`.
510  // For example, when `result` has 2 words, the first word will be filled with
511  // data. So, the first 8 bytes are copied from `inArray` here.
512  // `inArray` (10 bytes, BE): |abcdefgh|ij|
513  // ==> `result` (2 words, BE): |abcdefgh|--------|
514  size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
515  std::copy_n(
516  inArray, numFilledWords,
517  const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())));
518 
519  // Convert array data which will be last word of `result` to LE format, and
520  // store it in char array(`inArrayLE`).
521  // ex. `inArray` (last two bytes, BE): |ij| ==> `inArrayLE` (LE): |ji------|
522  size_t lastWordPos = numFilledWords;
523  SmallVector<char, 8> inArrayLE(APInt::APINT_WORD_SIZE);
524  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
525  inArray + lastWordPos, inArrayLE.begin(),
526  (numBytes - lastWordPos) * CHAR_BIT, 1);
527 
528  // Convert `inArrayLE` to BE format, and store it in last word of `result`.
529  // ex. `inArrayLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|------ij|
530  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
531  inArrayLE.begin(),
532  const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())) +
533  lastWordPos,
534  APInt::APINT_BITS_PER_WORD, 1);
535 }
536 
537 /// Writes value to the bit position `bitPos` in array `rawData`.
538 static void writeBits(char *rawData, size_t bitPos, APInt value) {
539  size_t bitWidth = value.getBitWidth();
540 
541  // If the bitwidth is 1 we just toggle the specific bit.
542  if (bitWidth == 1)
543  return setBit(rawData, bitPos, value.isOne());
544 
545  // Otherwise, the bit position is guaranteed to be byte aligned.
546  assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
547  if (llvm::endianness::native == llvm::endianness::big) {
548  // Copy from `value` to `rawData + (bitPos / CHAR_BIT)`.
549  // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
550  // work correctly in BE format.
551  // ex. `value` (2 words including 10 bytes)
552  // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------|
553  copyAPIntToArrayForBEmachine(value, llvm::divideCeil(bitWidth, CHAR_BIT),
554  rawData + (bitPos / CHAR_BIT));
555  } else {
556  std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
557  llvm::divideCeil(bitWidth, CHAR_BIT),
558  rawData + (bitPos / CHAR_BIT));
559  }
560 }
561 
562 /// Reads the next `bitWidth` bits from the bit position `bitPos` in array
563 /// `rawData`.
564 static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth) {
565  // Handle a boolean bit position.
566  if (bitWidth == 1)
567  return APInt(1, getBit(rawData, bitPos) ? 1 : 0);
568 
569  // Otherwise, the bit position must be 8-bit aligned.
570  assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
571  APInt result(bitWidth, 0);
572  if (llvm::endianness::native == llvm::endianness::big) {
573  // Copy from `rawData + (bitPos / CHAR_BIT)` to `result`.
574  // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
575  // work correctly in BE format.
576  // ex. `result` (2 words including 10 bytes)
577  // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------| This function
578  copyArrayToAPIntForBEmachine(rawData + (bitPos / CHAR_BIT),
579  llvm::divideCeil(bitWidth, CHAR_BIT), result);
580  } else {
581  std::copy_n(rawData + (bitPos / CHAR_BIT),
582  llvm::divideCeil(bitWidth, CHAR_BIT),
583  const_cast<char *>(
584  reinterpret_cast<const char *>(result.getRawData())));
585  }
586  return result;
587 }
588 
589 /// Returns true if 'values' corresponds to a splat, i.e. one element, or has
590 /// the same element count as 'type'.
591 template <typename Values>
592 static bool hasSameElementsOrSplat(ShapedType type, const Values &values) {
593  return (values.size() == 1) ||
594  (type.getNumElements() == static_cast<int64_t>(values.size()));
595 }
596 
597 //===----------------------------------------------------------------------===//
598 // DenseElementsAttr Iterators
599 //===----------------------------------------------------------------------===//
600 
601 //===----------------------------------------------------------------------===//
602 // AttributeElementIterator
603 //===----------------------------------------------------------------------===//
604 
605 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
606  DenseElementsAttr attr, size_t index)
607  : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
609  attr.getAsOpaquePointer(), index) {}
610 
612  auto owner = llvm::cast<DenseElementsAttr>(getFromOpaquePointer(base));
613  Type eltTy = owner.getElementType();
614  if (llvm::dyn_cast<IntegerType>(eltTy))
615  return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
616  if (llvm::isa<IndexType>(eltTy))
617  return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
618  if (auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
619  IntElementIterator intIt(owner, index);
620  FloatElementIterator floatIt(floatEltTy.getFloatSemantics(), intIt);
621  return FloatAttr::get(eltTy, *floatIt);
622  }
623  if (auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
624  auto complexEltTy = complexTy.getElementType();
625  ComplexIntElementIterator complexIntIt(owner, index);
626  if (llvm::isa<IntegerType>(complexEltTy)) {
627  auto value = *complexIntIt;
628  auto real = IntegerAttr::get(complexEltTy, value.real());
629  auto imag = IntegerAttr::get(complexEltTy, value.imag());
630  return ArrayAttr::get(complexTy.getContext(),
631  ArrayRef<Attribute>{real, imag});
632  }
633 
634  ComplexFloatElementIterator complexFloatIt(
635  llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
636  auto value = *complexFloatIt;
637  auto real = FloatAttr::get(complexEltTy, value.real());
638  auto imag = FloatAttr::get(complexEltTy, value.imag());
639  return ArrayAttr::get(complexTy.getContext(),
640  ArrayRef<Attribute>{real, imag});
641  }
642  if (llvm::isa<DenseStringElementsAttr>(owner)) {
643  ArrayRef<StringRef> vals = owner.getRawStringData();
644  return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
645  }
646  llvm_unreachable("unexpected element type");
647 }
648 
649 //===----------------------------------------------------------------------===//
650 // BoolElementIterator
651 //===----------------------------------------------------------------------===//
652 
653 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
654  DenseElementsAttr attr, size_t dataIndex)
656  attr.getRawData().data(), attr.isSplat(), dataIndex) {}
657 
659  return getBit(getData(), getDataIndex());
660 }
661 
662 //===----------------------------------------------------------------------===//
663 // IntElementIterator
664 //===----------------------------------------------------------------------===//
665 
666 DenseElementsAttr::IntElementIterator::IntElementIterator(
667  DenseElementsAttr attr, size_t dataIndex)
668  : DenseElementIndexedIteratorImpl<IntElementIterator, APInt, APInt, APInt>(
669  attr.getRawData().data(), attr.isSplat(), dataIndex),
670  bitWidth(getDenseElementBitWidth(attr.getElementType())) {}
671 
673  return readBits(getData(),
674  getDataIndex() * getDenseElementStorageWidth(bitWidth),
675  bitWidth);
676 }
677 
678 //===----------------------------------------------------------------------===//
679 // ComplexIntElementIterator
680 //===----------------------------------------------------------------------===//
681 
682 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
683  DenseElementsAttr attr, size_t dataIndex)
685  std::complex<APInt>, std::complex<APInt>,
686  std::complex<APInt>>(
687  attr.getRawData().data(), attr.isSplat(), dataIndex) {
688  auto complexType = llvm::cast<ComplexType>(attr.getElementType());
689  bitWidth = getDenseElementBitWidth(complexType.getElementType());
690 }
691 
692 std::complex<APInt>
694  size_t storageWidth = getDenseElementStorageWidth(bitWidth);
695  size_t offset = getDataIndex() * storageWidth * 2;
696  return {readBits(getData(), offset, bitWidth),
697  readBits(getData(), offset + storageWidth, bitWidth)};
698 }
699 
700 //===----------------------------------------------------------------------===//
701 // DenseArrayAttr
702 //===----------------------------------------------------------------------===//
703 
704 LogicalResult
706  Type elementType, int64_t size, ArrayRef<char> rawData) {
707  if (!elementType.isIntOrIndexOrFloat())
708  return emitError() << "expected integer or floating point element type";
709  int64_t dataSize = rawData.size();
710  int64_t elementSize =
711  llvm::divideCeil(elementType.getIntOrFloatBitWidth(), CHAR_BIT);
712  if (size * elementSize != dataSize) {
713  return emitError() << "expected data size (" << size << " elements, "
714  << elementSize
715  << " bytes each) does not match: " << dataSize
716  << " bytes";
717  }
718  return success();
719 }
720 
721 namespace {
722 /// Instantiations of this class provide utilities for interacting with native
723 /// data types in the context of DenseArrayAttr.
724 template <size_t width,
725  IntegerType::SignednessSemantics signedness = IntegerType::Signless>
726 struct DenseArrayAttrIntUtil {
727  static bool checkElementType(Type eltType) {
728  auto type = llvm::dyn_cast<IntegerType>(eltType);
729  if (!type || type.getWidth() != width)
730  return false;
731  return type.getSignedness() == signedness;
732  }
733 
734  static Type getElementType(MLIRContext *ctx) {
735  return IntegerType::get(ctx, width, signedness);
736  }
737 
738  template <typename T>
739  static void printElement(raw_ostream &os, T value) {
740  os << value;
741  }
742 
743  template <typename T>
744  static ParseResult parseElement(AsmParser &parser, T &value) {
745  return parser.parseInteger(value);
746  }
747 };
748 template <typename T>
749 struct DenseArrayAttrUtil;
750 
751 /// Specialization for boolean elements to print 'true' and 'false' literals for
752 /// elements.
753 template <>
754 struct DenseArrayAttrUtil<bool> : public DenseArrayAttrIntUtil<1> {
755  static void printElement(raw_ostream &os, bool value) {
756  os << (value ? "true" : "false");
757  }
758 };
759 
760 /// Specialization for 8-bit integers to ensure values are printed as integers
761 /// and not characters.
762 template <>
763 struct DenseArrayAttrUtil<int8_t> : public DenseArrayAttrIntUtil<8> {
764  static void printElement(raw_ostream &os, int8_t value) {
765  os << static_cast<int>(value);
766  }
767 };
768 template <>
769 struct DenseArrayAttrUtil<int16_t> : public DenseArrayAttrIntUtil<16> {};
770 template <>
771 struct DenseArrayAttrUtil<int32_t> : public DenseArrayAttrIntUtil<32> {};
772 template <>
773 struct DenseArrayAttrUtil<int64_t> : public DenseArrayAttrIntUtil<64> {};
774 
775 /// Specialization for 32-bit floats.
776 template <>
777 struct DenseArrayAttrUtil<float> {
778  static bool checkElementType(Type eltType) { return eltType.isF32(); }
779  static Type getElementType(MLIRContext *ctx) { return Float32Type::get(ctx); }
780  static void printElement(raw_ostream &os, float value) { os << value; }
781 
782  /// Parse a double and cast it to a float.
783  static ParseResult parseElement(AsmParser &parser, float &value) {
784  double doubleVal;
785  if (parser.parseFloat(doubleVal))
786  return failure();
787  value = doubleVal;
788  return success();
789  }
790 };
791 
792 /// Specialization for 64-bit floats.
793 template <>
794 struct DenseArrayAttrUtil<double> {
795  static bool checkElementType(Type eltType) { return eltType.isF64(); }
796  static Type getElementType(MLIRContext *ctx) { return Float64Type::get(ctx); }
797  static void printElement(raw_ostream &os, float value) { os << value; }
798  static ParseResult parseElement(AsmParser &parser, double &value) {
799  return parser.parseFloat(value);
800  }
801 };
802 } // namespace
803 
804 template <typename T>
806  print(printer.getStream());
807 }
808 
809 template <typename T>
810 void DenseArrayAttrImpl<T>::printWithoutBraces(raw_ostream &os) const {
811  llvm::interleaveComma(asArrayRef(), os, [&](T value) {
812  DenseArrayAttrUtil<T>::printElement(os, value);
813  });
814 }
815 
816 template <typename T>
817 void DenseArrayAttrImpl<T>::print(raw_ostream &os) const {
818  os << "[";
819  printWithoutBraces(os);
820  os << "]";
821 }
822 
823 /// Parse a DenseArrayAttr without the braces: `1, 2, 3`
824 template <typename T>
826  Type odsType) {
827  SmallVector<T> data;
828  if (failed(parser.parseCommaSeparatedList([&]() {
829  T value;
830  if (DenseArrayAttrUtil<T>::parseElement(parser, value))
831  return failure();
832  data.push_back(value);
833  return success();
834  })))
835  return {};
836  return get(parser.getContext(), data);
837 }
838 
839 /// Parse a DenseArrayAttr: `[ 1, 2, 3 ]`
840 template <typename T>
842  if (parser.parseLSquare())
843  return {};
844  // Handle empty list case.
845  if (succeeded(parser.parseOptionalRSquare()))
846  return get(parser.getContext(), {});
847  Attribute result = parseWithoutBraces(parser, odsType);
848  if (parser.parseRSquare())
849  return {};
850  return result;
851 }
852 
853 /// Conversion from DenseArrayAttr<T> to ArrayRef<T>.
854 template <typename T>
856  ArrayRef<char> raw = getRawData();
857  assert((raw.size() % sizeof(T)) == 0);
858  return ArrayRef<T>(reinterpret_cast<const T *>(raw.data()),
859  raw.size() / sizeof(T));
860 }
861 
862 /// Builds a DenseArrayAttr<T> from an ArrayRef<T>.
863 template <typename T>
865  ArrayRef<T> content) {
866  Type elementType = DenseArrayAttrUtil<T>::getElementType(context);
867  auto rawArray = ArrayRef<char>(reinterpret_cast<const char *>(content.data()),
868  content.size() * sizeof(T));
869  return llvm::cast<DenseArrayAttrImpl<T>>(
870  Base::get(context, elementType, content.size(), rawArray));
871 }
872 
873 template <typename T>
875  if (auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
876  return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
877  return false;
878 }
879 
880 namespace mlir {
881 namespace detail {
882 // Explicit instantiation for all the supported DenseArrayAttr.
883 template class DenseArrayAttrImpl<bool>;
884 template class DenseArrayAttrImpl<int8_t>;
885 template class DenseArrayAttrImpl<int16_t>;
886 template class DenseArrayAttrImpl<int32_t>;
887 template class DenseArrayAttrImpl<int64_t>;
888 template class DenseArrayAttrImpl<float>;
889 template class DenseArrayAttrImpl<double>;
890 } // namespace detail
891 } // namespace mlir
892 
893 //===----------------------------------------------------------------------===//
894 // DenseElementsAttr
895 //===----------------------------------------------------------------------===//
896 
897 /// Method for support type inquiry through isa, cast and dyn_cast.
899  return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
900 }
901 
903  ArrayRef<Attribute> values) {
904  assert(hasSameElementsOrSplat(type, values));
905 
906  Type eltType = type.getElementType();
907 
908  // Take care complex type case first.
909  if (auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
910  if (complexType.getElementType().isIntOrIndex()) {
911  SmallVector<std::complex<APInt>> complexValues;
912  complexValues.reserve(values.size());
913  for (Attribute attr : values) {
914  assert(llvm::isa<ArrayAttr>(attr) && "expected ArrayAttr for complex");
915  auto arrayAttr = llvm::cast<ArrayAttr>(attr);
916  assert(arrayAttr.size() == 2 && "expected 2 element for complex");
917  auto attr0 = arrayAttr[0];
918  auto attr1 = arrayAttr[1];
919  complexValues.push_back(
920  std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
921  llvm::cast<IntegerAttr>(attr1).getValue()));
922  }
923  return DenseElementsAttr::get(type, complexValues);
924  }
925  // Must be float.
926  SmallVector<std::complex<APFloat>> complexValues;
927  complexValues.reserve(values.size());
928  for (Attribute attr : values) {
929  assert(llvm::isa<ArrayAttr>(attr) && "expected ArrayAttr for complex");
930  auto arrayAttr = llvm::cast<ArrayAttr>(attr);
931  assert(arrayAttr.size() == 2 && "expected 2 element for complex");
932  auto attr0 = arrayAttr[0];
933  auto attr1 = arrayAttr[1];
934  complexValues.push_back(
935  std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
936  llvm::cast<FloatAttr>(attr1).getValue()));
937  }
938  return DenseElementsAttr::get(type, complexValues);
939  }
940 
941  // If the element type is not based on int/float/index, assume it is a string
942  // type.
943  if (!eltType.isIntOrIndexOrFloat()) {
944  SmallVector<StringRef, 8> stringValues;
945  stringValues.reserve(values.size());
946  for (Attribute attr : values) {
947  assert(llvm::isa<StringAttr>(attr) &&
948  "expected string value for non integer/index/float element");
949  stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
950  }
951  return get(type, stringValues);
952  }
953 
954  // Otherwise, get the raw storage width to use for the allocation.
955  size_t bitWidth = getDenseElementBitWidth(eltType);
956  size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
957 
958  // Compress the attribute values into a character buffer.
960  llvm::divideCeil(storageBitWidth * values.size(), CHAR_BIT));
961  APInt intVal;
962  for (unsigned i = 0, e = values.size(); i < e; ++i) {
963  if (auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
964  assert(floatAttr.getType() == eltType &&
965  "expected float attribute type to equal element type");
966  intVal = floatAttr.getValue().bitcastToAPInt();
967  } else {
968  auto intAttr = llvm::cast<IntegerAttr>(values[i]);
969  assert(intAttr.getType() == eltType &&
970  "expected integer attribute type to equal element type");
971  intVal = intAttr.getValue();
972  }
973 
974  assert(intVal.getBitWidth() == bitWidth &&
975  "expected value to have same bitwidth as element type");
976  writeBits(data.data(), i * storageBitWidth, intVal);
977  }
978 
979  // Handle the special encoding of splat of bool.
980  if (values.size() == 1 && eltType.isInteger(1))
981  data[0] = data[0] ? -1 : 0;
982 
983  return DenseIntOrFPElementsAttr::getRaw(type, data);
984 }
985 
987  ArrayRef<bool> values) {
988  assert(hasSameElementsOrSplat(type, values));
989  assert(type.getElementType().isInteger(1));
990 
991  std::vector<char> buff(llvm::divideCeil(values.size(), CHAR_BIT));
992 
993  if (!values.empty()) {
994  bool isSplat = true;
995  bool firstValue = values[0];
996  for (int i = 0, e = values.size(); i != e; ++i) {
997  isSplat &= values[i] == firstValue;
998  setBit(buff.data(), i, values[i]);
999  }
1000 
1001  // Splat of bool is encoded as a byte with all-ones in it.
1002  if (isSplat) {
1003  buff.resize(1);
1004  buff[0] = values[0] ? -1 : 0;
1005  }
1006  }
1007 
1008  return DenseIntOrFPElementsAttr::getRaw(type, buff);
1009 }
1010 
1012  ArrayRef<StringRef> values) {
1013  assert(!type.getElementType().isIntOrFloat());
1014  return DenseStringElementsAttr::get(type, values);
1015 }
1016 
1017 /// Constructs a dense integer elements attribute from an array of APInt
1018 /// values. Each APInt value is expected to have the same bitwidth as the
1019 /// element type of 'type'.
1021  ArrayRef<APInt> values) {
1022  assert(type.getElementType().isIntOrIndex());
1023  assert(hasSameElementsOrSplat(type, values));
1024  size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
1025  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1026 }
1028  ArrayRef<std::complex<APInt>> values) {
1029  ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1030  assert(llvm::isa<IntegerType>(complex.getElementType()));
1031  assert(hasSameElementsOrSplat(type, values));
1032  size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
1033  ArrayRef<APInt> intVals(reinterpret_cast<const APInt *>(values.data()),
1034  values.size() * 2);
1035  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1036 }
1037 
1038 // Constructs a dense float elements attribute from an array of APFloat
1039 // values. Each APFloat value is expected to have the same bitwidth as the
1040 // element type of 'type'.
1042  ArrayRef<APFloat> values) {
1043  assert(llvm::isa<FloatType>(type.getElementType()));
1044  assert(hasSameElementsOrSplat(type, values));
1045  size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
1046  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1047 }
1049 DenseElementsAttr::get(ShapedType type,
1050  ArrayRef<std::complex<APFloat>> values) {
1051  ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1052  assert(llvm::isa<FloatType>(complex.getElementType()));
1053  assert(hasSameElementsOrSplat(type, values));
1054  ArrayRef<APFloat> apVals(reinterpret_cast<const APFloat *>(values.data()),
1055  values.size() * 2);
1056  size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
1057  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1058 }
1059 
1060 /// Construct a dense elements attribute from a raw buffer representing the
1061 /// data for this attribute. Users should generally not use this methods as
1062 /// the expected buffer format may not be a form the user expects.
1065  return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1066 }
1067 
1068 /// Returns true if the given buffer is a valid raw buffer for the given type.
1070  ArrayRef<char> rawBuffer,
1071  bool &detectedSplat) {
1072  size_t storageWidth = getDenseElementStorageWidth(type.getElementType());
1073  size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1074  int64_t numElements = type.getNumElements();
1075 
1076  // The initializer is always a splat if the result type has a single element.
1077  detectedSplat = numElements == 1;
1078 
1079  // Storage width of 1 is special as it is packed by the bit.
1080  if (storageWidth == 1) {
1081  // Check for a splat, or a buffer equal to the number of elements which
1082  // consists of either all 0's or all 1's.
1083  if (rawBuffer.size() == 1) {
1084  auto rawByte = static_cast<uint8_t>(rawBuffer[0]);
1085  if (rawByte == 0 || rawByte == 0xff) {
1086  detectedSplat = true;
1087  return true;
1088  }
1089  }
1090 
1091  // This is a valid non-splat buffer if it has the right size.
1092  return rawBufferWidth == llvm::alignTo<8>(numElements);
1093  }
1094 
1095  // All other types are 8-bit aligned, so we can just check the buffer width
1096  // to know if only a single initializer element was passed in.
1097  if (rawBufferWidth == storageWidth) {
1098  detectedSplat = true;
1099  return true;
1100  }
1101 
1102  // The raw buffer is valid if it has the right size.
1103  return rawBufferWidth == storageWidth * numElements;
1104 }
1105 
1106 /// Check the information for a C++ data type, check if this type is valid for
1107 /// the current attribute. This method is used to verify specific type
1108 /// invariants that the templatized 'getValues' method cannot.
1109 static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt,
1110  bool isSigned) {
1111  // Make sure that the data element size is the same as the type element width.
1112  auto denseEltBitWidth = getDenseElementBitWidth(type);
1113  auto dataSize = static_cast<size_t>(dataEltSize * CHAR_BIT);
1114  if (denseEltBitWidth != dataSize) {
1115  LLVM_DEBUG(llvm::dbgs() << "expected dense element bit width "
1116  << denseEltBitWidth << " to match data size "
1117  << dataSize << " for type " << type << "\n");
1118  return false;
1119  }
1120 
1121  // Check that the element type is either float or integer or index.
1122  if (!isInt) {
1123  bool valid = llvm::isa<FloatType>(type);
1124  if (!valid)
1125  LLVM_DEBUG(llvm::dbgs()
1126  << "expected float type when isInt is false, but found "
1127  << type << "\n");
1128  return valid;
1129  }
1130  if (type.isIndex())
1131  return true;
1132 
1133  auto intType = llvm::dyn_cast<IntegerType>(type);
1134  if (!intType) {
1135  LLVM_DEBUG(llvm::dbgs()
1136  << "expected integer type when isInt is true, but found " << type
1137  << "\n");
1138  return false;
1139  }
1140 
1141  // Make sure signedness semantics is consistent.
1142  if (intType.isSignless())
1143  return true;
1144 
1145  bool valid = intType.isSigned() == isSigned;
1146  if (!valid)
1147  LLVM_DEBUG(llvm::dbgs() << "expected signedness " << isSigned
1148  << " to match type " << type << "\n");
1149  return valid;
1150 }
1151 
1152 /// Defaults down the subclass implementation.
1154  ArrayRef<char> data,
1155  int64_t dataEltSize,
1156  bool isInt, bool isSigned) {
1157  return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1158  isSigned);
1159 }
1161  ArrayRef<char> data,
1162  int64_t dataEltSize,
1163  bool isInt,
1164  bool isSigned) {
1165  return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1166  isInt, isSigned);
1167 }
1168 
1169 bool DenseElementsAttr::isValidIntOrFloat(int64_t dataEltSize, bool isInt,
1170  bool isSigned) const {
1171  return ::isValidIntOrFloat(getElementType(), dataEltSize, isInt, isSigned);
1172 }
1173 bool DenseElementsAttr::isValidComplex(int64_t dataEltSize, bool isInt,
1174  bool isSigned) const {
1176  llvm::cast<ComplexType>(getElementType()).getElementType(),
1177  dataEltSize / 2, isInt, isSigned);
1178 }
1179 
1180 /// Returns true if this attribute corresponds to a splat, i.e. if all element
1181 /// values are the same.
1183  return static_cast<DenseElementsAttributeStorage *>(impl)->isSplat;
1184 }
1185 
1186 /// Return if the given complex type has an integer element type.
1187 static bool isComplexOfIntType(Type type) {
1188  return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).getElementType());
1189 }
1190 
1194  return failure();
1196  getType(), ComplexIntElementIterator(*this, 0),
1198 }
1199 
1201  -> FailureOr<iterator_range_impl<FloatElementIterator>> {
1202  auto eltTy = llvm::dyn_cast<FloatType>(getElementType());
1203  if (!eltTy)
1204  return failure();
1205  const auto &elementSemantics = eltTy.getFloatSemantics();
1207  getType(), FloatElementIterator(elementSemantics, raw_int_begin()),
1208  FloatElementIterator(elementSemantics, raw_int_end()));
1209 }
1210 
1213  auto complexTy = llvm::dyn_cast<ComplexType>(getElementType());
1214  if (!complexTy)
1215  return failure();
1216  auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1217  if (!eltTy)
1218  return failure();
1219  const auto &semantics = eltTy.getFloatSemantics();
1221  getType(), {semantics, {*this, 0}},
1222  {semantics, {*this, static_cast<size_t>(getNumElements())}});
1223 }
1224 
1225 /// Return the raw storage data held by this attribute.
1227  return static_cast<DenseIntOrFPElementsAttrStorage *>(impl)->data;
1228 }
1229 
1231  return static_cast<DenseStringElementsAttrStorage *>(impl)->data;
1232 }
1233 
1234 /// Return a new DenseElementsAttr that has the same data as the current
1235 /// attribute, but has been reshaped to 'newType'. The new type must have the
1236 /// same total number of elements as well as element type.
1238  ShapedType curType = getType();
1239  if (curType == newType)
1240  return *this;
1241 
1242  assert(newType.getElementType() == curType.getElementType() &&
1243  "expected the same element type");
1244  assert(newType.getNumElements() == curType.getNumElements() &&
1245  "expected the same number of elements");
1246  return DenseIntOrFPElementsAttr::getRaw(newType, getRawData());
1247 }
1248 
1250  assert(isSplat() && "expected a splat type");
1251 
1252  ShapedType curType = getType();
1253  if (curType == newType)
1254  return *this;
1255 
1256  assert(newType.getElementType() == curType.getElementType() &&
1257  "expected the same element type");
1258  return DenseIntOrFPElementsAttr::getRaw(newType, getRawData());
1259 }
1260 
1261 /// Return a new DenseElementsAttr that has the same data as the current
1262 /// attribute, but has bitcast elements such that it is now 'newType'. The new
1263 /// type must have the same shape and element types of the same bitwidth as the
1264 /// current type.
1266  ShapedType curType = getType();
1267  Type curElType = curType.getElementType();
1268  if (curElType == newElType)
1269  return *this;
1270 
1271  assert(getDenseElementBitWidth(newElType) ==
1272  getDenseElementBitWidth(curElType) &&
1273  "expected element types with the same bitwidth");
1274  return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1275  getRawData());
1276 }
1277 
1280  function_ref<APInt(const APInt &)> mapping) const {
1281  return llvm::cast<DenseIntElementsAttr>(*this).mapValues(newElementType,
1282  mapping);
1283 }
1284 
1286  Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1287  return llvm::cast<DenseFPElementsAttr>(*this).mapValues(newElementType,
1288  mapping);
1289 }
1290 
1291 ShapedType DenseElementsAttr::getType() const {
1292  return static_cast<const DenseElementsAttributeStorage *>(impl)->type;
1293 }
1294 
1296  return getType().getElementType();
1297 }
1298 
1300  return getType().getNumElements();
1301 }
1302 
1303 //===----------------------------------------------------------------------===//
1304 // DenseIntOrFPElementsAttr
1305 //===----------------------------------------------------------------------===//
1306 
1307 /// Utility method to write a range of APInt values to a buffer.
1308 template <typename APRangeT>
1309 static void writeAPIntsToBuffer(size_t storageWidth, std::vector<char> &data,
1310  APRangeT &&values) {
1311  size_t numValues = llvm::size(values);
1312  data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1313  size_t offset = 0;
1314  for (auto it = values.begin(), e = values.end(); it != e;
1315  ++it, offset += storageWidth) {
1316  assert((*it).getBitWidth() <= storageWidth);
1317  writeBits(data.data(), offset, *it);
1318  }
1319 
1320  // Handle the special encoding of splat of a boolean.
1321  if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1322  data[0] = data[0] ? -1 : 0;
1323 }
1324 
1325 /// Constructs a dense elements attribute from an array of raw APFloat values.
1326 /// Each APFloat value is expected to have the same bitwidth as the element
1327 /// type of 'type'. 'type' must be a vector or tensor with static shape.
1328 DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1329  size_t storageWidth,
1330  ArrayRef<APFloat> values) {
1331  std::vector<char> data;
1332  auto unwrapFloat = [](const APFloat &val) { return val.bitcastToAPInt(); };
1333  writeAPIntsToBuffer(storageWidth, data, llvm::map_range(values, unwrapFloat));
1334  return DenseIntOrFPElementsAttr::getRaw(type, data);
1335 }
1336 
1337 /// Constructs a dense elements attribute from an array of raw APInt values.
1338 /// Each APInt value is expected to have the same bitwidth as the element type
1339 /// of 'type'.
1340 DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1341  size_t storageWidth,
1342  ArrayRef<APInt> values) {
1343  std::vector<char> data;
1344  writeAPIntsToBuffer(storageWidth, data, values);
1345  return DenseIntOrFPElementsAttr::getRaw(type, data);
1346 }
1347 
1348 DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1349  ArrayRef<char> data) {
1350  assert(type.hasStaticShape() && "type must have static shape");
1351  bool isSplat = false;
1352  bool isValid = isValidRawBuffer(type, data, isSplat);
1353  assert(isValid);
1354  (void)isValid;
1355  return Base::get(type.getContext(), type, data, isSplat);
1356 }
1357 
1358 /// Overload of the raw 'get' method that asserts that the given type is of
1359 /// complex type. This method is used to verify type invariants that the
1360 /// templatized 'get' method cannot.
1361 DenseElementsAttr DenseIntOrFPElementsAttr::getRawComplex(ShapedType type,
1362  ArrayRef<char> data,
1363  int64_t dataEltSize,
1364  bool isInt,
1365  bool isSigned) {
1366  assert(::isValidIntOrFloat(
1367  llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1368  dataEltSize / 2, isInt, isSigned) &&
1369  "Try re-running with -debug-only=builtinattributes");
1370 
1371  int64_t numElements = data.size() / dataEltSize;
1372  (void)numElements;
1373  assert(numElements == 1 || numElements == type.getNumElements());
1374  return getRaw(type, data);
1375 }
1376 
1377 /// Overload of the 'getRaw' method that asserts that the given type is of
1378 /// integer type. This method is used to verify type invariants that the
1379 /// templatized 'get' method cannot.
1381 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
1382  int64_t dataEltSize, bool isInt,
1383  bool isSigned) {
1384  assert(::isValidIntOrFloat(type.getElementType(), dataEltSize, isInt,
1385  isSigned) &&
1386  "Try re-running with -debug-only=builtinattributes");
1387 
1388  int64_t numElements = data.size() / dataEltSize;
1389  assert(numElements == 1 || numElements == type.getNumElements());
1390  (void)numElements;
1391  return getRaw(type, data);
1392 }
1393 
1394 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1395  const char *inRawData, char *outRawData, size_t elementBitWidth,
1396  size_t numElements) {
1397  using llvm::support::ulittle16_t;
1398  using llvm::support::ulittle32_t;
1399  using llvm::support::ulittle64_t;
1400 
1401  assert(llvm::endianness::native == llvm::endianness::big);
1402  // NOLINT to avoid warning message about replacing by static_assert()
1403 
1404  // Following std::copy_n always converts endianness on BE machine.
1405  switch (elementBitWidth) {
1406  case 16: {
1407  const ulittle16_t *inRawDataPos =
1408  reinterpret_cast<const ulittle16_t *>(inRawData);
1409  uint16_t *outDataPos = reinterpret_cast<uint16_t *>(outRawData);
1410  std::copy_n(inRawDataPos, numElements, outDataPos);
1411  break;
1412  }
1413  case 32: {
1414  const ulittle32_t *inRawDataPos =
1415  reinterpret_cast<const ulittle32_t *>(inRawData);
1416  uint32_t *outDataPos = reinterpret_cast<uint32_t *>(outRawData);
1417  std::copy_n(inRawDataPos, numElements, outDataPos);
1418  break;
1419  }
1420  case 64: {
1421  const ulittle64_t *inRawDataPos =
1422  reinterpret_cast<const ulittle64_t *>(inRawData);
1423  uint64_t *outDataPos = reinterpret_cast<uint64_t *>(outRawData);
1424  std::copy_n(inRawDataPos, numElements, outDataPos);
1425  break;
1426  }
1427  default: {
1428  size_t nBytes = elementBitWidth / CHAR_BIT;
1429  for (size_t i = 0; i < nBytes; i++)
1430  std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1431  break;
1432  }
1433  }
1434 }
1435 
1436 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1437  ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1438  ShapedType type) {
1439  size_t numElements = type.getNumElements();
1440  Type elementType = type.getElementType();
1441  if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1442  elementType = complexTy.getElementType();
1443  numElements = numElements * 2;
1444  }
1445  size_t elementBitWidth = getDenseElementStorageWidth(elementType);
1446  assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1447  inRawData.size() <= outRawData.size());
1448  if (elementBitWidth <= CHAR_BIT)
1449  std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1450  else
1451  convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1452  elementBitWidth, numElements);
1453 }
1454 
1455 //===----------------------------------------------------------------------===//
1456 // DenseFPElementsAttr
1457 //===----------------------------------------------------------------------===//
1458 
1459 template <typename Fn, typename Attr>
1460 static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType,
1461  Type newElementType,
1463  size_t bitWidth = getDenseElementBitWidth(newElementType);
1464  size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
1465 
1466  ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1467 
1468  size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1469  data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1470 
1471  // Functor used to process a single element value of the attribute.
1472  auto processElt = [&](decltype(*attr.begin()) value, size_t index) {
1473  auto newInt = mapping(value);
1474  assert(newInt.getBitWidth() == bitWidth);
1475  writeBits(data.data(), index * storageBitWidth, newInt);
1476  };
1477 
1478  // Check for the splat case.
1479  if (attr.isSplat()) {
1480  if (bitWidth == 1) {
1481  // Handle the special encoding of splat of bool.
1482  data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1483  } else {
1484  processElt(*attr.begin(), /*index=*/0);
1485  }
1486  return newArrayType;
1487  }
1488 
1489  // Otherwise, process all of the element values.
1490  uint64_t elementIdx = 0;
1491  for (auto value : attr)
1492  processElt(value, elementIdx++);
1493  return newArrayType;
1494 }
1495 
1497  Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1498  llvm::SmallVector<char, 8> elementData;
1499  auto newArrayType =
1500  mappingHelper(mapping, *this, getType(), newElementType, elementData);
1501 
1502  return getRaw(newArrayType, elementData);
1503 }
1504 
1505 /// Method for supporting type inquiry through isa, cast and dyn_cast.
1507  if (auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1508  return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1509  return false;
1510 }
1511 
1512 //===----------------------------------------------------------------------===//
1513 // DenseIntElementsAttr
1514 //===----------------------------------------------------------------------===//
1515 
1517  Type newElementType, function_ref<APInt(const APInt &)> mapping) const {
1518  llvm::SmallVector<char, 8> elementData;
1519  auto newArrayType =
1520  mappingHelper(mapping, *this, getType(), newElementType, elementData);
1521  return getRaw(newArrayType, elementData);
1522 }
1523 
1524 /// Method for supporting type inquiry through isa, cast and dyn_cast.
1526  if (auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1527  return denseAttr.getType().getElementType().isIntOrIndex();
1528  return false;
1529 }
1530 
1531 //===----------------------------------------------------------------------===//
1532 // DenseResourceElementsAttr
1533 //===----------------------------------------------------------------------===//
1534 
1536 DenseResourceElementsAttr::get(ShapedType type,
1537  DenseResourceElementsHandle handle) {
1538  return Base::get(type.getContext(), type, handle);
1539 }
1540 
1542  StringRef blobName,
1543  AsmResourceBlob blob) {
1544  // Extract the builtin dialect resource manager from context and construct a
1545  // handle by inserting a new resource using the provided blob.
1546  auto &manager =
1548  return get(type, manager.insert(blobName, std::move(blob)));
1549 }
1550 
1551 ArrayRef<char> DenseResourceElementsAttr::getData() {
1552  if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1553  return blob->getDataAs<char>();
1554  return {};
1555 }
1556 
1557 //===----------------------------------------------------------------------===//
1558 // DenseResourceElementsAttrBase
1559 //===----------------------------------------------------------------------===//
1560 
1561 namespace {
1562 /// Instantiations of this class provide utilities for interacting with native
1563 /// data types in the context of DenseResourceElementsAttr.
1564 template <typename T>
1565 struct DenseResourceAttrUtil;
1566 template <size_t width, bool isSigned>
1567 struct DenseResourceElementsAttrIntUtil {
1568  static bool checkElementType(Type eltType) {
1569  IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1570  if (!type || type.getWidth() != width)
1571  return false;
1572  return isSigned ? !type.isUnsigned() : !type.isSigned();
1573  }
1574 };
1575 template <>
1576 struct DenseResourceAttrUtil<bool> {
1577  static bool checkElementType(Type eltType) {
1578  return eltType.isSignlessInteger(1);
1579  }
1580 };
1581 template <>
1582 struct DenseResourceAttrUtil<int8_t>
1583  : public DenseResourceElementsAttrIntUtil<8, true> {};
1584 template <>
1585 struct DenseResourceAttrUtil<uint8_t>
1586  : public DenseResourceElementsAttrIntUtil<8, false> {};
1587 template <>
1588 struct DenseResourceAttrUtil<int16_t>
1589  : public DenseResourceElementsAttrIntUtil<16, true> {};
1590 template <>
1591 struct DenseResourceAttrUtil<uint16_t>
1592  : public DenseResourceElementsAttrIntUtil<16, false> {};
1593 template <>
1594 struct DenseResourceAttrUtil<int32_t>
1595  : public DenseResourceElementsAttrIntUtil<32, true> {};
1596 template <>
1597 struct DenseResourceAttrUtil<uint32_t>
1598  : public DenseResourceElementsAttrIntUtil<32, false> {};
1599 template <>
1600 struct DenseResourceAttrUtil<int64_t>
1601  : public DenseResourceElementsAttrIntUtil<64, true> {};
1602 template <>
1603 struct DenseResourceAttrUtil<uint64_t>
1604  : public DenseResourceElementsAttrIntUtil<64, false> {};
1605 template <>
1606 struct DenseResourceAttrUtil<float> {
1607  static bool checkElementType(Type eltType) { return eltType.isF32(); }
1608 };
1609 template <>
1610 struct DenseResourceAttrUtil<double> {
1611  static bool checkElementType(Type eltType) { return eltType.isF64(); }
1612 };
1613 } // namespace
1614 
1615 template <typename T>
1617 DenseResourceElementsAttrBase<T>::get(ShapedType type, StringRef blobName,
1618  AsmResourceBlob blob) {
1619  // Check that the blob is in the form we were expecting.
1620  assert(blob.getDataAlignment() == alignof(T) &&
1621  "alignment mismatch between expected alignment and blob alignment");
1622  assert(((blob.getData().size() % sizeof(T)) == 0) &&
1623  "size mismatch between expected element width and blob size");
1624  assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1625  "invalid shape element type for provided type `T`");
1626  return llvm::cast<DenseResourceElementsAttrBase<T>>(
1627  DenseResourceElementsAttr::get(type, blobName, std::move(blob)));
1628 }
1629 
1630 template <typename T>
1631 std::optional<ArrayRef<T>>
1633  if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1634  return blob->template getDataAs<T>();
1635  return std::nullopt;
1636 }
1637 
1638 template <typename T>
1640  auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1641  return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1642  resourceAttr.getElementType());
1643 }
1644 
1645 namespace mlir {
1646 namespace detail {
1647 // Explicit instantiation for all the supported DenseResourceElementsAttr.
1659 } // namespace detail
1660 } // namespace mlir
1661 
1662 //===----------------------------------------------------------------------===//
1663 // SparseElementsAttr
1664 //===----------------------------------------------------------------------===//
1665 
1666 /// Get a zero APFloat for the given sparse attribute.
1667 APFloat SparseElementsAttr::getZeroAPFloat() const {
1668  auto eltType = llvm::cast<FloatType>(getElementType());
1669  return APFloat(eltType.getFloatSemantics());
1670 }
1671 
1672 /// Get a zero APInt for the given sparse attribute.
1673 APInt SparseElementsAttr::getZeroAPInt() const {
1674  auto eltType = llvm::cast<IntegerType>(getElementType());
1675  return APInt::getZero(eltType.getWidth());
1676 }
1677 
1678 /// Get a zero attribute for the given attribute type.
1679 Attribute SparseElementsAttr::getZeroAttr() const {
1680  auto eltType = getElementType();
1681 
1682  // Handle floating point elements.
1683  if (llvm::isa<FloatType>(eltType))
1684  return FloatAttr::get(eltType, 0);
1685 
1686  // Handle complex elements.
1687  if (auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1688  auto eltType = complexTy.getElementType();
1689  Attribute zero;
1690  if (llvm::isa<FloatType>(eltType))
1691  zero = FloatAttr::get(eltType, 0);
1692  else // must be integer
1693  zero = IntegerAttr::get(eltType, 0);
1694  return ArrayAttr::get(complexTy.getContext(),
1695  ArrayRef<Attribute>{zero, zero});
1696  }
1697 
1698  // Handle string type.
1699  if (llvm::isa<DenseStringElementsAttr>(getValues()))
1700  return StringAttr::get("", eltType);
1701 
1702  // Otherwise, this is an integer.
1703  return IntegerAttr::get(eltType, 0);
1704 }
1705 
1706 /// Flatten, and return, all of the sparse indices in this attribute in
1707 /// row-major order.
1708 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices() const {
1709  std::vector<ptrdiff_t> flatSparseIndices;
1710 
1711  // The sparse indices are 64-bit integers, so we can reinterpret the raw data
1712  // as a 1-D index array.
1713  auto sparseIndices = getIndices();
1714  auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1715  if (sparseIndices.isSplat()) {
1716  SmallVector<uint64_t, 8> indices(getType().getRank(),
1717  *sparseIndexValues.begin());
1718  flatSparseIndices.push_back(getFlattenedIndex(indices));
1719  return flatSparseIndices;
1720  }
1721 
1722  // Otherwise, reinterpret each index as an ArrayRef when flattening.
1723  auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1724  size_t rank = getType().getRank();
1725  for (size_t i = 0, e = numSparseIndices; i != e; ++i)
1726  flatSparseIndices.push_back(getFlattenedIndex(
1727  {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1728  return flatSparseIndices;
1729 }
1730 
1731 LogicalResult
1733  ShapedType type, DenseIntElementsAttr sparseIndices,
1734  DenseElementsAttr values) {
1735  ShapedType valuesType = values.getType();
1736  if (valuesType.getRank() != 1)
1737  return emitError() << "expected 1-d tensor for sparse element values";
1738 
1739  // Verify the indices and values shape.
1740  ShapedType indicesType = sparseIndices.getType();
1741  auto emitShapeError = [&]() {
1742  return emitError() << "expected shape ([" << type.getShape()
1743  << "]); inferred shape of indices literal (["
1744  << indicesType.getShape()
1745  << "]); inferred shape of values literal (["
1746  << valuesType.getShape() << "])";
1747  };
1748  // Verify indices shape.
1749  size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1750  if (indicesRank == 2) {
1751  if (indicesType.getDimSize(1) != static_cast<int64_t>(rank))
1752  return emitShapeError();
1753  } else if (indicesRank != 1 || rank != 1) {
1754  return emitShapeError();
1755  }
1756  // Verify the values shape.
1757  int64_t numSparseIndices = indicesType.getDimSize(0);
1758  if (numSparseIndices != valuesType.getDimSize(0))
1759  return emitShapeError();
1760 
1761  // Verify that the sparse indices are within the value shape.
1762  auto emitIndexError = [&](unsigned indexNum, ArrayRef<uint64_t> index) {
1763  return emitError()
1764  << "sparse index #" << indexNum
1765  << " is not contained within the value shape, with index=[" << index
1766  << "], and type=" << type;
1767  };
1768 
1769  // Handle the case where the index values are a splat.
1770  auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1771  if (sparseIndices.isSplat()) {
1772  SmallVector<uint64_t> indices(rank, *sparseIndexValues.begin());
1773  if (!ElementsAttr::isValidIndex(type, indices))
1774  return emitIndexError(0, indices);
1775  return success();
1776  }
1777 
1778  // Otherwise, reinterpret each index as an ArrayRef.
1779  for (size_t i = 0, e = numSparseIndices; i != e; ++i) {
1780  ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1781  rank);
1782  if (!ElementsAttr::isValidIndex(type, index))
1783  return emitIndexError(i, index);
1784  }
1785 
1786  return success();
1787 }
1788 
1789 //===----------------------------------------------------------------------===//
1790 // DistinctAttr
1791 //===----------------------------------------------------------------------===//
1792 
1794  return Base::get(referencedAttr.getContext(), referencedAttr);
1795 }
1796 
1798  return getImpl()->referencedAttr;
1799 }
1800 
1801 //===----------------------------------------------------------------------===//
1802 // Attribute Utilities
1803 //===----------------------------------------------------------------------===//
1804 
1806  int64_t offset,
1807  MLIRContext *context) {
1808  AffineExpr expr;
1809  unsigned nSymbols = 0;
1810 
1811  // AffineExpr for offset.
1812  // Static case.
1813  if (!ShapedType::isDynamic(offset)) {
1814  auto cst = getAffineConstantExpr(offset, context);
1815  expr = cst;
1816  } else {
1817  // Dynamic case, new symbol for the offset.
1818  auto sym = getAffineSymbolExpr(nSymbols++, context);
1819  expr = sym;
1820  }
1821 
1822  // AffineExpr for strides.
1823  for (const auto &en : llvm::enumerate(strides)) {
1824  auto dim = en.index();
1825  auto stride = en.value();
1826  auto d = getAffineDimExpr(dim, context);
1827  AffineExpr mult;
1828  // Static case.
1829  if (!ShapedType::isDynamic(stride))
1830  mult = getAffineConstantExpr(stride, context);
1831  else
1832  // Dynamic case, new symbol for each new stride.
1833  mult = getAffineSymbolExpr(nSymbols++, context);
1834  expr = expr + d * mult;
1835  }
1836 
1837  return AffineMap::get(strides.size(), nSymbols, expr);
1838 }
static Value getZero(OpBuilder &b, Location loc, Type elementType)
Get zero value for an element type.
static void writeAPIntsToBuffer(size_t storageWidth, std::vector< char > &data, APRangeT &&values)
Utility method to write a range of APInt values to a buffer.
static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt, bool isSigned)
Check the information for a C++ data type, check if this type is valid for the current attribute.
static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes, char *result)
Copy actual numBytes data from value (APInt) to char array(result) for BE format.
static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType, Type newElementType, llvm::SmallVectorImpl< char > &data)
static void setBit(char *rawData, size_t bitPos, bool value)
Set a bit to a specific value.
static void writeBits(char *rawData, size_t bitPos, APInt value)
Writes value to the bit position bitPos in array rawData.
static bool dictionaryAttrSort(ArrayRef< NamedAttribute > value, SmallVectorImpl< NamedAttribute > &storage)
Helper function that does either an in place sort or sorts from source array into destination.
static size_t getDenseElementStorageWidth(size_t origWidth)
Get the bitwidth of a dense element type within the buffer.
static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes, APInt &result)
Copy numBytes data from inArray(char array) to result(APINT) for BE format.
static bool getBit(const char *rawData, size_t bitPos)
Return the value of the specified bit.
static bool isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
static std::optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
static bool hasSameElementsOrSplat(ShapedType type, const Values &values)
Returns true if 'values' corresponds to a splat, i.e.
static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth)
Reads the next bitWidth bits from the bit position bitPos in array rawData.
static MLIRContext * getContext(OpFoldResult val)
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
Definition: MLIRServer.cpp:111
static DimensionSize operator*(DimensionSize lhs, DimensionSize rhs)
Definition: MeshOps.cpp:71
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
Definition: SPIRVOps.cpp:187
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
Definition: AsmPrinter.cpp:73
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
ImplType * impl
Definition: Attributes.h:165
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
MLIRContext * getContext() const
Return the context this attribute belongs to.
Definition: Attributes.cpp:37
ImplType * getImpl() const
Return the internal Attribute implementation.
Definition: Attributes.h:162
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
Definition: Attributes.h:93
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.
bool getValue() const
Return the boolean value of this attribute.
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
auto getValues() const
Return the held element values as a range of the given type.
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
int64_t getNumElements() const
Returns the number of elements held by this attribute.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
int64_t size() const
Returns the number of elements held by this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each int value to a new underlying APInt.
Type getElementType() const
Return the element type of this DenseElementsAttr.
FailureOr< iterator_range_impl< ComplexFloatElementIterator > > tryGetComplexFloatValues() const
IntElementIterator raw_int_end() const
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
FailureOr< iterator_range_impl< FloatElementIterator > > tryGetFloatValues() const
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer, bool &detectedSplat)
Returns true if the given buffer is a valid raw buffer for the given type.
DenseElementsAttr bitcast(Type newElType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has bitcast eleme...
bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr reshape(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has been reshaped...
FailureOr< iterator_range_impl< ComplexIntElementIterator > > tryGetComplexIntValues() const
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APFloat &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
An attribute that represents a reference to a dense integer vector or tensor object.
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:98
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.
Definition: Diagnostics.h:314
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
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:207
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:550
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:76
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
bool isF64() const
Definition: Types.cpp:41
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:35
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
Definition: Types.cpp:64
bool isIndex() const
Definition: Types.cpp:54
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
Definition: Types.cpp:120
bool isF32() const
Definition: Types.cpp:40
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition: Types.cpp:56
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition: Types.cpp:122
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
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...
This class provides iterator utilities for an ElementsAttr range.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
AttrTypeReplacer.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator)
Divides the known min value of the numerator by the denominator and rounds the result up to the next ...
std::pair< IteratorT, bool > findAttrSorted(IteratorT first, IteratorT last, StringRef name)
Using llvm::lower_bound requires an extra string comparison to check whether the returned iterator po...
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
Definition: Utils.cpp:18
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:20
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:305
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)
Definition: AffineExpr.cpp:645
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.
Definition: AffineExpr.cpp:621
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:424
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
Definition: AffineExpr.cpp:631
This class defines a dialect specific handle to a resource blob.
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
Get the interface for the dialect that owns handles of this type.
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object.
static const char kSplatTrue
The values used to denote a boolean splat value.
An attribute representing a reference to a dense vector or tensor object containing strings.