1 //===- Attributes.cpp - MLIR Affine Expr 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/Attributes.h" 10 #include "AttributeDetail.h" 11 #include "mlir/IR/AffineMap.h" 12 #include "mlir/IR/Diagnostics.h" 13 #include "mlir/IR/Dialect.h" 14 #include "mlir/IR/Function.h" 15 #include "mlir/IR/IntegerSet.h" 16 #include "mlir/IR/Types.h" 17 #include "llvm/ADT/Sequence.h" 18 #include "llvm/ADT/Twine.h" 19 20 using namespace mlir; 21 using namespace mlir::detail; 22 23 //===----------------------------------------------------------------------===// 24 // AttributeStorage 25 //===----------------------------------------------------------------------===// 26 27 AttributeStorage::AttributeStorage(Type type) 28 : type(type.getAsOpaquePointer()) {} 29 AttributeStorage::AttributeStorage() : type(nullptr) {} 30 31 Type AttributeStorage::getType() const { 32 return Type::getFromOpaquePointer(type); 33 } 34 void AttributeStorage::setType(Type newType) { 35 type = newType.getAsOpaquePointer(); 36 } 37 38 //===----------------------------------------------------------------------===// 39 // Attribute 40 //===----------------------------------------------------------------------===// 41 42 /// Return the type of this attribute. 43 Type Attribute::getType() const { return impl->getType(); } 44 45 /// Return the context this attribute belongs to. 46 MLIRContext *Attribute::getContext() const { return getType().getContext(); } 47 48 /// Get the dialect this attribute is registered to. 49 Dialect &Attribute::getDialect() const { return impl->getDialect(); } 50 51 //===----------------------------------------------------------------------===// 52 // AffineMapAttr 53 //===----------------------------------------------------------------------===// 54 55 AffineMapAttr AffineMapAttr::get(AffineMap value) { 56 return Base::get(value.getContext(), StandardAttributes::AffineMap, value); 57 } 58 59 AffineMap AffineMapAttr::getValue() const { return getImpl()->value; } 60 61 //===----------------------------------------------------------------------===// 62 // ArrayAttr 63 //===----------------------------------------------------------------------===// 64 65 ArrayAttr ArrayAttr::get(ArrayRef<Attribute> value, MLIRContext *context) { 66 return Base::get(context, StandardAttributes::Array, value); 67 } 68 69 ArrayRef<Attribute> ArrayAttr::getValue() const { return getImpl()->value; } 70 71 Attribute ArrayAttr::operator[](unsigned idx) const { 72 assert(idx < size() && "index out of bounds"); 73 return getValue()[idx]; 74 } 75 76 //===----------------------------------------------------------------------===// 77 // BoolAttr 78 //===----------------------------------------------------------------------===// 79 80 bool BoolAttr::getValue() const { return getImpl()->value; } 81 82 //===----------------------------------------------------------------------===// 83 // DictionaryAttr 84 //===----------------------------------------------------------------------===// 85 86 /// Perform a three-way comparison between the names of the specified 87 /// NamedAttributes. 88 static int compareNamedAttributes(const NamedAttribute *lhs, 89 const NamedAttribute *rhs) { 90 return strcmp(lhs->first.data(), rhs->first.data()); 91 } 92 93 DictionaryAttr DictionaryAttr::get(ArrayRef<NamedAttribute> value, 94 MLIRContext *context) { 95 assert(llvm::all_of(value, 96 [](const NamedAttribute &attr) { return attr.second; }) && 97 "value cannot have null entries"); 98 99 // We need to sort the element list to canonicalize it, but we also don't want 100 // to do a ton of work in the super common case where the element list is 101 // already sorted. 102 SmallVector<NamedAttribute, 8> storage; 103 switch (value.size()) { 104 case 0: 105 break; 106 case 1: 107 // A single element is already sorted. 108 break; 109 case 2: 110 assert(value[0].first != value[1].first && 111 "DictionaryAttr element names must be unique"); 112 113 // Don't invoke a general sort for two element case. 114 if (compareNamedAttributes(&value[0], &value[1]) > 0) { 115 storage.push_back(value[1]); 116 storage.push_back(value[0]); 117 value = storage; 118 } 119 break; 120 default: 121 // Check to see they are sorted already. 122 bool isSorted = true; 123 for (unsigned i = 0, e = value.size() - 1; i != e; ++i) { 124 if (compareNamedAttributes(&value[i], &value[i + 1]) > 0) { 125 isSorted = false; 126 break; 127 } 128 } 129 // If not, do a general sort. 130 if (!isSorted) { 131 storage.append(value.begin(), value.end()); 132 llvm::array_pod_sort(storage.begin(), storage.end(), 133 compareNamedAttributes); 134 value = storage; 135 } 136 137 // Ensure that the attribute elements are unique. 138 assert(std::adjacent_find(value.begin(), value.end(), 139 [](NamedAttribute l, NamedAttribute r) { 140 return l.first == r.first; 141 }) == value.end() && 142 "DictionaryAttr element names must be unique"); 143 } 144 145 return Base::get(context, StandardAttributes::Dictionary, value); 146 } 147 148 ArrayRef<NamedAttribute> DictionaryAttr::getValue() const { 149 return getImpl()->getElements(); 150 } 151 152 /// Return the specified attribute if present, null otherwise. 153 Attribute DictionaryAttr::get(StringRef name) const { 154 ArrayRef<NamedAttribute> values = getValue(); 155 auto compare = [](NamedAttribute attr, StringRef name) -> bool { 156 // This is correct even when attr.first.data()[name.size()] is not a zero 157 // string terminator, because we only care about a less than comparison. 158 // This can't use memcmp, because it doesn't guarantee that it will stop 159 // reading both buffers if one is shorter than the other, even if there is 160 // a difference. 161 return strncmp(attr.first.data(), name.data(), name.size()) < 0; 162 }; 163 auto it = llvm::lower_bound(values, name, compare); 164 return it != values.end() && it->first == name ? it->second : Attribute(); 165 } 166 Attribute DictionaryAttr::get(Identifier name) const { 167 for (auto elt : getValue()) 168 if (elt.first == name) 169 return elt.second; 170 return nullptr; 171 } 172 173 DictionaryAttr::iterator DictionaryAttr::begin() const { 174 return getValue().begin(); 175 } 176 DictionaryAttr::iterator DictionaryAttr::end() const { 177 return getValue().end(); 178 } 179 size_t DictionaryAttr::size() const { return getValue().size(); } 180 181 //===----------------------------------------------------------------------===// 182 // FloatAttr 183 //===----------------------------------------------------------------------===// 184 185 FloatAttr FloatAttr::get(Type type, double value) { 186 return Base::get(type.getContext(), StandardAttributes::Float, type, value); 187 } 188 189 FloatAttr FloatAttr::getChecked(Type type, double value, Location loc) { 190 return Base::getChecked(loc, StandardAttributes::Float, type, value); 191 } 192 193 FloatAttr FloatAttr::get(Type type, const APFloat &value) { 194 return Base::get(type.getContext(), StandardAttributes::Float, type, value); 195 } 196 197 FloatAttr FloatAttr::getChecked(Type type, const APFloat &value, Location loc) { 198 return Base::getChecked(loc, StandardAttributes::Float, type, value); 199 } 200 201 APFloat FloatAttr::getValue() const { return getImpl()->getValue(); } 202 203 double FloatAttr::getValueAsDouble() const { 204 return getValueAsDouble(getValue()); 205 } 206 double FloatAttr::getValueAsDouble(APFloat value) { 207 if (&value.getSemantics() != &APFloat::IEEEdouble()) { 208 bool losesInfo = false; 209 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, 210 &losesInfo); 211 } 212 return value.convertToDouble(); 213 } 214 215 /// Verify construction invariants. 216 static LogicalResult verifyFloatTypeInvariants(Location loc, Type type) { 217 if (!type.isa<FloatType>()) 218 return emitError(loc, "expected floating point type"); 219 return success(); 220 } 221 222 LogicalResult FloatAttr::verifyConstructionInvariants(Location loc, Type type, 223 double value) { 224 return verifyFloatTypeInvariants(loc, type); 225 } 226 227 LogicalResult FloatAttr::verifyConstructionInvariants(Location loc, Type type, 228 const APFloat &value) { 229 // Verify that the type is correct. 230 if (failed(verifyFloatTypeInvariants(loc, type))) 231 return failure(); 232 233 // Verify that the type semantics match that of the value. 234 if (&type.cast<FloatType>().getFloatSemantics() != &value.getSemantics()) { 235 return emitError( 236 loc, "FloatAttr type doesn't match the type implied by its value"); 237 } 238 return success(); 239 } 240 241 //===----------------------------------------------------------------------===// 242 // SymbolRefAttr 243 //===----------------------------------------------------------------------===// 244 245 FlatSymbolRefAttr SymbolRefAttr::get(StringRef value, MLIRContext *ctx) { 246 return Base::get(ctx, StandardAttributes::SymbolRef, value, llvm::None) 247 .cast<FlatSymbolRefAttr>(); 248 } 249 250 SymbolRefAttr SymbolRefAttr::get(StringRef value, 251 ArrayRef<FlatSymbolRefAttr> nestedReferences, 252 MLIRContext *ctx) { 253 return Base::get(ctx, StandardAttributes::SymbolRef, value, nestedReferences); 254 } 255 256 StringRef SymbolRefAttr::getRootReference() const { return getImpl()->value; } 257 258 StringRef SymbolRefAttr::getLeafReference() const { 259 ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences(); 260 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getValue(); 261 } 262 263 ArrayRef<FlatSymbolRefAttr> SymbolRefAttr::getNestedReferences() const { 264 return getImpl()->getNestedRefs(); 265 } 266 267 //===----------------------------------------------------------------------===// 268 // IntegerAttr 269 //===----------------------------------------------------------------------===// 270 271 IntegerAttr IntegerAttr::get(Type type, const APInt &value) { 272 return Base::get(type.getContext(), StandardAttributes::Integer, type, value); 273 } 274 275 IntegerAttr IntegerAttr::get(Type type, int64_t value) { 276 // This uses 64 bit APInts by default for index type. 277 if (type.isIndex()) 278 return get(type, APInt(64, value)); 279 280 auto intType = type.cast<IntegerType>(); 281 return get(type, APInt(intType.getWidth(), value, intType.isSignedInteger())); 282 } 283 284 APInt IntegerAttr::getValue() const { return getImpl()->getValue(); } 285 286 int64_t IntegerAttr::getInt() const { 287 assert((getImpl()->getType().isIndex() || 288 getImpl()->getType().isSignlessInteger()) && 289 "must be signless integer"); 290 return getValue().getSExtValue(); 291 } 292 293 int64_t IntegerAttr::getSInt() const { 294 assert(getImpl()->getType().isSignedInteger() && "must be signed integer"); 295 return getValue().getSExtValue(); 296 } 297 298 uint64_t IntegerAttr::getUInt() const { 299 assert(getImpl()->getType().isUnsignedInteger() && 300 "must be unsigned integer"); 301 return getValue().getZExtValue(); 302 } 303 304 static LogicalResult verifyIntegerTypeInvariants(Location loc, Type type) { 305 if (type.isa<IntegerType>() || type.isa<IndexType>()) 306 return success(); 307 return emitError(loc, "expected integer or index type"); 308 } 309 310 LogicalResult IntegerAttr::verifyConstructionInvariants(Location loc, Type type, 311 int64_t value) { 312 return verifyIntegerTypeInvariants(loc, type); 313 } 314 315 LogicalResult IntegerAttr::verifyConstructionInvariants(Location loc, Type type, 316 const APInt &value) { 317 if (failed(verifyIntegerTypeInvariants(loc, type))) 318 return failure(); 319 if (auto integerType = type.dyn_cast<IntegerType>()) 320 if (integerType.getWidth() != value.getBitWidth()) 321 return emitError(loc, "integer type bit width (") 322 << integerType.getWidth() << ") doesn't match value bit width (" 323 << value.getBitWidth() << ")"; 324 return success(); 325 } 326 327 //===----------------------------------------------------------------------===// 328 // IntegerSetAttr 329 //===----------------------------------------------------------------------===// 330 331 IntegerSetAttr IntegerSetAttr::get(IntegerSet value) { 332 return Base::get(value.getConstraint(0).getContext(), 333 StandardAttributes::IntegerSet, value); 334 } 335 336 IntegerSet IntegerSetAttr::getValue() const { return getImpl()->value; } 337 338 //===----------------------------------------------------------------------===// 339 // OpaqueAttr 340 //===----------------------------------------------------------------------===// 341 342 OpaqueAttr OpaqueAttr::get(Identifier dialect, StringRef attrData, Type type, 343 MLIRContext *context) { 344 return Base::get(context, StandardAttributes::Opaque, dialect, attrData, 345 type); 346 } 347 348 OpaqueAttr OpaqueAttr::getChecked(Identifier dialect, StringRef attrData, 349 Type type, Location location) { 350 return Base::getChecked(location, StandardAttributes::Opaque, dialect, 351 attrData, type); 352 } 353 354 /// Returns the dialect namespace of the opaque attribute. 355 Identifier OpaqueAttr::getDialectNamespace() const { 356 return getImpl()->dialectNamespace; 357 } 358 359 /// Returns the raw attribute data of the opaque attribute. 360 StringRef OpaqueAttr::getAttrData() const { return getImpl()->attrData; } 361 362 /// Verify the construction of an opaque attribute. 363 LogicalResult OpaqueAttr::verifyConstructionInvariants(Location loc, 364 Identifier dialect, 365 StringRef attrData, 366 Type type) { 367 if (!Dialect::isValidNamespace(dialect.strref())) 368 return emitError(loc, "invalid dialect namespace '") << dialect << "'"; 369 return success(); 370 } 371 372 //===----------------------------------------------------------------------===// 373 // StringAttr 374 //===----------------------------------------------------------------------===// 375 376 StringAttr StringAttr::get(StringRef bytes, MLIRContext *context) { 377 return get(bytes, NoneType::get(context)); 378 } 379 380 /// Get an instance of a StringAttr with the given string and Type. 381 StringAttr StringAttr::get(StringRef bytes, Type type) { 382 return Base::get(type.getContext(), StandardAttributes::String, bytes, type); 383 } 384 385 StringRef StringAttr::getValue() const { return getImpl()->value; } 386 387 //===----------------------------------------------------------------------===// 388 // TypeAttr 389 //===----------------------------------------------------------------------===// 390 391 TypeAttr TypeAttr::get(Type value) { 392 return Base::get(value.getContext(), StandardAttributes::Type, value); 393 } 394 395 Type TypeAttr::getValue() const { return getImpl()->value; } 396 397 //===----------------------------------------------------------------------===// 398 // ElementsAttr 399 //===----------------------------------------------------------------------===// 400 401 ShapedType ElementsAttr::getType() const { 402 return Attribute::getType().cast<ShapedType>(); 403 } 404 405 /// Returns the number of elements held by this attribute. 406 int64_t ElementsAttr::getNumElements() const { 407 return getType().getNumElements(); 408 } 409 410 /// Return the value at the given index. If index does not refer to a valid 411 /// element, then a null attribute is returned. 412 Attribute ElementsAttr::getValue(ArrayRef<uint64_t> index) const { 413 switch (getKind()) { 414 case StandardAttributes::DenseElements: 415 return cast<DenseElementsAttr>().getValue(index); 416 case StandardAttributes::OpaqueElements: 417 return cast<OpaqueElementsAttr>().getValue(index); 418 case StandardAttributes::SparseElements: 419 return cast<SparseElementsAttr>().getValue(index); 420 default: 421 llvm_unreachable("unknown ElementsAttr kind"); 422 } 423 } 424 425 /// Return if the given 'index' refers to a valid element in this attribute. 426 bool ElementsAttr::isValidIndex(ArrayRef<uint64_t> index) const { 427 auto type = getType(); 428 429 // Verify that the rank of the indices matches the held type. 430 auto rank = type.getRank(); 431 if (rank != static_cast<int64_t>(index.size())) 432 return false; 433 434 // Verify that all of the indices are within the shape dimensions. 435 auto shape = type.getShape(); 436 return llvm::all_of(llvm::seq<int>(0, rank), [&](int i) { 437 return static_cast<int64_t>(index[i]) < shape[i]; 438 }); 439 } 440 441 ElementsAttr 442 ElementsAttr::mapValues(Type newElementType, 443 function_ref<APInt(const APInt &)> mapping) const { 444 switch (getKind()) { 445 case StandardAttributes::DenseElements: 446 return cast<DenseElementsAttr>().mapValues(newElementType, mapping); 447 default: 448 llvm_unreachable("unsupported ElementsAttr subtype"); 449 } 450 } 451 452 ElementsAttr 453 ElementsAttr::mapValues(Type newElementType, 454 function_ref<APInt(const APFloat &)> mapping) const { 455 switch (getKind()) { 456 case StandardAttributes::DenseElements: 457 return cast<DenseElementsAttr>().mapValues(newElementType, mapping); 458 default: 459 llvm_unreachable("unsupported ElementsAttr subtype"); 460 } 461 } 462 463 /// Returns the 1 dimensional flattened row-major index from the given 464 /// multi-dimensional index. 465 uint64_t ElementsAttr::getFlattenedIndex(ArrayRef<uint64_t> index) const { 466 assert(isValidIndex(index) && "expected valid multi-dimensional index"); 467 auto type = getType(); 468 469 // Reduce the provided multidimensional index into a flattended 1D row-major 470 // index. 471 auto rank = type.getRank(); 472 auto shape = type.getShape(); 473 uint64_t valueIndex = 0; 474 uint64_t dimMultiplier = 1; 475 for (int i = rank - 1; i >= 0; --i) { 476 valueIndex += index[i] * dimMultiplier; 477 dimMultiplier *= shape[i]; 478 } 479 return valueIndex; 480 } 481 482 //===----------------------------------------------------------------------===// 483 // DenseElementAttr Utilities 484 //===----------------------------------------------------------------------===// 485 486 static size_t getDenseElementBitwidth(Type eltType) { 487 // FIXME(b/121118307): using 64 bits for BF16 because it is currently stored 488 // with double semantics. 489 return eltType.isBF16() ? 64 : eltType.getIntOrFloatBitWidth(); 490 } 491 492 /// Get the bitwidth of a dense element type within the buffer. 493 /// DenseElementsAttr requires bitwidths greater than 1 to be aligned by 8. 494 static size_t getDenseElementStorageWidth(size_t origWidth) { 495 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth); 496 } 497 498 /// Set a bit to a specific value. 499 static void setBit(char *rawData, size_t bitPos, bool value) { 500 if (value) 501 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT)); 502 else 503 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT)); 504 } 505 506 /// Return the value of the specified bit. 507 static bool getBit(const char *rawData, size_t bitPos) { 508 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0; 509 } 510 511 /// Writes value to the bit position `bitPos` in array `rawData`. 512 static void writeBits(char *rawData, size_t bitPos, APInt value) { 513 size_t bitWidth = value.getBitWidth(); 514 515 // If the bitwidth is 1 we just toggle the specific bit. 516 if (bitWidth == 1) 517 return setBit(rawData, bitPos, value.isOneValue()); 518 519 // Otherwise, the bit position is guaranteed to be byte aligned. 520 assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned"); 521 std::copy_n(reinterpret_cast<const char *>(value.getRawData()), 522 llvm::divideCeil(bitWidth, CHAR_BIT), 523 rawData + (bitPos / CHAR_BIT)); 524 } 525 526 /// Reads the next `bitWidth` bits from the bit position `bitPos` in array 527 /// `rawData`. 528 static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth) { 529 // Handle a boolean bit position. 530 if (bitWidth == 1) 531 return APInt(1, getBit(rawData, bitPos) ? 1 : 0); 532 533 // Otherwise, the bit position must be 8-bit aligned. 534 assert((bitPos % CHAR_BIT) == 0 && "expected bitPos to be 8-bit aligned"); 535 APInt result(bitWidth, 0); 536 std::copy_n( 537 rawData + (bitPos / CHAR_BIT), llvm::divideCeil(bitWidth, CHAR_BIT), 538 const_cast<char *>(reinterpret_cast<const char *>(result.getRawData()))); 539 return result; 540 } 541 542 /// Returns if 'values' corresponds to a splat, i.e. one element, or has the 543 /// same element count as 'type'. 544 template <typename Values> 545 static bool hasSameElementsOrSplat(ShapedType type, const Values &values) { 546 return (values.size() == 1) || 547 (type.getNumElements() == static_cast<int64_t>(values.size())); 548 } 549 550 //===----------------------------------------------------------------------===// 551 // DenseElementAttr Iterators 552 //===----------------------------------------------------------------------===// 553 554 /// Constructs a new iterator. 555 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator( 556 DenseElementsAttr attr, size_t index) 557 : indexed_accessor_iterator<AttributeElementIterator, const void *, 558 Attribute, Attribute, Attribute>( 559 attr.getAsOpaquePointer(), index) {} 560 561 /// Accesses the Attribute value at this iterator position. 562 Attribute DenseElementsAttr::AttributeElementIterator::operator*() const { 563 auto owner = getFromOpaquePointer(base).cast<DenseElementsAttr>(); 564 Type eltTy = owner.getType().getElementType(); 565 if (auto intEltTy = eltTy.dyn_cast<IntegerType>()) { 566 if (intEltTy.getWidth() == 1) 567 return BoolAttr::get((*IntElementIterator(owner, index)).isOneValue(), 568 owner.getContext()); 569 return IntegerAttr::get(eltTy, *IntElementIterator(owner, index)); 570 } 571 if (auto floatEltTy = eltTy.dyn_cast<FloatType>()) { 572 IntElementIterator intIt(owner, index); 573 FloatElementIterator floatIt(floatEltTy.getFloatSemantics(), intIt); 574 return FloatAttr::get(eltTy, *floatIt); 575 } 576 llvm_unreachable("unexpected element type"); 577 } 578 579 /// Constructs a new iterator. 580 DenseElementsAttr::BoolElementIterator::BoolElementIterator( 581 DenseElementsAttr attr, size_t dataIndex) 582 : DenseElementIndexedIteratorImpl<BoolElementIterator, bool, bool, bool>( 583 attr.getRawData().data(), attr.isSplat(), dataIndex) {} 584 585 /// Accesses the bool value at this iterator position. 586 bool DenseElementsAttr::BoolElementIterator::operator*() const { 587 return getBit(getData(), getDataIndex()); 588 } 589 590 /// Constructs a new iterator. 591 DenseElementsAttr::IntElementIterator::IntElementIterator( 592 DenseElementsAttr attr, size_t dataIndex) 593 : DenseElementIndexedIteratorImpl<IntElementIterator, APInt, APInt, APInt>( 594 attr.getRawData().data(), attr.isSplat(), dataIndex), 595 bitWidth(getDenseElementBitwidth(attr.getType().getElementType())) {} 596 597 /// Accesses the raw APInt value at this iterator position. 598 APInt DenseElementsAttr::IntElementIterator::operator*() const { 599 return readBits(getData(), 600 getDataIndex() * getDenseElementStorageWidth(bitWidth), 601 bitWidth); 602 } 603 604 DenseElementsAttr::FloatElementIterator::FloatElementIterator( 605 const llvm::fltSemantics &smt, IntElementIterator it) 606 : llvm::mapped_iterator<IntElementIterator, 607 std::function<APFloat(const APInt &)>>( 608 it, [&](const APInt &val) { return APFloat(smt, val); }) {} 609 610 //===----------------------------------------------------------------------===// 611 // DenseElementsAttr 612 //===----------------------------------------------------------------------===// 613 614 DenseElementsAttr DenseElementsAttr::get(ShapedType type, 615 ArrayRef<Attribute> values) { 616 assert(type.getElementType().isIntOrFloat() && 617 "expected int or float element type"); 618 assert(hasSameElementsOrSplat(type, values)); 619 620 auto eltType = type.getElementType(); 621 size_t bitWidth = getDenseElementBitwidth(eltType); 622 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth); 623 624 // Compress the attribute values into a character buffer. 625 SmallVector<char, 8> data(llvm::divideCeil(storageBitWidth, CHAR_BIT) * 626 values.size()); 627 APInt intVal; 628 for (unsigned i = 0, e = values.size(); i < e; ++i) { 629 assert(eltType == values[i].getType() && 630 "expected attribute value to have element type"); 631 632 switch (eltType.getKind()) { 633 case StandardTypes::BF16: 634 case StandardTypes::F16: 635 case StandardTypes::F32: 636 case StandardTypes::F64: 637 intVal = values[i].cast<FloatAttr>().getValue().bitcastToAPInt(); 638 break; 639 case StandardTypes::Integer: 640 intVal = values[i].isa<BoolAttr>() 641 ? APInt(1, values[i].cast<BoolAttr>().getValue() ? 1 : 0) 642 : values[i].cast<IntegerAttr>().getValue(); 643 break; 644 default: 645 llvm_unreachable("unexpected element type"); 646 } 647 assert(intVal.getBitWidth() == bitWidth && 648 "expected value to have same bitwidth as element type"); 649 writeBits(data.data(), i * storageBitWidth, intVal); 650 } 651 return getRaw(type, data, /*isSplat=*/(values.size() == 1)); 652 } 653 654 DenseElementsAttr DenseElementsAttr::get(ShapedType type, 655 ArrayRef<bool> values) { 656 assert(hasSameElementsOrSplat(type, values)); 657 assert(type.getElementType().isInteger(1)); 658 659 std::vector<char> buff(llvm::divideCeil(values.size(), CHAR_BIT)); 660 for (int i = 0, e = values.size(); i != e; ++i) 661 setBit(buff.data(), i, values[i]); 662 return getRaw(type, buff, /*isSplat=*/(values.size() == 1)); 663 } 664 665 /// Constructs a dense integer elements attribute from an array of APInt 666 /// values. Each APInt value is expected to have the same bitwidth as the 667 /// element type of 'type'. 668 DenseElementsAttr DenseElementsAttr::get(ShapedType type, 669 ArrayRef<APInt> values) { 670 assert(type.getElementType().isa<IntegerType>()); 671 return getRaw(type, values); 672 } 673 674 // Constructs a dense float elements attribute from an array of APFloat 675 // values. Each APFloat value is expected to have the same bitwidth as the 676 // element type of 'type'. 677 DenseElementsAttr DenseElementsAttr::get(ShapedType type, 678 ArrayRef<APFloat> values) { 679 assert(type.getElementType().isa<FloatType>()); 680 681 // Convert the APFloat values to APInt and create a dense elements attribute. 682 std::vector<APInt> intValues(values.size()); 683 for (unsigned i = 0, e = values.size(); i != e; ++i) 684 intValues[i] = values[i].bitcastToAPInt(); 685 return getRaw(type, intValues); 686 } 687 688 /// Construct a dense elements attribute from a raw buffer representing the 689 /// data for this attribute. Users should generally not use this methods as 690 /// the expected buffer format may not be a form the user expects. 691 DenseElementsAttr DenseElementsAttr::getFromRawBuffer(ShapedType type, 692 ArrayRef<char> rawBuffer, 693 bool isSplatBuffer) { 694 return getRaw(type, rawBuffer, isSplatBuffer); 695 } 696 697 /// Constructs a dense elements attribute from an array of raw APInt values. 698 /// Each APInt value is expected to have the same bitwidth as the element type 699 /// of 'type'. 700 DenseElementsAttr DenseElementsAttr::getRaw(ShapedType type, 701 ArrayRef<APInt> values) { 702 assert(hasSameElementsOrSplat(type, values)); 703 704 size_t bitWidth = getDenseElementBitwidth(type.getElementType()); 705 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth); 706 std::vector<char> elementData(llvm::divideCeil(storageBitWidth, CHAR_BIT) * 707 values.size()); 708 for (unsigned i = 0, e = values.size(); i != e; ++i) { 709 assert(values[i].getBitWidth() == bitWidth); 710 writeBits(elementData.data(), i * storageBitWidth, values[i]); 711 } 712 return getRaw(type, elementData, /*isSplat=*/(values.size() == 1)); 713 } 714 715 DenseElementsAttr DenseElementsAttr::getRaw(ShapedType type, 716 ArrayRef<char> data, bool isSplat) { 717 assert((type.isa<RankedTensorType>() || type.isa<VectorType>()) && 718 "type must be ranked tensor or vector"); 719 assert(type.hasStaticShape() && "type must have static shape"); 720 return Base::get(type.getContext(), StandardAttributes::DenseElements, type, 721 data, isSplat); 722 } 723 724 /// Check the information for a C++ data type, check if this type is valid for 725 /// the current attribute. This method is used to verify specific type 726 /// invariants that the templatized 'getValues' method cannot. 727 static bool isValidIntOrFloat(ShapedType type, int64_t dataEltSize, bool isInt, 728 bool isSigned) { 729 // Make sure that the data element size is the same as the type element width. 730 if (getDenseElementBitwidth(type.getElementType()) != 731 static_cast<size_t>(dataEltSize * CHAR_BIT)) 732 return false; 733 734 // Check that the element type is either float or integer. 735 if (!isInt) 736 return type.getElementType().isa<FloatType>(); 737 738 auto intType = type.getElementType().dyn_cast<IntegerType>(); 739 if (!intType) 740 return false; 741 742 // Make sure signedness semantics is consistent. 743 if (intType.isSignless()) 744 return true; 745 return intType.isSigned() ? isSigned : !isSigned; 746 } 747 748 /// Overload of the 'getRaw' method that asserts that the given type is of 749 /// integer type. This method is used to verify type invariants that the 750 /// templatized 'get' method cannot. 751 DenseElementsAttr DenseElementsAttr::getRawIntOrFloat(ShapedType type, 752 ArrayRef<char> data, 753 int64_t dataEltSize, 754 bool isInt, 755 bool isSigned) { 756 assert(::isValidIntOrFloat(type, dataEltSize, isInt, isSigned)); 757 758 int64_t numElements = data.size() / dataEltSize; 759 assert(numElements == 1 || numElements == type.getNumElements()); 760 return getRaw(type, data, /*isSplat=*/numElements == 1); 761 } 762 763 /// A method used to verify specific type invariants that the templatized 'get' 764 /// method cannot. 765 bool DenseElementsAttr::isValidIntOrFloat(int64_t dataEltSize, bool isInt, 766 bool isSigned) const { 767 return ::isValidIntOrFloat(getType(), dataEltSize, isInt, isSigned); 768 } 769 770 /// Returns if this attribute corresponds to a splat, i.e. if all element 771 /// values are the same. 772 bool DenseElementsAttr::isSplat() const { return getImpl()->isSplat; } 773 774 /// Return the held element values as a range of Attributes. 775 auto DenseElementsAttr::getAttributeValues() const 776 -> llvm::iterator_range<AttributeElementIterator> { 777 return {attr_value_begin(), attr_value_end()}; 778 } 779 auto DenseElementsAttr::attr_value_begin() const -> AttributeElementIterator { 780 return AttributeElementIterator(*this, 0); 781 } 782 auto DenseElementsAttr::attr_value_end() const -> AttributeElementIterator { 783 return AttributeElementIterator(*this, getNumElements()); 784 } 785 786 /// Return the held element values as a range of bool. The element type of 787 /// this attribute must be of integer type of bitwidth 1. 788 auto DenseElementsAttr::getBoolValues() const 789 -> llvm::iterator_range<BoolElementIterator> { 790 auto eltType = getType().getElementType().dyn_cast<IntegerType>(); 791 assert(eltType && eltType.getWidth() == 1 && "expected i1 integer type"); 792 (void)eltType; 793 return {BoolElementIterator(*this, 0), 794 BoolElementIterator(*this, getNumElements())}; 795 } 796 797 /// Return the held element values as a range of APInts. The element type of 798 /// this attribute must be of integer type. 799 auto DenseElementsAttr::getIntValues() const 800 -> llvm::iterator_range<IntElementIterator> { 801 assert(getType().getElementType().isa<IntegerType>() && 802 "expected integer type"); 803 return {raw_int_begin(), raw_int_end()}; 804 } 805 auto DenseElementsAttr::int_value_begin() const -> IntElementIterator { 806 assert(getType().getElementType().isa<IntegerType>() && 807 "expected integer type"); 808 return raw_int_begin(); 809 } 810 auto DenseElementsAttr::int_value_end() const -> IntElementIterator { 811 assert(getType().getElementType().isa<IntegerType>() && 812 "expected integer type"); 813 return raw_int_end(); 814 } 815 816 /// Return the held element values as a range of APFloat. The element type of 817 /// this attribute must be of float type. 818 auto DenseElementsAttr::getFloatValues() const 819 -> llvm::iterator_range<FloatElementIterator> { 820 auto elementType = getType().getElementType().cast<FloatType>(); 821 assert(elementType.isa<FloatType>() && "expected float type"); 822 const auto &elementSemantics = elementType.getFloatSemantics(); 823 return {FloatElementIterator(elementSemantics, raw_int_begin()), 824 FloatElementIterator(elementSemantics, raw_int_end())}; 825 } 826 auto DenseElementsAttr::float_value_begin() const -> FloatElementIterator { 827 return getFloatValues().begin(); 828 } 829 auto DenseElementsAttr::float_value_end() const -> FloatElementIterator { 830 return getFloatValues().end(); 831 } 832 833 /// Return the raw storage data held by this attribute. 834 ArrayRef<char> DenseElementsAttr::getRawData() const { 835 return static_cast<ImplType *>(impl)->data; 836 } 837 838 /// Return a new DenseElementsAttr that has the same data as the current 839 /// attribute, but has been reshaped to 'newType'. The new type must have the 840 /// same total number of elements as well as element type. 841 DenseElementsAttr DenseElementsAttr::reshape(ShapedType newType) { 842 ShapedType curType = getType(); 843 if (curType == newType) 844 return *this; 845 846 (void)curType; 847 assert(newType.getElementType() == curType.getElementType() && 848 "expected the same element type"); 849 assert(newType.getNumElements() == curType.getNumElements() && 850 "expected the same number of elements"); 851 return getRaw(newType, getRawData(), isSplat()); 852 } 853 854 DenseElementsAttr 855 DenseElementsAttr::mapValues(Type newElementType, 856 function_ref<APInt(const APInt &)> mapping) const { 857 return cast<DenseIntElementsAttr>().mapValues(newElementType, mapping); 858 } 859 860 DenseElementsAttr DenseElementsAttr::mapValues( 861 Type newElementType, function_ref<APInt(const APFloat &)> mapping) const { 862 return cast<DenseFPElementsAttr>().mapValues(newElementType, mapping); 863 } 864 865 //===----------------------------------------------------------------------===// 866 // DenseFPElementsAttr 867 //===----------------------------------------------------------------------===// 868 869 template <typename Fn, typename Attr> 870 static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType, 871 Type newElementType, 872 llvm::SmallVectorImpl<char> &data) { 873 size_t bitWidth = getDenseElementBitwidth(newElementType); 874 size_t storageBitWidth = getDenseElementStorageWidth(bitWidth); 875 876 ShapedType newArrayType; 877 if (inType.isa<RankedTensorType>()) 878 newArrayType = RankedTensorType::get(inType.getShape(), newElementType); 879 else if (inType.isa<UnrankedTensorType>()) 880 newArrayType = RankedTensorType::get(inType.getShape(), newElementType); 881 else if (inType.isa<VectorType>()) 882 newArrayType = VectorType::get(inType.getShape(), newElementType); 883 else 884 assert(newArrayType && "Unhandled tensor type"); 885 886 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements(); 887 data.resize(llvm::divideCeil(storageBitWidth, CHAR_BIT) * numRawElements); 888 889 // Functor used to process a single element value of the attribute. 890 auto processElt = [&](decltype(*attr.begin()) value, size_t index) { 891 auto newInt = mapping(value); 892 assert(newInt.getBitWidth() == bitWidth); 893 writeBits(data.data(), index * storageBitWidth, newInt); 894 }; 895 896 // Check for the splat case. 897 if (attr.isSplat()) { 898 processElt(*attr.begin(), /*index=*/0); 899 return newArrayType; 900 } 901 902 // Otherwise, process all of the element values. 903 uint64_t elementIdx = 0; 904 for (auto value : attr) 905 processElt(value, elementIdx++); 906 return newArrayType; 907 } 908 909 DenseElementsAttr DenseFPElementsAttr::mapValues( 910 Type newElementType, function_ref<APInt(const APFloat &)> mapping) const { 911 llvm::SmallVector<char, 8> elementData; 912 auto newArrayType = 913 mappingHelper(mapping, *this, getType(), newElementType, elementData); 914 915 return getRaw(newArrayType, elementData, isSplat()); 916 } 917 918 /// Method for supporting type inquiry through isa, cast and dyn_cast. 919 bool DenseFPElementsAttr::classof(Attribute attr) { 920 return attr.isa<DenseElementsAttr>() && 921 attr.getType().cast<ShapedType>().getElementType().isa<FloatType>(); 922 } 923 924 //===----------------------------------------------------------------------===// 925 // DenseIntElementsAttr 926 //===----------------------------------------------------------------------===// 927 928 DenseElementsAttr DenseIntElementsAttr::mapValues( 929 Type newElementType, function_ref<APInt(const APInt &)> mapping) const { 930 llvm::SmallVector<char, 8> elementData; 931 auto newArrayType = 932 mappingHelper(mapping, *this, getType(), newElementType, elementData); 933 934 return getRaw(newArrayType, elementData, isSplat()); 935 } 936 937 /// Method for supporting type inquiry through isa, cast and dyn_cast. 938 bool DenseIntElementsAttr::classof(Attribute attr) { 939 return attr.isa<DenseElementsAttr>() && 940 attr.getType().cast<ShapedType>().getElementType().isa<IntegerType>(); 941 } 942 943 //===----------------------------------------------------------------------===// 944 // OpaqueElementsAttr 945 //===----------------------------------------------------------------------===// 946 947 OpaqueElementsAttr OpaqueElementsAttr::get(Dialect *dialect, ShapedType type, 948 StringRef bytes) { 949 assert(TensorType::isValidElementType(type.getElementType()) && 950 "Input element type should be a valid tensor element type"); 951 return Base::get(type.getContext(), StandardAttributes::OpaqueElements, type, 952 dialect, bytes); 953 } 954 955 StringRef OpaqueElementsAttr::getValue() const { return getImpl()->bytes; } 956 957 /// Return the value at the given index. If index does not refer to a valid 958 /// element, then a null attribute is returned. 959 Attribute OpaqueElementsAttr::getValue(ArrayRef<uint64_t> index) const { 960 assert(isValidIndex(index) && "expected valid multi-dimensional index"); 961 if (Dialect *dialect = getDialect()) 962 return dialect->extractElementHook(*this, index); 963 return Attribute(); 964 } 965 966 Dialect *OpaqueElementsAttr::getDialect() const { return getImpl()->dialect; } 967 968 bool OpaqueElementsAttr::decode(ElementsAttr &result) { 969 if (auto *d = getDialect()) 970 return d->decodeHook(*this, result); 971 return true; 972 } 973 974 //===----------------------------------------------------------------------===// 975 // SparseElementsAttr 976 //===----------------------------------------------------------------------===// 977 978 SparseElementsAttr SparseElementsAttr::get(ShapedType type, 979 DenseElementsAttr indices, 980 DenseElementsAttr values) { 981 assert(indices.getType().getElementType().isInteger(64) && 982 "expected sparse indices to be 64-bit integer values"); 983 assert((type.isa<RankedTensorType>() || type.isa<VectorType>()) && 984 "type must be ranked tensor or vector"); 985 assert(type.hasStaticShape() && "type must have static shape"); 986 return Base::get(type.getContext(), StandardAttributes::SparseElements, type, 987 indices.cast<DenseIntElementsAttr>(), values); 988 } 989 990 DenseIntElementsAttr SparseElementsAttr::getIndices() const { 991 return getImpl()->indices; 992 } 993 994 DenseElementsAttr SparseElementsAttr::getValues() const { 995 return getImpl()->values; 996 } 997 998 /// Return the value of the element at the given index. 999 Attribute SparseElementsAttr::getValue(ArrayRef<uint64_t> index) const { 1000 assert(isValidIndex(index) && "expected valid multi-dimensional index"); 1001 auto type = getType(); 1002 1003 // The sparse indices are 64-bit integers, so we can reinterpret the raw data 1004 // as a 1-D index array. 1005 auto sparseIndices = getIndices(); 1006 auto sparseIndexValues = sparseIndices.getValues<uint64_t>(); 1007 1008 // Check to see if the indices are a splat. 1009 if (sparseIndices.isSplat()) { 1010 // If the index is also not a splat of the index value, we know that the 1011 // value is zero. 1012 auto splatIndex = *sparseIndexValues.begin(); 1013 if (llvm::any_of(index, [=](uint64_t i) { return i != splatIndex; })) 1014 return getZeroAttr(); 1015 1016 // If the indices are a splat, we also expect the values to be a splat. 1017 assert(getValues().isSplat() && "expected splat values"); 1018 return getValues().getSplatValue(); 1019 } 1020 1021 // Build a mapping between known indices and the offset of the stored element. 1022 llvm::SmallDenseMap<llvm::ArrayRef<uint64_t>, size_t> mappedIndices; 1023 auto numSparseIndices = sparseIndices.getType().getDimSize(0); 1024 size_t rank = type.getRank(); 1025 for (size_t i = 0, e = numSparseIndices; i != e; ++i) 1026 mappedIndices.try_emplace( 1027 {&*std::next(sparseIndexValues.begin(), i * rank), rank}, i); 1028 1029 // Look for the provided index key within the mapped indices. If the provided 1030 // index is not found, then return a zero attribute. 1031 auto it = mappedIndices.find(index); 1032 if (it == mappedIndices.end()) 1033 return getZeroAttr(); 1034 1035 // Otherwise, return the held sparse value element. 1036 return getValues().getValue(it->second); 1037 } 1038 1039 /// Get a zero APFloat for the given sparse attribute. 1040 APFloat SparseElementsAttr::getZeroAPFloat() const { 1041 auto eltType = getType().getElementType().cast<FloatType>(); 1042 return APFloat(eltType.getFloatSemantics()); 1043 } 1044 1045 /// Get a zero APInt for the given sparse attribute. 1046 APInt SparseElementsAttr::getZeroAPInt() const { 1047 auto eltType = getType().getElementType().cast<IntegerType>(); 1048 return APInt::getNullValue(eltType.getWidth()); 1049 } 1050 1051 /// Get a zero attribute for the given attribute type. 1052 Attribute SparseElementsAttr::getZeroAttr() const { 1053 auto eltType = getType().getElementType(); 1054 1055 // Handle floating point elements. 1056 if (eltType.isa<FloatType>()) 1057 return FloatAttr::get(eltType, 0); 1058 1059 // Otherwise, this is an integer. 1060 auto intEltTy = eltType.cast<IntegerType>(); 1061 if (intEltTy.getWidth() == 1) 1062 return BoolAttr::get(false, eltType.getContext()); 1063 return IntegerAttr::get(eltType, 0); 1064 } 1065 1066 /// Flatten, and return, all of the sparse indices in this attribute in 1067 /// row-major order. 1068 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices() const { 1069 std::vector<ptrdiff_t> flatSparseIndices; 1070 1071 // The sparse indices are 64-bit integers, so we can reinterpret the raw data 1072 // as a 1-D index array. 1073 auto sparseIndices = getIndices(); 1074 auto sparseIndexValues = sparseIndices.getValues<uint64_t>(); 1075 if (sparseIndices.isSplat()) { 1076 SmallVector<uint64_t, 8> indices(getType().getRank(), 1077 *sparseIndexValues.begin()); 1078 flatSparseIndices.push_back(getFlattenedIndex(indices)); 1079 return flatSparseIndices; 1080 } 1081 1082 // Otherwise, reinterpret each index as an ArrayRef when flattening. 1083 auto numSparseIndices = sparseIndices.getType().getDimSize(0); 1084 size_t rank = getType().getRank(); 1085 for (size_t i = 0, e = numSparseIndices; i != e; ++i) 1086 flatSparseIndices.push_back(getFlattenedIndex( 1087 {&*std::next(sparseIndexValues.begin(), i * rank), rank})); 1088 return flatSparseIndices; 1089 } 1090 1091 //===----------------------------------------------------------------------===// 1092 // NamedAttributeList 1093 //===----------------------------------------------------------------------===// 1094 1095 NamedAttributeList::NamedAttributeList(ArrayRef<NamedAttribute> attributes) { 1096 setAttrs(attributes); 1097 } 1098 1099 ArrayRef<NamedAttribute> NamedAttributeList::getAttrs() const { 1100 return attrs ? attrs.getValue() : llvm::None; 1101 } 1102 1103 /// Replace the held attributes with ones provided in 'newAttrs'. 1104 void NamedAttributeList::setAttrs(ArrayRef<NamedAttribute> attributes) { 1105 // Don't create an attribute list if there are no attributes. 1106 if (attributes.empty()) 1107 attrs = nullptr; 1108 else 1109 attrs = DictionaryAttr::get(attributes, attributes[0].second.getContext()); 1110 } 1111 1112 /// Return the specified attribute if present, null otherwise. 1113 Attribute NamedAttributeList::get(StringRef name) const { 1114 return attrs ? attrs.get(name) : nullptr; 1115 } 1116 1117 /// Return the specified attribute if present, null otherwise. 1118 Attribute NamedAttributeList::get(Identifier name) const { 1119 return attrs ? attrs.get(name) : nullptr; 1120 } 1121 1122 /// If the an attribute exists with the specified name, change it to the new 1123 /// value. Otherwise, add a new attribute with the specified name/value. 1124 void NamedAttributeList::set(Identifier name, Attribute value) { 1125 assert(value && "attributes may never be null"); 1126 1127 // If we already have this attribute, replace it. 1128 auto origAttrs = getAttrs(); 1129 SmallVector<NamedAttribute, 8> newAttrs(origAttrs.begin(), origAttrs.end()); 1130 for (auto &elt : newAttrs) 1131 if (elt.first == name) { 1132 elt.second = value; 1133 attrs = DictionaryAttr::get(newAttrs, value.getContext()); 1134 return; 1135 } 1136 1137 // Otherwise, add it. 1138 newAttrs.push_back({name, value}); 1139 attrs = DictionaryAttr::get(newAttrs, value.getContext()); 1140 } 1141 1142 /// Remove the attribute with the specified name if it exists. The return 1143 /// value indicates whether the attribute was present or not. 1144 auto NamedAttributeList::remove(Identifier name) -> RemoveResult { 1145 auto origAttrs = getAttrs(); 1146 for (unsigned i = 0, e = origAttrs.size(); i != e; ++i) { 1147 if (origAttrs[i].first == name) { 1148 // Handle the simple case of removing the only attribute in the list. 1149 if (e == 1) { 1150 attrs = nullptr; 1151 return RemoveResult::Removed; 1152 } 1153 1154 SmallVector<NamedAttribute, 8> newAttrs; 1155 newAttrs.reserve(origAttrs.size() - 1); 1156 newAttrs.append(origAttrs.begin(), origAttrs.begin() + i); 1157 newAttrs.append(origAttrs.begin() + i + 1, origAttrs.end()); 1158 attrs = DictionaryAttr::get(newAttrs, newAttrs[0].second.getContext()); 1159 return RemoveResult::Removed; 1160 } 1161 } 1162 return RemoveResult::NotFound; 1163 } 1164