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