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