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