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