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