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