MLIR  14.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"
14 #include "mlir/IR/IntegerSet.h"
15 #include "mlir/IR/Operation.h"
16 #include "mlir/IR/SymbolTable.h"
17 #include "mlir/IR/Types.h"
19 #include "llvm/ADT/APSInt.h"
20 #include "llvm/ADT/Sequence.h"
21 #include "llvm/Support/Endian.h"
22 
23 using namespace mlir;
24 using namespace mlir::detail;
25 
26 //===----------------------------------------------------------------------===//
27 /// Tablegen Attribute Definitions
28 //===----------------------------------------------------------------------===//
29 
30 #define GET_ATTRDEF_CLASSES
31 #include "mlir/IR/BuiltinAttributes.cpp.inc"
32 
33 //===----------------------------------------------------------------------===//
34 // BuiltinDialect
35 //===----------------------------------------------------------------------===//
36 
37 void BuiltinDialect::registerAttributes() {
38  addAttributes<AffineMapAttr, ArrayAttr, DenseIntOrFPElementsAttr,
39  DenseStringElementsAttr, DictionaryAttr, FloatAttr,
40  SymbolRefAttr, IntegerAttr, IntegerSetAttr, OpaqueAttr,
41  OpaqueElementsAttr, SparseElementsAttr, StringAttr, TypeAttr,
42  UnitAttr>();
43 }
44 
45 //===----------------------------------------------------------------------===//
46 // ArrayAttr
47 //===----------------------------------------------------------------------===//
48 
49 void ArrayAttr::walkImmediateSubElements(
50  function_ref<void(Attribute)> walkAttrsFn,
51  function_ref<void(Type)> walkTypesFn) const {
52  for (Attribute attr : getValue())
53  walkAttrsFn(attr);
54 }
55 
56 SubElementAttrInterface ArrayAttr::replaceImmediateSubAttribute(
57  ArrayRef<std::pair<size_t, Attribute>> replacements) const {
58  std::vector<Attribute> vector = getValue().vec();
59  for (auto &it : replacements) {
60  vector[it.first] = it.second;
61  }
62  return get(getContext(), vector);
63 }
64 
65 //===----------------------------------------------------------------------===//
66 // DictionaryAttr
67 //===----------------------------------------------------------------------===//
68 
69 /// Helper function that does either an in place sort or sorts from source array
70 /// into destination. If inPlace then storage is both the source and the
71 /// destination, else value is the source and storage destination. Returns
72 /// whether source was sorted.
73 template <bool inPlace>
76  // Specialize for the common case.
77  switch (value.size()) {
78  case 0:
79  // Zero already sorted.
80  if (!inPlace)
81  storage.clear();
82  break;
83  case 1:
84  // One already sorted but may need to be copied.
85  if (!inPlace)
86  storage.assign({value[0]});
87  break;
88  case 2: {
89  bool isSorted = value[0] < value[1];
90  if (inPlace) {
91  if (!isSorted)
92  std::swap(storage[0], storage[1]);
93  } else if (isSorted) {
94  storage.assign({value[0], value[1]});
95  } else {
96  storage.assign({value[1], value[0]});
97  }
98  return !isSorted;
99  }
100  default:
101  if (!inPlace)
102  storage.assign(value.begin(), value.end());
103  // Check to see they are sorted already.
104  bool isSorted = llvm::is_sorted(value);
105  // If not, do a general sort.
106  if (!isSorted)
107  llvm::array_pod_sort(storage.begin(), storage.end());
108  return !isSorted;
109  }
110  return false;
111 }
112 
113 /// Returns an entry with a duplicate name from the given sorted array of named
114 /// attributes. Returns llvm::None if all elements have unique names.
115 static Optional<NamedAttribute>
117  const Optional<NamedAttribute> none{llvm::None};
118  if (value.size() < 2)
119  return none;
120 
121  if (value.size() == 2)
122  return value[0].getName() == value[1].getName() ? value[0] : none;
123 
124  const auto *it = std::adjacent_find(value.begin(), value.end(),
125  [](NamedAttribute l, NamedAttribute r) {
126  return l.getName() == r.getName();
127  });
128  return it != value.end() ? *it : none;
129 }
130 
131 bool DictionaryAttr::sort(ArrayRef<NamedAttribute> value,
133  bool isSorted = dictionaryAttrSort</*inPlace=*/false>(value, storage);
134  assert(!findDuplicateElement(storage) &&
135  "DictionaryAttr element names must be unique");
136  return isSorted;
137 }
138 
139 bool DictionaryAttr::sortInPlace(SmallVectorImpl<NamedAttribute> &array) {
140  bool isSorted = dictionaryAttrSort</*inPlace=*/true>(array, array);
141  assert(!findDuplicateElement(array) &&
142  "DictionaryAttr element names must be unique");
143  return isSorted;
144 }
145 
146 Optional<NamedAttribute>
147 DictionaryAttr::findDuplicate(SmallVectorImpl<NamedAttribute> &array,
148  bool isSorted) {
149  if (!isSorted)
150  dictionaryAttrSort</*inPlace=*/true>(array, array);
151  return findDuplicateElement(array);
152 }
153 
154 DictionaryAttr DictionaryAttr::get(MLIRContext *context,
155  ArrayRef<NamedAttribute> value) {
156  if (value.empty())
157  return DictionaryAttr::getEmpty(context);
158 
159  // We need to sort the element list to canonicalize it.
161  if (dictionaryAttrSort</*inPlace=*/false>(value, storage))
162  value = storage;
163  assert(!findDuplicateElement(value) &&
164  "DictionaryAttr element names must be unique");
165  return Base::get(context, value);
166 }
167 /// Construct a dictionary with an array of values that is known to already be
168 /// sorted by name and uniqued.
169 DictionaryAttr DictionaryAttr::getWithSorted(MLIRContext *context,
170  ArrayRef<NamedAttribute> value) {
171  if (value.empty())
172  return DictionaryAttr::getEmpty(context);
173  // Ensure that the attribute elements are unique and sorted.
174  assert(llvm::is_sorted(
175  value, [](NamedAttribute l, NamedAttribute r) { return l < r; }) &&
176  "expected attribute values to be sorted");
177  assert(!findDuplicateElement(value) &&
178  "DictionaryAttr element names must be unique");
179  return Base::get(context, value);
180 }
181 
182 /// Return the specified attribute if present, null otherwise.
183 Attribute DictionaryAttr::get(StringRef name) const {
184  auto it = impl::findAttrSorted(begin(), end(), name);
185  return it.second ? it.first->getValue() : Attribute();
186 }
187 Attribute DictionaryAttr::get(StringAttr name) const {
188  auto it = impl::findAttrSorted(begin(), end(), name);
189  return it.second ? it.first->getValue() : Attribute();
190 }
191 
192 /// Return the specified named attribute if present, None otherwise.
193 Optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name) const {
194  auto it = impl::findAttrSorted(begin(), end(), name);
195  return it.second ? *it.first : Optional<NamedAttribute>();
196 }
197 Optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name) const {
198  auto it = impl::findAttrSorted(begin(), end(), name);
199  return it.second ? *it.first : Optional<NamedAttribute>();
200 }
201 
202 /// Return whether the specified attribute is present.
203 bool DictionaryAttr::contains(StringRef name) const {
204  return impl::findAttrSorted(begin(), end(), name).second;
205 }
206 bool DictionaryAttr::contains(StringAttr name) const {
207  return impl::findAttrSorted(begin(), end(), name).second;
208 }
209 
210 DictionaryAttr::iterator DictionaryAttr::begin() const {
211  return getValue().begin();
212 }
213 DictionaryAttr::iterator DictionaryAttr::end() const {
214  return getValue().end();
215 }
216 size_t DictionaryAttr::size() const { return getValue().size(); }
217 
218 DictionaryAttr DictionaryAttr::getEmptyUnchecked(MLIRContext *context) {
219  return Base::get(context, ArrayRef<NamedAttribute>());
220 }
221 
222 void DictionaryAttr::walkImmediateSubElements(
223  function_ref<void(Attribute)> walkAttrsFn,
224  function_ref<void(Type)> walkTypesFn) const {
225  for (const NamedAttribute &attr : getValue())
226  walkAttrsFn(attr.getValue());
227 }
228 
229 SubElementAttrInterface DictionaryAttr::replaceImmediateSubAttribute(
230  ArrayRef<std::pair<size_t, Attribute>> replacements) const {
231  std::vector<NamedAttribute> vec = getValue().vec();
232  for (auto &it : replacements)
233  vec[it.first].setValue(it.second);
234 
235  // The above only modifies the mapped value, but not the key, and therefore
236  // not the order of the elements. It remains sorted
237  return getWithSorted(getContext(), vec);
238 }
239 
240 //===----------------------------------------------------------------------===//
241 // StringAttr
242 //===----------------------------------------------------------------------===//
243 
244 StringAttr StringAttr::getEmptyStringAttrUnchecked(MLIRContext *context) {
245  return Base::get(context, "", NoneType::get(context));
246 }
247 
248 /// Twine support for StringAttr.
249 StringAttr StringAttr::get(MLIRContext *context, const Twine &twine) {
250  // Fast-path empty twine.
251  if (twine.isTriviallyEmpty())
252  return get(context);
253  SmallVector<char, 32> tempStr;
254  return Base::get(context, twine.toStringRef(tempStr), NoneType::get(context));
255 }
256 
257 /// Twine support for StringAttr.
258 StringAttr StringAttr::get(const Twine &twine, Type type) {
259  SmallVector<char, 32> tempStr;
260  return Base::get(type.getContext(), twine.toStringRef(tempStr), type);
261 }
262 
263 StringRef StringAttr::getValue() const { return getImpl()->value; }
264 
265 Dialect *StringAttr::getReferencedDialect() const {
266  return getImpl()->referencedDialect;
267 }
268 
269 //===----------------------------------------------------------------------===//
270 // FloatAttr
271 //===----------------------------------------------------------------------===//
272 
273 double FloatAttr::getValueAsDouble() const {
274  return getValueAsDouble(getValue());
275 }
276 double FloatAttr::getValueAsDouble(APFloat value) {
277  if (&value.getSemantics() != &APFloat::IEEEdouble()) {
278  bool losesInfo = false;
279  value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
280  &losesInfo);
281  }
282  return value.convertToDouble();
283 }
284 
286  Type type, APFloat value) {
287  // Verify that the type is correct.
288  if (!type.isa<FloatType>())
289  return emitError() << "expected floating point type";
290 
291  // Verify that the type semantics match that of the value.
292  if (&type.cast<FloatType>().getFloatSemantics() != &value.getSemantics()) {
293  return emitError()
294  << "FloatAttr type doesn't match the type implied by its value";
295  }
296  return success();
297 }
298 
299 //===----------------------------------------------------------------------===//
300 // SymbolRefAttr
301 //===----------------------------------------------------------------------===//
302 
303 SymbolRefAttr SymbolRefAttr::get(MLIRContext *ctx, StringRef value,
304  ArrayRef<FlatSymbolRefAttr> nestedRefs) {
305  return get(StringAttr::get(ctx, value), nestedRefs);
306 }
307 
308 FlatSymbolRefAttr SymbolRefAttr::get(MLIRContext *ctx, StringRef value) {
309  return get(ctx, value, {}).cast<FlatSymbolRefAttr>();
310 }
311 
312 FlatSymbolRefAttr SymbolRefAttr::get(StringAttr value) {
313  return get(value, {}).cast<FlatSymbolRefAttr>();
314 }
315 
316 FlatSymbolRefAttr SymbolRefAttr::get(Operation *symbol) {
317  auto symName =
318  symbol->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
319  assert(symName && "value does not have a valid symbol name");
320  return SymbolRefAttr::get(symName);
321 }
322 
323 StringAttr SymbolRefAttr::getLeafReference() const {
324  ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences();
325  return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
326 }
327 
328 //===----------------------------------------------------------------------===//
329 // IntegerAttr
330 //===----------------------------------------------------------------------===//
331 
332 int64_t IntegerAttr::getInt() const {
333  assert((getType().isIndex() || getType().isSignlessInteger()) &&
334  "must be signless integer");
335  return getValue().getSExtValue();
336 }
337 
338 int64_t IntegerAttr::getSInt() const {
339  assert(getType().isSignedInteger() && "must be signed integer");
340  return getValue().getSExtValue();
341 }
342 
343 uint64_t IntegerAttr::getUInt() const {
344  assert(getType().isUnsignedInteger() && "must be unsigned integer");
345  return getValue().getZExtValue();
346 }
347 
348 /// Return the value as an APSInt which carries the signed from the type of
349 /// the attribute. This traps on signless integers types!
350 APSInt IntegerAttr::getAPSInt() const {
351  assert(!getType().isSignlessInteger() &&
352  "Signless integers don't carry a sign for APSInt");
353  return APSInt(getValue(), getType().isUnsignedInteger());
354 }
355 
357  Type type, APInt value) {
358  if (IntegerType integerType = type.dyn_cast<IntegerType>()) {
359  if (integerType.getWidth() != value.getBitWidth())
360  return emitError() << "integer type bit width (" << integerType.getWidth()
361  << ") doesn't match value bit width ("
362  << value.getBitWidth() << ")";
363  return success();
364  }
365  if (type.isa<IndexType>())
366  return success();
367  return emitError() << "expected integer or index type";
368 }
369 
370 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type, bool value) {
371  auto attr = Base::get(type.getContext(), type, APInt(/*numBits=*/1, value));
372  return attr.cast<BoolAttr>();
373 }
374 
375 //===----------------------------------------------------------------------===//
376 // BoolAttr
377 //===----------------------------------------------------------------------===//
378 
379 bool BoolAttr::getValue() const {
380  auto *storage = reinterpret_cast<IntegerAttrStorage *>(impl);
381  return storage->value.getBoolValue();
382 }
383 
385  IntegerAttr intAttr = attr.dyn_cast<IntegerAttr>();
386  return intAttr && intAttr.getType().isSignlessInteger(1);
387 }
388 
389 //===----------------------------------------------------------------------===//
390 // OpaqueAttr
391 //===----------------------------------------------------------------------===//
392 
394  StringAttr dialect, StringRef attrData,
395  Type type) {
396  if (!Dialect::isValidNamespace(dialect.strref()))
397  return emitError() << "invalid dialect namespace '" << dialect << "'";
398 
399  // Check that the dialect is actually registered.
400  MLIRContext *context = dialect.getContext();
401  if (!context->allowsUnregisteredDialects() &&
402  !context->getLoadedDialect(dialect.strref())) {
403  return emitError()
404  << "#" << dialect << "<\"" << attrData << "\"> : " << type
405  << " attribute created with unregistered dialect. If this is "
406  "intended, please call allowUnregisteredDialects() on the "
407  "MLIRContext, or use -allow-unregistered-dialect with "
408  "the MLIR opt tool used";
409  }
410 
411  return success();
412 }
413 
414 //===----------------------------------------------------------------------===//
415 // DenseElementsAttr Utilities
416 //===----------------------------------------------------------------------===//
417 
418 /// Get the bitwidth of a dense element type within the buffer.
419 /// DenseElementsAttr requires bitwidths greater than 1 to be aligned by 8.
420 static size_t getDenseElementStorageWidth(size_t origWidth) {
421  return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
422 }
423 static size_t getDenseElementStorageWidth(Type elementType) {
425 }
426 
427 /// Set a bit to a specific value.
428 static void setBit(char *rawData, size_t bitPos, bool value) {
429  if (value)
430  rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
431  else
432  rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
433 }
434 
435 /// Return the value of the specified bit.
436 static bool getBit(const char *rawData, size_t bitPos) {
437  return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
438 }
439 
440 /// Copy actual `numBytes` data from `value` (APInt) to char array(`result`) for
441 /// BE format.
442 static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes,
443  char *result) {
444  assert(llvm::support::endian::system_endianness() == // NOLINT
445  llvm::support::endianness::big); // NOLINT
446  assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
447 
448  // Copy the words filled with data.
449  // For example, when `value` has 2 words, the first word is filled with data.
450  // `value` (10 bytes, BE):|abcdefgh|------ij| ==> `result` (BE):|abcdefgh|--|
451  size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
452  std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
453  numFilledWords, result);
454  // Convert last word of APInt to LE format and store it in char
455  // array(`valueLE`).
456  // ex. last word of `value` (BE): |------ij| ==> `valueLE` (LE): |ji------|
457  size_t lastWordPos = numFilledWords;
458  SmallVector<char, 8> valueLE(APInt::APINT_WORD_SIZE);
459  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
460  reinterpret_cast<const char *>(value.getRawData()) + lastWordPos,
461  valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
462  // Extract actual APInt data from `valueLE`, convert endianness to BE format,
463  // and store it in `result`.
464  // ex. `valueLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|ij|
465  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
466  valueLE.begin(), result + lastWordPos,
467  (numBytes - lastWordPos) * CHAR_BIT, 1);
468 }
469 
470 /// Copy `numBytes` data from `inArray`(char array) to `result`(APINT) for BE
471 /// format.
472 static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes,
473  APInt &result) {
474  assert(llvm::support::endian::system_endianness() == // NOLINT
475  llvm::support::endianness::big); // NOLINT
476  assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
477 
478  // Copy the data that fills the word of `result` from `inArray`.
479  // For example, when `result` has 2 words, the first word will be filled with
480  // data. So, the first 8 bytes are copied from `inArray` here.
481  // `inArray` (10 bytes, BE): |abcdefgh|ij|
482  // ==> `result` (2 words, BE): |abcdefgh|--------|
483  size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
484  std::copy_n(
485  inArray, numFilledWords,
486  const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())));
487 
488  // Convert array data which will be last word of `result` to LE format, and
489  // store it in char array(`inArrayLE`).
490  // ex. `inArray` (last two bytes, BE): |ij| ==> `inArrayLE` (LE): |ji------|
491  size_t lastWordPos = numFilledWords;
492  SmallVector<char, 8> inArrayLE(APInt::APINT_WORD_SIZE);
493  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
494  inArray + lastWordPos, inArrayLE.begin(),
495  (numBytes - lastWordPos) * CHAR_BIT, 1);
496 
497  // Convert `inArrayLE` to BE format, and store it in last word of `result`.
498  // ex. `inArrayLE` (LE): |ji------| ==> `result` (BE): |abcdefgh|------ij|
499  DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
500  inArrayLE.begin(),
501  const_cast<char *>(reinterpret_cast<const char *>(result.getRawData())) +
502  lastWordPos,
503  APInt::APINT_BITS_PER_WORD, 1);
504 }
505 
506 /// Writes value to the bit position `bitPos` in array `rawData`.
507 static void writeBits(char *rawData, size_t bitPos, APInt value) {
508  size_t bitWidth = value.getBitWidth();
509 
510  // If the bitwidth is 1 we just toggle the specific bit.
511  if (bitWidth == 1)
512  return setBit(rawData, bitPos, value.isOneValue());
513 
514  // Otherwise, the bit position is guaranteed to be byte aligned.
515  assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
516  if (llvm::support::endian::system_endianness() ==
517  llvm::support::endianness::big) {
518  // Copy from `value` to `rawData + (bitPos / CHAR_BIT)`.
519  // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
520  // work correctly in BE format.
521  // ex. `value` (2 words including 10 bytes)
522  // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------|
523  copyAPIntToArrayForBEmachine(value, llvm::divideCeil(bitWidth, CHAR_BIT),
524  rawData + (bitPos / CHAR_BIT));
525  } else {
526  std::copy_n(reinterpret_cast<const char *>(value.getRawData()),
527  llvm::divideCeil(bitWidth, CHAR_BIT),
528  rawData + (bitPos / CHAR_BIT));
529  }
530 }
531 
532 /// Reads the next `bitWidth` bits from the bit position `bitPos` in array
533 /// `rawData`.
534 static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth) {
535  // Handle a boolean bit position.
536  if (bitWidth == 1)
537  return APInt(1, getBit(rawData, bitPos) ? 1 : 0);
538 
539  // Otherwise, the bit position must be 8-bit aligned.
540  assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned");
541  APInt result(bitWidth, 0);
542  if (llvm::support::endian::system_endianness() ==
543  llvm::support::endianness::big) {
544  // Copy from `rawData + (bitPos / CHAR_BIT)` to `result`.
545  // Copying the first `llvm::divideCeil(bitWidth, CHAR_BIT)` bytes doesn't
546  // work correctly in BE format.
547  // ex. `result` (2 words including 10 bytes)
548  // ==> BE: |abcdefgh|------ij|, LE: |hgfedcba|ji------| This function
549  copyArrayToAPIntForBEmachine(rawData + (bitPos / CHAR_BIT),
550  llvm::divideCeil(bitWidth, CHAR_BIT), result);
551  } else {
552  std::copy_n(rawData + (bitPos / CHAR_BIT),
553  llvm::divideCeil(bitWidth, CHAR_BIT),
554  const_cast<char *>(
555  reinterpret_cast<const char *>(result.getRawData())));
556  }
557  return result;
558 }
559 
560 /// Returns true if 'values' corresponds to a splat, i.e. one element, or has
561 /// the same element count as 'type'.
562 template <typename Values>
563 static bool hasSameElementsOrSplat(ShapedType type, const Values &values) {
564  return (values.size() == 1) ||
565  (type.getNumElements() == static_cast<int64_t>(values.size()));
566 }
567 
568 //===----------------------------------------------------------------------===//
569 // DenseElementsAttr Iterators
570 //===----------------------------------------------------------------------===//
571 
572 //===----------------------------------------------------------------------===//
573 // AttributeElementIterator
574 
575 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
576  DenseElementsAttr attr, size_t index)
577  : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
579  attr.getAsOpaquePointer(), index) {}
580 
582  auto owner = getFromOpaquePointer(base).cast<DenseElementsAttr>();
583  Type eltTy = owner.getElementType();
584  if (auto intEltTy = eltTy.dyn_cast<IntegerType>())
585  return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
586  if (eltTy.isa<IndexType>())
587  return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
588  if (auto floatEltTy = eltTy.dyn_cast<FloatType>()) {
589  IntElementIterator intIt(owner, index);
590  FloatElementIterator floatIt(floatEltTy.getFloatSemantics(), intIt);
591  return FloatAttr::get(eltTy, *floatIt);
592  }
593  if (auto complexTy = eltTy.dyn_cast<ComplexType>()) {
594  auto complexEltTy = complexTy.getElementType();
595  ComplexIntElementIterator complexIntIt(owner, index);
596  if (complexEltTy.isa<IntegerType>()) {
597  auto value = *complexIntIt;
598  auto real = IntegerAttr::get(complexEltTy, value.real());
599  auto imag = IntegerAttr::get(complexEltTy, value.imag());
600  return ArrayAttr::get(complexTy.getContext(),
601  ArrayRef<Attribute>{real, imag});
602  }
603 
604  ComplexFloatElementIterator complexFloatIt(
605  complexEltTy.cast<FloatType>().getFloatSemantics(), complexIntIt);
606  auto value = *complexFloatIt;
607  auto real = FloatAttr::get(complexEltTy, value.real());
608  auto imag = FloatAttr::get(complexEltTy, value.imag());
609  return ArrayAttr::get(complexTy.getContext(),
610  ArrayRef<Attribute>{real, imag});
611  }
612  if (owner.isa<DenseStringElementsAttr>()) {
613  ArrayRef<StringRef> vals = owner.getRawStringData();
614  return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
615  }
616  llvm_unreachable("unexpected element type");
617 }
618 
619 //===----------------------------------------------------------------------===//
620 // BoolElementIterator
621 
622 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
623  DenseElementsAttr attr, size_t dataIndex)
625  attr.getRawData().data(), attr.isSplat(), dataIndex) {}
626 
628  return getBit(getData(), getDataIndex());
629 }
630 
631 //===----------------------------------------------------------------------===//
632 // IntElementIterator
633 
634 DenseElementsAttr::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(),
642  getDataIndex() * getDenseElementStorageWidth(bitWidth),
643  bitWidth);
644 }
645 
646 //===----------------------------------------------------------------------===//
647 // ComplexIntElementIterator
648 
649 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
650  DenseElementsAttr attr, size_t dataIndex)
652  std::complex<APInt>, std::complex<APInt>,
653  std::complex<APInt>>(
654  attr.getRawData().data(), attr.isSplat(), dataIndex) {
655  auto complexType = attr.getElementType().cast<ComplexType>();
656  bitWidth = getDenseElementBitWidth(complexType.getElementType());
657 }
658 
659 std::complex<APInt>
661  size_t storageWidth = getDenseElementStorageWidth(bitWidth);
662  size_t offset = getDataIndex() * storageWidth * 2;
663  return {readBits(getData(), offset, bitWidth),
664  readBits(getData(), offset + storageWidth, bitWidth)};
665 }
666 
667 //===----------------------------------------------------------------------===//
668 // DenseElementsAttr
669 //===----------------------------------------------------------------------===//
670 
671 /// Method for support type inquiry through isa, cast and dyn_cast.
673  return attr.isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>();
674 }
675 
677  ArrayRef<Attribute> values) {
678  assert(hasSameElementsOrSplat(type, values));
679 
680  // If the element type is not based on int/float/index, assume it is a string
681  // type.
682  auto eltType = type.getElementType();
683  if (!type.getElementType().isIntOrIndexOrFloat()) {
684  SmallVector<StringRef, 8> stringValues;
685  stringValues.reserve(values.size());
686  for (Attribute attr : values) {
687  assert(attr.isa<StringAttr>() &&
688  "expected string value for non integer/index/float element");
689  stringValues.push_back(attr.cast<StringAttr>().getValue());
690  }
691  return get(type, stringValues);
692  }
693 
694  // Otherwise, get the raw storage width to use for the allocation.
695  size_t bitWidth = getDenseElementBitWidth(eltType);
696  size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
697 
698  // Compress the attribute values into a character buffer.
699  SmallVector<char, 8> data(llvm::divideCeil(storageBitWidth, CHAR_BIT) *
700  values.size());
701  APInt intVal;
702  for (unsigned i = 0, e = values.size(); i < e; ++i) {
703  assert(eltType == values[i].getType() &&
704  "expected attribute value to have element type");
705  if (eltType.isa<FloatType>())
706  intVal = values[i].cast<FloatAttr>().getValue().bitcastToAPInt();
707  else if (eltType.isa<IntegerType, IndexType>())
708  intVal = values[i].cast<IntegerAttr>().getValue();
709  else
710  llvm_unreachable("unexpected element type");
711 
712  assert(intVal.getBitWidth() == bitWidth &&
713  "expected value to have same bitwidth as element type");
714  writeBits(data.data(), i * storageBitWidth, intVal);
715  }
716  return DenseIntOrFPElementsAttr::getRaw(type, data,
717  /*isSplat=*/(values.size() == 1));
718 }
719 
721  ArrayRef<bool> values) {
722  assert(hasSameElementsOrSplat(type, values));
723  assert(type.getElementType().isInteger(1));
724 
725  std::vector<char> buff(llvm::divideCeil(values.size(), CHAR_BIT));
726  for (int i = 0, e = values.size(); i != e; ++i)
727  setBit(buff.data(), i, values[i]);
728  return DenseIntOrFPElementsAttr::getRaw(type, buff,
729  /*isSplat=*/(values.size() == 1));
730 }
731 
733  ArrayRef<StringRef> values) {
734  assert(!type.getElementType().isIntOrFloat());
735  return DenseStringElementsAttr::get(type, values);
736 }
737 
738 /// Constructs a dense integer elements attribute from an array of APInt
739 /// values. Each APInt value is expected to have the same bitwidth as the
740 /// element type of 'type'.
742  ArrayRef<APInt> values) {
743  assert(type.getElementType().isIntOrIndex());
744  assert(hasSameElementsOrSplat(type, values));
745  size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
746  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values,
747  /*isSplat=*/(values.size() == 1));
748 }
750  ArrayRef<std::complex<APInt>> values) {
751  ComplexType complex = type.getElementType().cast<ComplexType>();
752  assert(complex.getElementType().isa<IntegerType>());
753  assert(hasSameElementsOrSplat(type, values));
754  size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
755  ArrayRef<APInt> intVals(reinterpret_cast<const APInt *>(values.data()),
756  values.size() * 2);
757  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals,
758  /*isSplat=*/(values.size() == 1));
759 }
760 
761 // Constructs a dense float elements attribute from an array of APFloat
762 // values. Each APFloat value is expected to have the same bitwidth as the
763 // element type of 'type'.
765  ArrayRef<APFloat> values) {
766  assert(type.getElementType().isa<FloatType>());
767  assert(hasSameElementsOrSplat(type, values));
768  size_t storageBitWidth = getDenseElementStorageWidth(type.getElementType());
769  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values,
770  /*isSplat=*/(values.size() == 1));
771 }
773 DenseElementsAttr::get(ShapedType type,
774  ArrayRef<std::complex<APFloat>> values) {
775  ComplexType complex = type.getElementType().cast<ComplexType>();
776  assert(complex.getElementType().isa<FloatType>());
777  assert(hasSameElementsOrSplat(type, values));
778  ArrayRef<APFloat> apVals(reinterpret_cast<const APFloat *>(values.data()),
779  values.size() * 2);
780  size_t storageBitWidth = getDenseElementStorageWidth(complex) / 2;
781  return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals,
782  /*isSplat=*/(values.size() == 1));
783 }
784 
785 /// Construct a dense elements attribute from a raw buffer representing the
786 /// data for this attribute. Users should generally not use this methods as
787 /// the expected buffer format may not be a form the user expects.
789  ArrayRef<char> rawBuffer,
790  bool isSplatBuffer) {
791  return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer, isSplatBuffer);
792 }
793 
794 /// Returns true if the given buffer is a valid raw buffer for the given type.
796  ArrayRef<char> rawBuffer,
797  bool &detectedSplat) {
798  size_t storageWidth = getDenseElementStorageWidth(type.getElementType());
799  size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
800 
801  // Storage width of 1 is special as it is packed by the bit.
802  if (storageWidth == 1) {
803  // Check for a splat, or a buffer equal to the number of elements which
804  // consists of either all 0's or all 1's.
805  detectedSplat = false;
806  if (rawBuffer.size() == 1) {
807  auto rawByte = static_cast<uint8_t>(rawBuffer[0]);
808  if (rawByte == 0 || rawByte == 0xff) {
809  detectedSplat = true;
810  return true;
811  }
812  }
813  return rawBufferWidth == llvm::alignTo<8>(type.getNumElements());
814  }
815  // All other types are 8-bit aligned.
816  if ((detectedSplat = rawBufferWidth == storageWidth))
817  return true;
818  return rawBufferWidth == (storageWidth * type.getNumElements());
819 }
820 
821 /// Check the information for a C++ data type, check if this type is valid for
822 /// the current attribute. This method is used to verify specific type
823 /// invariants that the templatized 'getValues' method cannot.
824 static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt,
825  bool isSigned) {
826  // Make sure that the data element size is the same as the type element width.
827  if (getDenseElementBitWidth(type) !=
828  static_cast<size_t>(dataEltSize * CHAR_BIT))
829  return false;
830 
831  // Check that the element type is either float or integer or index.
832  if (!isInt)
833  return type.isa<FloatType>();
834  if (type.isIndex())
835  return true;
836 
837  auto intType = type.dyn_cast<IntegerType>();
838  if (!intType)
839  return false;
840 
841  // Make sure signedness semantics is consistent.
842  if (intType.isSignless())
843  return true;
844  return intType.isSigned() ? isSigned : !isSigned;
845 }
846 
847 /// Defaults down the subclass implementation.
849  ArrayRef<char> data,
850  int64_t dataEltSize,
851  bool isInt, bool isSigned) {
852  return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
853  isSigned);
854 }
856  ArrayRef<char> data,
857  int64_t dataEltSize,
858  bool isInt,
859  bool isSigned) {
860  return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
861  isInt, isSigned);
862 }
863 
864 bool DenseElementsAttr::isValidIntOrFloat(int64_t dataEltSize, bool isInt,
865  bool isSigned) const {
866  return ::isValidIntOrFloat(getElementType(), dataEltSize, isInt, isSigned);
867 }
868 bool DenseElementsAttr::isValidComplex(int64_t dataEltSize, bool isInt,
869  bool isSigned) const {
871  getElementType().cast<ComplexType>().getElementType(), dataEltSize / 2,
872  isInt, isSigned);
873 }
874 
875 /// Returns true if this attribute corresponds to a splat, i.e. if all element
876 /// values are the same.
878  return static_cast<DenseElementsAttributeStorage *>(impl)->isSplat;
879 }
880 
881 /// Return if the given complex type has an integer element type.
882 LLVM_ATTRIBUTE_UNUSED static bool isComplexOfIntType(Type type) {
883  return type.cast<ComplexType>().getElementType().isa<IntegerType>();
884 }
885 
887  -> iterator_range_impl<ComplexIntElementIterator> {
889  "expected complex integral type");
890  return {getType(), ComplexIntElementIterator(*this, 0),
891  ComplexIntElementIterator(*this, getNumElements())};
892 }
894  -> ComplexIntElementIterator {
896  "expected complex integral type");
897  return ComplexIntElementIterator(*this, 0);
898 }
899 auto DenseElementsAttr::complex_value_end() const -> ComplexIntElementIterator {
901  "expected complex integral type");
902  return ComplexIntElementIterator(*this, getNumElements());
903 }
904 
905 /// Return the held element values as a range of APFloat. The element type of
906 /// this attribute must be of float type.
909  auto elementType = getElementType().cast<FloatType>();
910  const auto &elementSemantics = elementType.getFloatSemantics();
911  return {getType(), FloatElementIterator(elementSemantics, raw_int_begin()),
912  FloatElementIterator(elementSemantics, raw_int_end())};
913 }
915  auto elementType = getElementType().cast<FloatType>();
916  return FloatElementIterator(elementType.getFloatSemantics(), raw_int_begin());
917 }
919  auto elementType = getElementType().cast<FloatType>();
920  return FloatElementIterator(elementType.getFloatSemantics(), raw_int_end());
921 }
922 
925  Type eltTy = getElementType().cast<ComplexType>().getElementType();
926  assert(eltTy.isa<FloatType>() && "expected complex float type");
927  const auto &semantics = eltTy.cast<FloatType>().getFloatSemantics();
928  return {getType(),
929  {semantics, {*this, 0}},
930  {semantics, {*this, static_cast<size_t>(getNumElements())}}};
931 }
934  Type eltTy = getElementType().cast<ComplexType>().getElementType();
935  assert(eltTy.isa<FloatType>() && "expected complex float type");
936  return {eltTy.cast<FloatType>().getFloatSemantics(), {*this, 0}};
937 }
940  Type eltTy = getElementType().cast<ComplexType>().getElementType();
941  assert(eltTy.isa<FloatType>() && "expected complex float type");
942  return {eltTy.cast<FloatType>().getFloatSemantics(),
943  {*this, static_cast<size_t>(getNumElements())}};
944 }
945 
946 /// Return the raw storage data held by this attribute.
948  return static_cast<DenseIntOrFPElementsAttrStorage *>(impl)->data;
949 }
950 
952  return static_cast<DenseStringElementsAttrStorage *>(impl)->data;
953 }
954 
955 /// Return a new DenseElementsAttr that has the same data as the current
956 /// attribute, but has been reshaped to 'newType'. The new type must have the
957 /// same total number of elements as well as element type.
959  ShapedType curType = getType();
960  if (curType == newType)
961  return *this;
962 
963  assert(newType.getElementType() == curType.getElementType() &&
964  "expected the same element type");
965  assert(newType.getNumElements() == curType.getNumElements() &&
966  "expected the same number of elements");
967  return DenseIntOrFPElementsAttr::getRaw(newType, getRawData(), isSplat());
968 }
969 
970 /// Return a new DenseElementsAttr that has the same data as the current
971 /// attribute, but has bitcast elements such that it is now 'newType'. The new
972 /// type must have the same shape and element types of the same bitwidth as the
973 /// current type.
975  ShapedType curType = getType();
976  Type curElType = curType.getElementType();
977  if (curElType == newElType)
978  return *this;
979 
980  assert(getDenseElementBitWidth(newElType) ==
981  getDenseElementBitWidth(curElType) &&
982  "expected element types with the same bitwidth");
983  return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
984  getRawData(), isSplat());
985 }
986 
989  function_ref<APInt(const APInt &)> mapping) const {
990  return cast<DenseIntElementsAttr>().mapValues(newElementType, mapping);
991 }
992 
994  Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
995  return cast<DenseFPElementsAttr>().mapValues(newElementType, mapping);
996 }
997 
998 ShapedType DenseElementsAttr::getType() const {
999  return Attribute::getType().cast<ShapedType>();
1000 }
1001 
1003  return getType().getElementType();
1004 }
1005 
1007  return getType().getNumElements();
1008 }
1009 
1010 //===----------------------------------------------------------------------===//
1011 // DenseIntOrFPElementsAttr
1012 //===----------------------------------------------------------------------===//
1013 
1014 /// Utility method to write a range of APInt values to a buffer.
1015 template <typename APRangeT>
1016 static void writeAPIntsToBuffer(size_t storageWidth, std::vector<char> &data,
1017  APRangeT &&values) {
1018  data.resize(llvm::divideCeil(storageWidth, CHAR_BIT) * llvm::size(values));
1019  size_t offset = 0;
1020  for (auto it = values.begin(), e = values.end(); it != e;
1021  ++it, offset += storageWidth) {
1022  assert((*it).getBitWidth() <= storageWidth);
1023  writeBits(data.data(), offset, *it);
1024  }
1025 }
1026 
1027 /// Constructs a dense elements attribute from an array of raw APFloat values.
1028 /// Each APFloat value is expected to have the same bitwidth as the element
1029 /// type of 'type'. 'type' must be a vector or tensor with static shape.
1030 DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1031  size_t storageWidth,
1032  ArrayRef<APFloat> values,
1033  bool isSplat) {
1034  std::vector<char> data;
1035  auto unwrapFloat = [](const APFloat &val) { return val.bitcastToAPInt(); };
1036  writeAPIntsToBuffer(storageWidth, data, llvm::map_range(values, unwrapFloat));
1037  return DenseIntOrFPElementsAttr::getRaw(type, data, isSplat);
1038 }
1039 
1040 /// Constructs a dense elements attribute from an array of raw APInt values.
1041 /// Each APInt value is expected to have the same bitwidth as the element type
1042 /// of 'type'.
1043 DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1044  size_t storageWidth,
1045  ArrayRef<APInt> values,
1046  bool isSplat) {
1047  std::vector<char> data;
1048  writeAPIntsToBuffer(storageWidth, data, values);
1049  return DenseIntOrFPElementsAttr::getRaw(type, data, isSplat);
1050 }
1051 
1052 DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1053  ArrayRef<char> data,
1054  bool isSplat) {
1055  assert((type.isa<RankedTensorType, VectorType>()) &&
1056  "type must be ranked tensor or vector");
1057  assert(type.hasStaticShape() && "type must have static shape");
1058  return Base::get(type.getContext(), type, data, isSplat);
1059 }
1060 
1061 /// Overload of the raw 'get' method that asserts that the given type is of
1062 /// complex type. This method is used to verify type invariants that the
1063 /// templatized 'get' method cannot.
1064 DenseElementsAttr DenseIntOrFPElementsAttr::getRawComplex(ShapedType type,
1065  ArrayRef<char> data,
1066  int64_t dataEltSize,
1067  bool isInt,
1068  bool isSigned) {
1069  assert(::isValidIntOrFloat(
1070  type.getElementType().cast<ComplexType>().getElementType(),
1071  dataEltSize / 2, isInt, isSigned));
1072 
1073  int64_t numElements = data.size() / dataEltSize;
1074  assert(numElements == 1 || numElements == type.getNumElements());
1075  return getRaw(type, data, /*isSplat=*/numElements == 1);
1076 }
1077 
1078 /// Overload of the 'getRaw' method that asserts that the given type is of
1079 /// integer type. This method is used to verify type invariants that the
1080 /// templatized 'get' method cannot.
1082 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
1083  int64_t dataEltSize, bool isInt,
1084  bool isSigned) {
1085  assert(
1086  ::isValidIntOrFloat(type.getElementType(), dataEltSize, isInt, isSigned));
1087 
1088  int64_t numElements = data.size() / dataEltSize;
1089  assert(numElements == 1 || numElements == type.getNumElements());
1090  return getRaw(type, data, /*isSplat=*/numElements == 1);
1091 }
1092 
1093 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1094  const char *inRawData, char *outRawData, size_t elementBitWidth,
1095  size_t numElements) {
1096  using llvm::support::ulittle16_t;
1097  using llvm::support::ulittle32_t;
1098  using llvm::support::ulittle64_t;
1099 
1100  assert(llvm::support::endian::system_endianness() == // NOLINT
1101  llvm::support::endianness::big); // NOLINT
1102  // NOLINT to avoid warning message about replacing by static_assert()
1103 
1104  // Following std::copy_n always converts endianness on BE machine.
1105  switch (elementBitWidth) {
1106  case 16: {
1107  const ulittle16_t *inRawDataPos =
1108  reinterpret_cast<const ulittle16_t *>(inRawData);
1109  uint16_t *outDataPos = reinterpret_cast<uint16_t *>(outRawData);
1110  std::copy_n(inRawDataPos, numElements, outDataPos);
1111  break;
1112  }
1113  case 32: {
1114  const ulittle32_t *inRawDataPos =
1115  reinterpret_cast<const ulittle32_t *>(inRawData);
1116  uint32_t *outDataPos = reinterpret_cast<uint32_t *>(outRawData);
1117  std::copy_n(inRawDataPos, numElements, outDataPos);
1118  break;
1119  }
1120  case 64: {
1121  const ulittle64_t *inRawDataPos =
1122  reinterpret_cast<const ulittle64_t *>(inRawData);
1123  uint64_t *outDataPos = reinterpret_cast<uint64_t *>(outRawData);
1124  std::copy_n(inRawDataPos, numElements, outDataPos);
1125  break;
1126  }
1127  default: {
1128  size_t nBytes = elementBitWidth / CHAR_BIT;
1129  for (size_t i = 0; i < nBytes; i++)
1130  std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1131  break;
1132  }
1133  }
1134 }
1135 
1136 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1137  ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1138  ShapedType type) {
1139  size_t numElements = type.getNumElements();
1140  Type elementType = type.getElementType();
1141  if (ComplexType complexTy = elementType.dyn_cast<ComplexType>()) {
1142  elementType = complexTy.getElementType();
1143  numElements = numElements * 2;
1144  }
1145  size_t elementBitWidth = getDenseElementStorageWidth(elementType);
1146  assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1147  inRawData.size() <= outRawData.size());
1148  convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1149  elementBitWidth, numElements);
1150 }
1151 
1152 //===----------------------------------------------------------------------===//
1153 // DenseFPElementsAttr
1154 //===----------------------------------------------------------------------===//
1155 
1156 template <typename Fn, typename Attr>
1157 static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType,
1158  Type newElementType,
1160  size_t bitWidth = getDenseElementBitWidth(newElementType);
1161  size_t storageBitWidth = getDenseElementStorageWidth(bitWidth);
1162 
1163  ShapedType newArrayType;
1164  if (inType.isa<RankedTensorType>())
1165  newArrayType = RankedTensorType::get(inType.getShape(), newElementType);
1166  else if (inType.isa<UnrankedTensorType>())
1167  newArrayType = RankedTensorType::get(inType.getShape(), newElementType);
1168  else if (auto vType = inType.dyn_cast<VectorType>())
1169  newArrayType = VectorType::get(vType.getShape(), newElementType,
1170  vType.getNumScalableDims());
1171  else
1172  assert(newArrayType && "Unhandled tensor type");
1173 
1174  size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1175  data.resize(llvm::divideCeil(storageBitWidth, CHAR_BIT) * numRawElements);
1176 
1177  // Functor used to process a single element value of the attribute.
1178  auto processElt = [&](decltype(*attr.begin()) value, size_t index) {
1179  auto newInt = mapping(value);
1180  assert(newInt.getBitWidth() == bitWidth);
1181  writeBits(data.data(), index * storageBitWidth, newInt);
1182  };
1183 
1184  // Check for the splat case.
1185  if (attr.isSplat()) {
1186  processElt(*attr.begin(), /*index=*/0);
1187  return newArrayType;
1188  }
1189 
1190  // Otherwise, process all of the element values.
1191  uint64_t elementIdx = 0;
1192  for (auto value : attr)
1193  processElt(value, elementIdx++);
1194  return newArrayType;
1195 }
1196 
1198  Type newElementType, function_ref<APInt(const APFloat &)> mapping) const {
1199  llvm::SmallVector<char, 8> elementData;
1200  auto newArrayType =
1201  mappingHelper(mapping, *this, getType(), newElementType, elementData);
1202 
1203  return getRaw(newArrayType, elementData, isSplat());
1204 }
1205 
1206 /// Method for supporting type inquiry through isa, cast and dyn_cast.
1208  return attr.isa<DenseElementsAttr>() &&
1209  attr.getType().cast<ShapedType>().getElementType().isa<FloatType>();
1210 }
1211 
1212 //===----------------------------------------------------------------------===//
1213 // DenseIntElementsAttr
1214 //===----------------------------------------------------------------------===//
1215 
1217  Type newElementType, function_ref<APInt(const APInt &)> mapping) const {
1218  llvm::SmallVector<char, 8> elementData;
1219  auto newArrayType =
1220  mappingHelper(mapping, *this, getType(), newElementType, elementData);
1221 
1222  return getRaw(newArrayType, elementData, isSplat());
1223 }
1224 
1225 /// Method for supporting type inquiry through isa, cast and dyn_cast.
1227  return attr.isa<DenseElementsAttr>() &&
1228  attr.getType().cast<ShapedType>().getElementType().isIntOrIndex();
1229 }
1230 
1231 //===----------------------------------------------------------------------===//
1232 // OpaqueElementsAttr
1233 //===----------------------------------------------------------------------===//
1234 
1235 bool OpaqueElementsAttr::decode(ElementsAttr &result) {
1236  Dialect *dialect = getContext()->getLoadedDialect(getDialect());
1237  if (!dialect)
1238  return true;
1239  auto *interface =
1240  dialect->getRegisteredInterface<DialectDecodeAttributesInterface>();
1241  if (!interface)
1242  return true;
1243  return failed(interface->decode(*this, result));
1244 }
1245 
1248  StringAttr dialect, StringRef value,
1249  ShapedType type) {
1250  if (!Dialect::isValidNamespace(dialect.strref()))
1251  return emitError() << "invalid dialect namespace '" << dialect << "'";
1252  return success();
1253 }
1254 
1255 //===----------------------------------------------------------------------===//
1256 // SparseElementsAttr
1257 //===----------------------------------------------------------------------===//
1258 
1259 /// Get a zero APFloat for the given sparse attribute.
1260 APFloat SparseElementsAttr::getZeroAPFloat() const {
1261  auto eltType = getElementType().cast<FloatType>();
1262  return APFloat(eltType.getFloatSemantics());
1263 }
1264 
1265 /// Get a zero APInt for the given sparse attribute.
1266 APInt SparseElementsAttr::getZeroAPInt() const {
1267  auto eltType = getElementType().cast<IntegerType>();
1268  return APInt::getZero(eltType.getWidth());
1269 }
1270 
1271 /// Get a zero attribute for the given attribute type.
1272 Attribute SparseElementsAttr::getZeroAttr() const {
1273  auto eltType = getElementType();
1274 
1275  // Handle floating point elements.
1276  if (eltType.isa<FloatType>())
1277  return FloatAttr::get(eltType, 0);
1278 
1279  // Handle string type.
1280  if (getValues().isa<DenseStringElementsAttr>())
1281  return StringAttr::get("", eltType);
1282 
1283  // Otherwise, this is an integer.
1284  return IntegerAttr::get(eltType, 0);
1285 }
1286 
1287 /// Flatten, and return, all of the sparse indices in this attribute in
1288 /// row-major order.
1289 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices() const {
1290  std::vector<ptrdiff_t> flatSparseIndices;
1291 
1292  // The sparse indices are 64-bit integers, so we can reinterpret the raw data
1293  // as a 1-D index array.
1294  auto sparseIndices = getIndices();
1295  auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1296  if (sparseIndices.isSplat()) {
1297  SmallVector<uint64_t, 8> indices(getType().getRank(),
1298  *sparseIndexValues.begin());
1299  flatSparseIndices.push_back(getFlattenedIndex(indices));
1300  return flatSparseIndices;
1301  }
1302 
1303  // Otherwise, reinterpret each index as an ArrayRef when flattening.
1304  auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1305  size_t rank = getType().getRank();
1306  for (size_t i = 0, e = numSparseIndices; i != e; ++i)
1307  flatSparseIndices.push_back(getFlattenedIndex(
1308  {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1309  return flatSparseIndices;
1310 }
1311 
1314  ShapedType type, DenseIntElementsAttr sparseIndices,
1315  DenseElementsAttr values) {
1316  ShapedType valuesType = values.getType();
1317  if (valuesType.getRank() != 1)
1318  return emitError() << "expected 1-d tensor for sparse element values";
1319 
1320  // Verify the indices and values shape.
1321  ShapedType indicesType = sparseIndices.getType();
1322  auto emitShapeError = [&]() {
1323  return emitError() << "expected shape ([" << type.getShape()
1324  << "]); inferred shape of indices literal (["
1325  << indicesType.getShape()
1326  << "]); inferred shape of values literal (["
1327  << valuesType.getShape() << "])";
1328  };
1329  // Verify indices shape.
1330  size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1331  if (indicesRank == 2) {
1332  if (indicesType.getDimSize(1) != static_cast<int64_t>(rank))
1333  return emitShapeError();
1334  } else if (indicesRank != 1 || rank != 1) {
1335  return emitShapeError();
1336  }
1337  // Verify the values shape.
1338  int64_t numSparseIndices = indicesType.getDimSize(0);
1339  if (numSparseIndices != valuesType.getDimSize(0))
1340  return emitShapeError();
1341 
1342  // Verify that the sparse indices are within the value shape.
1343  auto emitIndexError = [&](unsigned indexNum, ArrayRef<uint64_t> index) {
1344  return emitError()
1345  << "sparse index #" << indexNum
1346  << " is not contained within the value shape, with index=[" << index
1347  << "], and type=" << type;
1348  };
1349 
1350  // Handle the case where the index values are a splat.
1351  auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1352  if (sparseIndices.isSplat()) {
1353  SmallVector<uint64_t> indices(rank, *sparseIndexValues.begin());
1354  if (!ElementsAttr::isValidIndex(type, indices))
1355  return emitIndexError(0, indices);
1356  return success();
1357  }
1358 
1359  // Otherwise, reinterpret each index as an ArrayRef.
1360  for (size_t i = 0, e = numSparseIndices; i != e; ++i) {
1361  ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1362  rank);
1363  if (!ElementsAttr::isValidIndex(type, index))
1364  return emitIndexError(i, index);
1365  }
1366 
1367  return success();
1368 }
1369 
1370 //===----------------------------------------------------------------------===//
1371 // TypeAttr
1372 //===----------------------------------------------------------------------===//
1373 
1374 void TypeAttr::walkImmediateSubElements(
1375  function_ref<void(Attribute)> walkAttrsFn,
1376  function_ref<void(Type)> walkTypesFn) const {
1377  walkTypesFn(getValue());
1378 }
Include the generated interface declarations.
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Definition: SymbolTable.h:55
U cast() const
Definition: Attributes.h:123
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
ComplexFloatElementIterator complex_float_value_end() const
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:301
std::complex< APInt > operator*() const
Accesses the raw std::complex<APInt> value at this iterator position.
A symbol reference with a reference path containing a single element.
DenseElementsAttr reshape(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has been reshaped...
const void * getAsOpaquePointer() const
Get an opaque pointer to the attribute.
Definition: Attributes.h:79
ComplexIntElementIterator complex_value_begin() const
A utility iterator that allows walking over the internal raw APInt values.
AttrClass getAttrOfType(StringAttr name)
Definition: Operation.h:327
LogicalResult verify(Operation *op)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs, on this operation and any nested operations.
Definition: Verifier.cpp:353
bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const
bool isa() const
Definition: Attributes.h:107
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
Attribute operator*() const
Accesses the Attribute value at this iterator position.
static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType, Type newElementType, llvm::SmallVectorImpl< char > &data)
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes, char *result)
Copy actual numBytes data from value (APInt) to char array(result) for BE format. ...
A utility iterator that allows walking over the internal raw complex APInt values.
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:639
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape...
iterator_range_impl< ComplexFloatElementIterator > getComplexFloatValues() const
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 bool classof(Attribute attr)
Methods for support type inquiry through isa, cast, and dyn_cast.
static constexpr const bool value
const llvm::fltSemantics & getFloatSemantics()
Return the floating semantics of this float type.
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:137
static bool hasSameElementsOrSplat(ShapedType type, const Values &values)
Returns true if &#39;values&#39; corresponds to a splat, i.e.
static size_t getDenseElementStorageWidth(size_t origWidth)
Get the bitwidth of a dense element type within the buffer.
bool getValue() const
Return the boolean value of this attribute.
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.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
static void setBit(char *rawData, size_t bitPos, bool value)
Set a bit to a specific value.
An attribute representing a reference to a dense vector or tensor object containing strings...
static void writeBits(char *rawData, size_t bitPos, APInt value)
Writes value to the bit position bitPos in array rawData.
Type getElementType() const
Return the element type of this DenseElementsAttr.
An attribute that represents a reference to a dense vector or tensor object.
static bool contains(llvm::SMRange range, llvm::SMLoc loc)
Returns true if the given range contains the given source location.
Definition: MLIRServer.cpp:118
U dyn_cast() const
Definition: Types.h:244
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
Attributes are known-constant values of operations.
Definition: Attributes.h:24
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
Iterator for walking over APFloat values.
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.
An attribute representing a reference to a dense vector or tensor object.
StringAttr getName() const
Return the name of the attribute.
Definition: Attributes.cpp:32
DenseElementsAttr bitcast(Type newElType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has bitcast eleme...
bool isIndex() const
Definition: Types.cpp:28
An attribute representing a reference to a dense vector or tensor object.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:42
static DenseElementsAttr getRawIntOrFloat(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw &#39;get&#39; method that asserts that the given type is of integer or floating-point typ...
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.
static bool classof(Attribute attr)
Method for support type inquiry through isa, cast and dyn_cast.
static bool getBit(const char *rawData, size_t bitPos)
Return the value of the specified bit.
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:72
static LLVM_ATTRIBUTE_UNUSED bool isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
bool operator*() const
Accesses the bool value at this iterator position.
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:19
static Optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
static void writeAPIntsToBuffer(size_t storageWidth, std::vector< char > &data, APRangeT &&values)
Utility method to write a range of APInt values to a buffer.
FloatElementIterator float_value_end() const
Type getType() const
Return the type of this attribute.
Definition: Attributes.h:64
iterator_range_impl< FloatElementIterator > getFloatValues() const
Return the held element values as a range of APFloat.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
U dyn_cast() const
Definition: Attributes.h:117
static int64_t getNumElements(ShapedType type)
Definition: TensorOps.cpp:678
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:55
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
int64_t getNumElements() const
Returns the number of elements held by this attribute.
iterator_range_impl< ComplexIntElementIterator > getComplexIntValues() const
bool isIntOrIndex() const
Return true if this is an integer (of any signedness) or an index type.
Definition: Types.cpp:85
This class provides iterator utilities for an ElementsAttr range.
ComplexFloatElementIterator complex_float_value_begin() const
APInt operator*() const
Accesses the raw APInt value at this iterator position.
static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw &#39;get&#39; method that asserts that the given type is of complex type.
bool isa() const
Definition: Types.h:234
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
Iterator for walking over complex APFloat values.
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...
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...
ArrayRef< StringRef > getRawStringData() const
Return the raw StringRef data held by this attribute.
FloatElementIterator float_value_begin() const
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
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 DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer, bool isSplatBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute...
An attribute that represents a reference to a dense integer vector or tensor object.
U cast() const
Definition: Types.h:250
ComplexIntElementIterator complex_value_end() const
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 isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
Definition: Dialect.cpp:182