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