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