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