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