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