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