1 //===- Attributes.h - MLIR Attribute Classes --------------------*- C++ -*-===// 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 #ifndef MLIR_IR_ATTRIBUTES_H 10 #define MLIR_IR_ATTRIBUTES_H 11 12 #include "mlir/IR/AttributeSupport.h" 13 #include "llvm/ADT/APFloat.h" 14 #include "llvm/ADT/Sequence.h" 15 #include "llvm/Support/PointerLikeTypeTraits.h" 16 #include <complex> 17 18 namespace mlir { 19 class AffineMap; 20 class Dialect; 21 class FunctionType; 22 class Identifier; 23 class IntegerSet; 24 class Location; 25 class MLIRContext; 26 class ShapedType; 27 class Type; 28 29 namespace detail { 30 31 struct AffineMapAttributeStorage; 32 struct ArrayAttributeStorage; 33 struct DictionaryAttributeStorage; 34 struct IntegerAttributeStorage; 35 struct IntegerSetAttributeStorage; 36 struct FloatAttributeStorage; 37 struct OpaqueAttributeStorage; 38 struct StringAttributeStorage; 39 struct SymbolRefAttributeStorage; 40 struct TypeAttributeStorage; 41 42 /// Elements Attributes. 43 struct DenseIntOrFPElementsAttributeStorage; 44 struct DenseStringElementsAttributeStorage; 45 struct OpaqueElementsAttributeStorage; 46 struct SparseElementsAttributeStorage; 47 } // namespace detail 48 49 /// Attributes are known-constant values of operations and functions. 50 /// 51 /// Instances of the Attribute class are references to immutable, uniqued, 52 /// and immortal values owned by MLIRContext. As such, an Attribute is a thin 53 /// wrapper around an underlying storage pointer. Attributes are usually passed 54 /// by value. 55 class Attribute { 56 public: 57 /// Integer identifier for all the concrete attribute kinds. 58 enum Kind { 59 // Reserve attribute kinds for dialect specific extensions. 60 #define DEFINE_SYM_KIND_RANGE(Dialect) \ 61 FIRST_##Dialect##_ATTR, LAST_##Dialect##_ATTR = FIRST_##Dialect##_ATTR + 0xff, 62 #include "DialectSymbolRegistry.def" 63 }; 64 65 /// Utility class for implementing attributes. 66 template <typename ConcreteType, typename BaseType, typename StorageType, 67 template <typename T> class... Traits> 68 using AttrBase = detail::StorageUserBase<ConcreteType, BaseType, StorageType, 69 detail::AttributeUniquer, Traits...>; 70 71 using ImplType = AttributeStorage; 72 using ValueType = void; 73 Attribute()74 constexpr Attribute() : impl(nullptr) {} Attribute(const ImplType * impl)75 /* implicit */ Attribute(const ImplType *impl) 76 : impl(const_cast<ImplType *>(impl)) {} 77 78 Attribute(const Attribute &other) = default; 79 Attribute &operator=(const Attribute &other) = default; 80 81 bool operator==(Attribute other) const { return impl == other.impl; } 82 bool operator!=(Attribute other) const { return !(*this == other); } 83 explicit operator bool() const { return impl; } 84 85 bool operator!() const { return impl == nullptr; } 86 87 template <typename U> bool isa() const; 88 template <typename First, typename Second, typename... Rest> 89 bool isa() const; 90 template <typename U> U dyn_cast() const; 91 template <typename U> U dyn_cast_or_null() const; 92 template <typename U> U cast() const; 93 94 // Support dyn_cast'ing Attribute to itself. classof(Attribute)95 static bool classof(Attribute) { return true; } 96 97 /// Return the classification for this attribute. getKind()98 unsigned getKind() const { return impl->getKind(); } 99 100 /// Return the type of this attribute. 101 Type getType() const; 102 103 /// Return the context this attribute belongs to. 104 MLIRContext *getContext() const; 105 106 /// Get the dialect this attribute is registered to. 107 Dialect &getDialect() const; 108 109 /// Print the attribute. 110 void print(raw_ostream &os) const; 111 void dump() const; 112 113 /// Get an opaque pointer to the attribute. getAsOpaquePointer()114 const void *getAsOpaquePointer() const { return impl; } 115 /// Construct an attribute from the opaque pointer representation. getFromOpaquePointer(const void * ptr)116 static Attribute getFromOpaquePointer(const void *ptr) { 117 return Attribute(reinterpret_cast<const ImplType *>(ptr)); 118 } 119 120 friend ::llvm::hash_code hash_value(Attribute arg); 121 122 /// Return the abstract descriptor for this attribute. getAbstractAttribute()123 const AbstractAttribute &getAbstractAttribute() const { 124 return impl->getAbstractAttribute(); 125 } 126 127 protected: 128 ImplType *impl; 129 }; 130 131 inline raw_ostream &operator<<(raw_ostream &os, Attribute attr) { 132 attr.print(os); 133 return os; 134 } 135 136 //===----------------------------------------------------------------------===// 137 // AttributeTraitBase 138 //===----------------------------------------------------------------------===// 139 140 namespace AttributeTrait { 141 /// This class represents the base of an attribute trait. 142 template <typename ConcreteType, template <typename> class TraitType> 143 using TraitBase = detail::StorageUserTraitBase<ConcreteType, TraitType>; 144 } // namespace AttributeTrait 145 146 //===----------------------------------------------------------------------===// 147 // AttributeInterface 148 //===----------------------------------------------------------------------===// 149 150 /// This class represents the base of an attribute interface. See the definition 151 /// of `detail::Interface` for requirements on the `Traits` type. 152 template <typename ConcreteType, typename Traits> 153 class AttributeInterface 154 : public detail::Interface<ConcreteType, Attribute, Traits, Attribute, 155 AttributeTrait::TraitBase> { 156 public: 157 using Base = AttributeInterface<ConcreteType, Traits>; 158 using InterfaceBase = detail::Interface<ConcreteType, Type, Traits, Type, 159 AttributeTrait::TraitBase>; 160 using InterfaceBase::InterfaceBase; 161 162 private: 163 /// Returns the impl interface instance for the given type. getInterfaceFor(Attribute attr)164 static typename InterfaceBase::Concept *getInterfaceFor(Attribute attr) { 165 return attr.getAbstractAttribute().getInterface<ConcreteType>(); 166 } 167 168 /// Allow access to 'getInterfaceFor'. 169 friend InterfaceBase; 170 }; 171 172 //===----------------------------------------------------------------------===// 173 // StandardAttributes 174 //===----------------------------------------------------------------------===// 175 176 namespace StandardAttributes { 177 enum Kind { 178 AffineMap = Attribute::FIRST_STANDARD_ATTR, 179 Array, 180 Dictionary, 181 Float, 182 Integer, 183 IntegerSet, 184 Opaque, 185 String, 186 SymbolRef, 187 Type, 188 Unit, 189 190 /// Elements Attributes. 191 DenseIntOrFPElements, 192 DenseStringElements, 193 OpaqueElements, 194 SparseElements, 195 FIRST_ELEMENTS_ATTR = DenseIntOrFPElements, 196 LAST_ELEMENTS_ATTR = SparseElements, 197 198 /// Locations. 199 CallSiteLocation, 200 FileLineColLocation, 201 FusedLocation, 202 NameLocation, 203 OpaqueLocation, 204 UnknownLocation, 205 206 // Represents a location as a 'void*' pointer to a front-end's opaque 207 // location information, which must live longer than the MLIR objects that 208 // refer to it. OpaqueLocation's are never serialized. 209 // 210 // TODO: OpaqueLocation, 211 212 // Represents a value inlined through a function call. 213 // TODO: InlinedLocation, 214 215 FIRST_LOCATION_ATTR = CallSiteLocation, 216 LAST_LOCATION_ATTR = UnknownLocation, 217 }; 218 } // namespace StandardAttributes 219 220 //===----------------------------------------------------------------------===// 221 // AffineMapAttr 222 //===----------------------------------------------------------------------===// 223 224 class AffineMapAttr 225 : public Attribute::AttrBase<AffineMapAttr, Attribute, 226 detail::AffineMapAttributeStorage> { 227 public: 228 using Base::Base; 229 using ValueType = AffineMap; 230 231 static AffineMapAttr get(AffineMap value); 232 233 AffineMap getValue() const; 234 235 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)236 static bool kindof(unsigned kind) { 237 return kind == StandardAttributes::AffineMap; 238 } 239 }; 240 241 //===----------------------------------------------------------------------===// 242 // ArrayAttr 243 //===----------------------------------------------------------------------===// 244 245 /// Array attributes are lists of other attributes. They are not necessarily 246 /// type homogenous given that attributes don't, in general, carry types. 247 class ArrayAttr : public Attribute::AttrBase<ArrayAttr, Attribute, 248 detail::ArrayAttributeStorage> { 249 public: 250 using Base::Base; 251 using ValueType = ArrayRef<Attribute>; 252 253 static ArrayAttr get(ArrayRef<Attribute> value, MLIRContext *context); 254 255 ArrayRef<Attribute> getValue() const; 256 Attribute operator[](unsigned idx) const; 257 258 /// Support range iteration. 259 using iterator = llvm::ArrayRef<Attribute>::iterator; begin()260 iterator begin() const { return getValue().begin(); } end()261 iterator end() const { return getValue().end(); } size()262 size_t size() const { return getValue().size(); } empty()263 bool empty() const { return size() == 0; } 264 265 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)266 static bool kindof(unsigned kind) { 267 return kind == StandardAttributes::Array; 268 } 269 270 private: 271 /// Class for underlying value iterator support. 272 template <typename AttrTy> 273 class attr_value_iterator final 274 : public llvm::mapped_iterator<ArrayAttr::iterator, 275 AttrTy (*)(Attribute)> { 276 public: attr_value_iterator(ArrayAttr::iterator it)277 explicit attr_value_iterator(ArrayAttr::iterator it) 278 : llvm::mapped_iterator<ArrayAttr::iterator, AttrTy (*)(Attribute)>( 279 it, [](Attribute attr) { return attr.cast<AttrTy>(); }) {} 280 AttrTy operator*() const { return (*this->I).template cast<AttrTy>(); } 281 }; 282 283 public: 284 template <typename AttrTy> getAsRange()285 llvm::iterator_range<attr_value_iterator<AttrTy>> getAsRange() { 286 return llvm::make_range(attr_value_iterator<AttrTy>(begin()), 287 attr_value_iterator<AttrTy>(end())); 288 } 289 template <typename AttrTy, typename UnderlyingTy> getAsRange()290 auto getAsRange() { 291 return llvm::map_range(getAsRange<AttrTy>(), [](AttrTy attr) { 292 return static_cast<UnderlyingTy>(attr.getValue()); 293 }); 294 } 295 }; 296 297 //===----------------------------------------------------------------------===// 298 // DictionaryAttr 299 //===----------------------------------------------------------------------===// 300 301 /// NamedAttribute is used for dictionary attributes, it holds an identifier for 302 /// the name and a value for the attribute. The attribute pointer should always 303 /// be non-null. 304 using NamedAttribute = std::pair<Identifier, Attribute>; 305 306 bool operator<(const NamedAttribute &lhs, const NamedAttribute &rhs); 307 bool operator<(const NamedAttribute &lhs, StringRef rhs); 308 309 /// Dictionary attribute is an attribute that represents a sorted collection of 310 /// named attribute values. The elements are sorted by name, and each name must 311 /// be unique within the collection. 312 class DictionaryAttr 313 : public Attribute::AttrBase<DictionaryAttr, Attribute, 314 detail::DictionaryAttributeStorage> { 315 public: 316 using Base::Base; 317 using ValueType = ArrayRef<NamedAttribute>; 318 319 /// Construct a dictionary attribute with the provided list of named 320 /// attributes. This method assumes that the provided list is unordered. If 321 /// the caller can guarantee that the attributes are ordered by name, 322 /// getWithSorted should be used instead. 323 static DictionaryAttr get(ArrayRef<NamedAttribute> value, 324 MLIRContext *context); 325 326 /// Construct a dictionary with an array of values that is known to already be 327 /// sorted by name and uniqued. 328 static DictionaryAttr getWithSorted(ArrayRef<NamedAttribute> value, 329 MLIRContext *context); 330 331 ArrayRef<NamedAttribute> getValue() const; 332 333 /// Return the specified attribute if present, null otherwise. 334 Attribute get(StringRef name) const; 335 Attribute get(Identifier name) const; 336 337 /// Return the specified named attribute if present, None otherwise. 338 Optional<NamedAttribute> getNamed(StringRef name) const; 339 Optional<NamedAttribute> getNamed(Identifier name) const; 340 341 /// Support range iteration. 342 using iterator = llvm::ArrayRef<NamedAttribute>::iterator; 343 iterator begin() const; 344 iterator end() const; empty()345 bool empty() const { return size() == 0; } 346 size_t size() const; 347 348 /// Sorts the NamedAttributes in the array ordered by name as expected by 349 /// getWithSorted and returns whether the values were sorted. 350 /// Requires: uniquely named attributes. 351 static bool sort(ArrayRef<NamedAttribute> values, 352 SmallVectorImpl<NamedAttribute> &storage); 353 354 /// Sorts the NamedAttributes in the array ordered by name as expected by 355 /// getWithSorted in place on an array and returns whether the values needed 356 /// to be sorted. 357 /// Requires: uniquely named attributes. 358 static bool sortInPlace(SmallVectorImpl<NamedAttribute> &array); 359 360 /// Methods for supporting type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)361 static bool kindof(unsigned kind) { 362 return kind == StandardAttributes::Dictionary; 363 } 364 365 private: 366 /// Return empty dictionary. 367 static DictionaryAttr getEmpty(MLIRContext *context); 368 }; 369 370 //===----------------------------------------------------------------------===// 371 // FloatAttr 372 //===----------------------------------------------------------------------===// 373 374 class FloatAttr : public Attribute::AttrBase<FloatAttr, Attribute, 375 detail::FloatAttributeStorage> { 376 public: 377 using Base::Base; 378 using ValueType = APFloat; 379 380 /// Return a float attribute for the specified value in the specified type. 381 /// These methods should only be used for simple constant values, e.g 1.0/2.0, 382 /// that are known-valid both as host double and the 'type' format. 383 static FloatAttr get(Type type, double value); 384 static FloatAttr getChecked(Type type, double value, Location loc); 385 386 /// Return a float attribute for the specified value in the specified type. 387 static FloatAttr get(Type type, const APFloat &value); 388 static FloatAttr getChecked(Type type, const APFloat &value, Location loc); 389 390 APFloat getValue() const; 391 392 /// This function is used to convert the value to a double, even if it loses 393 /// precision. 394 double getValueAsDouble() const; 395 static double getValueAsDouble(APFloat val); 396 397 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)398 static bool kindof(unsigned kind) { 399 return kind == StandardAttributes::Float; 400 } 401 402 /// Verify the construction invariants for a double value. 403 static LogicalResult verifyConstructionInvariants(Location loc, Type type, 404 double value); 405 static LogicalResult verifyConstructionInvariants(Location loc, Type type, 406 const APFloat &value); 407 }; 408 409 //===----------------------------------------------------------------------===// 410 // IntegerAttr 411 //===----------------------------------------------------------------------===// 412 413 class IntegerAttr 414 : public Attribute::AttrBase<IntegerAttr, Attribute, 415 detail::IntegerAttributeStorage> { 416 public: 417 using Base::Base; 418 using ValueType = APInt; 419 420 static IntegerAttr get(Type type, int64_t value); 421 static IntegerAttr get(Type type, const APInt &value); 422 423 APInt getValue() const; 424 /// Return the integer value as a 64-bit int. The attribute must be a signless 425 /// integer. 426 // TODO: Change callers to use getValue instead. 427 int64_t getInt() const; 428 /// Return the integer value as a signed 64-bit int. The attribute must be 429 /// a signed integer. 430 int64_t getSInt() const; 431 /// Return the integer value as a unsigned 64-bit int. The attribute must be 432 /// an unsigned integer. 433 uint64_t getUInt() const; 434 435 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)436 static bool kindof(unsigned kind) { 437 return kind == StandardAttributes::Integer; 438 } 439 440 static LogicalResult verifyConstructionInvariants(Location loc, Type type, 441 int64_t value); 442 static LogicalResult verifyConstructionInvariants(Location loc, Type type, 443 const APInt &value); 444 }; 445 446 //===----------------------------------------------------------------------===// 447 // BoolAttr 448 449 /// Special case of IntegerAttr to represent boolean integers, i.e., signless i1 450 /// integers. 451 class BoolAttr : public Attribute { 452 public: 453 using Attribute::Attribute; 454 using ValueType = bool; 455 456 static BoolAttr get(bool value, MLIRContext *context); 457 458 /// Enable conversion to IntegerAttr. This uses conversion vs. inheritance to 459 /// avoid bringing in all of IntegerAttrs methods. IntegerAttr()460 operator IntegerAttr() const { return IntegerAttr(impl); } 461 462 /// Return the boolean value of this attribute. 463 bool getValue() const; 464 465 /// Methods for support type inquiry through isa, cast, and dyn_cast. 466 static bool classof(Attribute attr); 467 }; 468 469 //===----------------------------------------------------------------------===// 470 // IntegerSetAttr 471 //===----------------------------------------------------------------------===// 472 473 class IntegerSetAttr 474 : public Attribute::AttrBase<IntegerSetAttr, Attribute, 475 detail::IntegerSetAttributeStorage> { 476 public: 477 using Base::Base; 478 using ValueType = IntegerSet; 479 480 static IntegerSetAttr get(IntegerSet value); 481 482 IntegerSet getValue() const; 483 484 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)485 static bool kindof(unsigned kind) { 486 return kind == StandardAttributes::IntegerSet; 487 } 488 }; 489 490 //===----------------------------------------------------------------------===// 491 // OpaqueAttr 492 //===----------------------------------------------------------------------===// 493 494 /// Opaque attributes represent attributes of non-registered dialects. These are 495 /// attribute represented in their raw string form, and can only usefully be 496 /// tested for attribute equality. 497 class OpaqueAttr : public Attribute::AttrBase<OpaqueAttr, Attribute, 498 detail::OpaqueAttributeStorage> { 499 public: 500 using Base::Base; 501 502 /// Get or create a new OpaqueAttr with the provided dialect and string data. 503 static OpaqueAttr get(Identifier dialect, StringRef attrData, Type type, 504 MLIRContext *context); 505 506 /// Get or create a new OpaqueAttr with the provided dialect and string data. 507 /// If the given identifier is not a valid namespace for a dialect, then a 508 /// null attribute is returned. 509 static OpaqueAttr getChecked(Identifier dialect, StringRef attrData, 510 Type type, Location location); 511 512 /// Returns the dialect namespace of the opaque attribute. 513 Identifier getDialectNamespace() const; 514 515 /// Returns the raw attribute data of the opaque attribute. 516 StringRef getAttrData() const; 517 518 /// Verify the construction of an opaque attribute. 519 static LogicalResult verifyConstructionInvariants(Location loc, 520 Identifier dialect, 521 StringRef attrData, 522 Type type); 523 kindof(unsigned kind)524 static bool kindof(unsigned kind) { 525 return kind == StandardAttributes::Opaque; 526 } 527 }; 528 529 //===----------------------------------------------------------------------===// 530 // StringAttr 531 //===----------------------------------------------------------------------===// 532 533 class StringAttr : public Attribute::AttrBase<StringAttr, Attribute, 534 detail::StringAttributeStorage> { 535 public: 536 using Base::Base; 537 using ValueType = StringRef; 538 539 /// Get an instance of a StringAttr with the given string. 540 static StringAttr get(StringRef bytes, MLIRContext *context); 541 542 /// Get an instance of a StringAttr with the given string and Type. 543 static StringAttr get(StringRef bytes, Type type); 544 545 StringRef getValue() const; 546 547 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)548 static bool kindof(unsigned kind) { 549 return kind == StandardAttributes::String; 550 } 551 }; 552 553 //===----------------------------------------------------------------------===// 554 // SymbolRefAttr 555 //===----------------------------------------------------------------------===// 556 557 class FlatSymbolRefAttr; 558 559 /// A symbol reference attribute represents a symbolic reference to another 560 /// operation. 561 class SymbolRefAttr 562 : public Attribute::AttrBase<SymbolRefAttr, Attribute, 563 detail::SymbolRefAttributeStorage> { 564 public: 565 using Base::Base; 566 567 /// Construct a symbol reference for the given value name. 568 static FlatSymbolRefAttr get(StringRef value, MLIRContext *ctx); 569 570 /// Construct a symbol reference for the given value name, and a set of nested 571 /// references that are further resolve to a nested symbol. 572 static SymbolRefAttr get(StringRef value, 573 ArrayRef<FlatSymbolRefAttr> references, 574 MLIRContext *ctx); 575 576 /// Returns the name of the top level symbol reference, i.e. the root of the 577 /// reference path. 578 StringRef getRootReference() const; 579 580 /// Returns the name of the fully resolved symbol, i.e. the leaf of the 581 /// reference path. 582 StringRef getLeafReference() const; 583 584 /// Returns the set of nested references representing the path to the symbol 585 /// nested under the root reference. 586 ArrayRef<FlatSymbolRefAttr> getNestedReferences() const; 587 588 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)589 static bool kindof(unsigned kind) { 590 return kind == StandardAttributes::SymbolRef; 591 } 592 }; 593 594 /// A symbol reference with a reference path containing a single element. This 595 /// is used to refer to an operation within the current symbol table. 596 class FlatSymbolRefAttr : public SymbolRefAttr { 597 public: 598 using SymbolRefAttr::SymbolRefAttr; 599 using ValueType = StringRef; 600 601 /// Construct a symbol reference for the given value name. get(StringRef value,MLIRContext * ctx)602 static FlatSymbolRefAttr get(StringRef value, MLIRContext *ctx) { 603 return SymbolRefAttr::get(value, ctx); 604 } 605 606 /// Returns the name of the held symbol reference. getValue()607 StringRef getValue() const { return getRootReference(); } 608 609 /// Methods for support type inquiry through isa, cast, and dyn_cast. classof(Attribute attr)610 static bool classof(Attribute attr) { 611 SymbolRefAttr refAttr = attr.dyn_cast<SymbolRefAttr>(); 612 return refAttr && refAttr.getNestedReferences().empty(); 613 } 614 615 private: 616 using SymbolRefAttr::get; 617 using SymbolRefAttr::getNestedReferences; 618 }; 619 620 //===----------------------------------------------------------------------===// 621 // Type 622 //===----------------------------------------------------------------------===// 623 624 class TypeAttr : public Attribute::AttrBase<TypeAttr, Attribute, 625 detail::TypeAttributeStorage> { 626 public: 627 using Base::Base; 628 using ValueType = Type; 629 630 static TypeAttr get(Type value); 631 632 Type getValue() const; 633 634 /// Methods for support type inquiry through isa, cast, and dyn_cast. kindof(unsigned kind)635 static bool kindof(unsigned kind) { return kind == StandardAttributes::Type; } 636 }; 637 638 //===----------------------------------------------------------------------===// 639 // UnitAttr 640 //===----------------------------------------------------------------------===// 641 642 /// Unit attributes are attributes that hold no specific value and are given 643 /// meaning by their existence. 644 class UnitAttr 645 : public Attribute::AttrBase<UnitAttr, Attribute, AttributeStorage> { 646 public: 647 using Base::Base; 648 649 static UnitAttr get(MLIRContext *context); 650 kindof(unsigned kind)651 static bool kindof(unsigned kind) { return kind == StandardAttributes::Unit; } 652 }; 653 654 //===----------------------------------------------------------------------===// 655 // Elements Attributes 656 //===----------------------------------------------------------------------===// 657 658 namespace detail { 659 template <typename T> class ElementsAttrIterator; 660 template <typename T> class ElementsAttrRange; 661 } // namespace detail 662 663 /// A base attribute that represents a reference to a static shaped tensor or 664 /// vector constant. 665 class ElementsAttr : public Attribute { 666 public: 667 using Attribute::Attribute; 668 template <typename T> using iterator = detail::ElementsAttrIterator<T>; 669 template <typename T> using iterator_range = detail::ElementsAttrRange<T>; 670 671 /// Return the type of this ElementsAttr, guaranteed to be a vector or tensor 672 /// with static shape. 673 ShapedType getType() const; 674 675 /// Return the value at the given index. The index is expected to refer to a 676 /// valid element. 677 Attribute getValue(ArrayRef<uint64_t> index) const; 678 679 /// Return the value of type 'T' at the given index, where 'T' corresponds to 680 /// an Attribute type. getValue(ArrayRef<uint64_t> index)681 template <typename T> T getValue(ArrayRef<uint64_t> index) const { 682 return getValue(index).template cast<T>(); 683 } 684 685 /// Return the elements of this attribute as a value of type 'T'. Note: 686 /// Aborts if the subclass is OpaqueElementsAttrs, these attrs do not support 687 /// iteration. 688 template <typename T> iterator_range<T> getValues() const; 689 690 /// Return if the given 'index' refers to a valid element in this attribute. 691 bool isValidIndex(ArrayRef<uint64_t> index) const; 692 693 /// Returns the number of elements held by this attribute. 694 int64_t getNumElements() const; 695 696 /// Generates a new ElementsAttr by mapping each int value to a new 697 /// underlying APInt. The new values can represent either an integer or float. 698 /// This ElementsAttr should contain integers. 699 ElementsAttr mapValues(Type newElementType, 700 function_ref<APInt(const APInt &)> mapping) const; 701 702 /// Generates a new ElementsAttr by mapping each float value to a new 703 /// underlying APInt. The new values can represent either an integer or float. 704 /// This ElementsAttr should contain floats. 705 ElementsAttr mapValues(Type newElementType, 706 function_ref<APInt(const APFloat &)> mapping) const; 707 708 /// Method for support type inquiry through isa, cast and dyn_cast. classof(Attribute attr)709 static bool classof(Attribute attr) { 710 return attr.getKind() >= StandardAttributes::FIRST_ELEMENTS_ATTR && 711 attr.getKind() <= StandardAttributes::LAST_ELEMENTS_ATTR; 712 } 713 714 protected: 715 /// Returns the 1 dimensional flattened row-major index from the given 716 /// multi-dimensional index. 717 uint64_t getFlattenedIndex(ArrayRef<uint64_t> index) const; 718 }; 719 720 namespace detail { 721 /// DenseElementsAttr data is aligned to uint64_t, so this traits class is 722 /// necessary to interop with PointerIntPair. 723 class DenseElementDataPointerTypeTraits { 724 public: getAsVoidPointer(const char * ptr)725 static inline const void *getAsVoidPointer(const char *ptr) { return ptr; } getFromVoidPointer(const void * ptr)726 static inline const char *getFromVoidPointer(const void *ptr) { 727 return static_cast<const char *>(ptr); 728 } 729 730 // Note: We could steal more bits if the need arises. 731 static constexpr int NumLowBitsAvailable = 1; 732 }; 733 734 /// Pair of raw pointer and a boolean flag of whether the pointer holds a splat, 735 using DenseIterPtrAndSplat = 736 llvm::PointerIntPair<const char *, 1, bool, 737 DenseElementDataPointerTypeTraits>; 738 739 /// Impl iterator for indexed DenseElementAttr iterators that records a data 740 /// pointer and data index that is adjusted for the case of a splat attribute. 741 template <typename ConcreteT, typename T, typename PointerT = T *, 742 typename ReferenceT = T &> 743 class DenseElementIndexedIteratorImpl 744 : public llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, 745 PointerT, ReferenceT> { 746 protected: DenseElementIndexedIteratorImpl(const char * data,bool isSplat,size_t dataIndex)747 DenseElementIndexedIteratorImpl(const char *data, bool isSplat, 748 size_t dataIndex) 749 : llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, 750 PointerT, ReferenceT>({data, isSplat}, 751 dataIndex) {} 752 753 /// Return the current index for this iterator, adjusted for the case of a 754 /// splat. getDataIndex()755 ptrdiff_t getDataIndex() const { 756 bool isSplat = this->base.getInt(); 757 return isSplat ? 0 : this->index; 758 } 759 760 /// Return the data base pointer. getData()761 const char *getData() const { return this->base.getPointer(); } 762 }; 763 764 /// Type trait detector that checks if a given type T is a complex type. 765 template <typename T> struct is_complex_t : public std::false_type {}; 766 template <typename T> 767 struct is_complex_t<std::complex<T>> : public std::true_type {}; 768 } // namespace detail 769 770 /// An attribute that represents a reference to a dense vector or tensor object. 771 /// 772 class DenseElementsAttr : public ElementsAttr { 773 public: 774 using ElementsAttr::ElementsAttr; 775 776 /// Method for support type inquiry through isa, cast and dyn_cast. 777 static bool classof(Attribute attr) { 778 return attr.getKind() == StandardAttributes::DenseIntOrFPElements || 779 attr.getKind() == StandardAttributes::DenseStringElements; 780 } 781 782 /// Constructs a dense elements attribute from an array of element values. 783 /// Each element attribute value is expected to be an element of 'type'. 784 /// 'type' must be a vector or tensor with static shape. If the element of 785 /// `type` is non-integer/index/float it is assumed to be a string type. 786 static DenseElementsAttr get(ShapedType type, ArrayRef<Attribute> values); 787 788 /// Constructs a dense integer elements attribute from an array of integer 789 /// or floating-point values. Each value is expected to be the same bitwidth 790 /// of the element type of 'type'. 'type' must be a vector or tensor with 791 /// static shape. 792 template <typename T, typename = typename std::enable_if< 793 std::numeric_limits<T>::is_integer || 794 llvm::is_one_of<T, float, double>::value>::type> 795 static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { 796 const char *data = reinterpret_cast<const char *>(values.data()); 797 return getRawIntOrFloat( 798 type, ArrayRef<char>(data, values.size() * sizeof(T)), sizeof(T), 799 std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed); 800 } 801 802 /// Constructs a dense integer elements attribute from a single element. 803 template <typename T, typename = typename std::enable_if< 804 std::numeric_limits<T>::is_integer || 805 llvm::is_one_of<T, float, double>::value || 806 detail::is_complex_t<T>::value>::type> 807 static DenseElementsAttr get(const ShapedType &type, T value) { 808 return get(type, llvm::makeArrayRef(value)); 809 } 810 811 /// Constructs a dense complex elements attribute from an array of complex 812 /// values. Each value is expected to be the same bitwidth of the element type 813 /// of 'type'. 'type' must be a vector or tensor with static shape. 814 template <typename T, typename ElementT = typename T::value_type, 815 typename = typename std::enable_if< 816 detail::is_complex_t<T>::value && 817 (std::numeric_limits<ElementT>::is_integer || 818 llvm::is_one_of<ElementT, float, double>::value)>::type> 819 static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { 820 const char *data = reinterpret_cast<const char *>(values.data()); 821 return getRawComplex(type, ArrayRef<char>(data, values.size() * sizeof(T)), 822 sizeof(T), std::numeric_limits<ElementT>::is_integer, 823 std::numeric_limits<ElementT>::is_signed); 824 } 825 826 /// Overload of the above 'get' method that is specialized for boolean values. 827 static DenseElementsAttr get(ShapedType type, ArrayRef<bool> values); 828 829 /// Overload of the above 'get' method that is specialized for StringRef 830 /// values. 831 static DenseElementsAttr get(ShapedType type, ArrayRef<StringRef> values); 832 833 /// Constructs a dense integer elements attribute from an array of APInt 834 /// values. Each APInt value is expected to have the same bitwidth as the 835 /// element type of 'type'. 'type' must be a vector or tensor with static 836 /// shape. 837 static DenseElementsAttr get(ShapedType type, ArrayRef<APInt> values); 838 839 /// Constructs a dense complex elements attribute from an array of APInt 840 /// values. Each APInt value is expected to have the same bitwidth as the 841 /// element type of 'type'. 'type' must be a vector or tensor with static 842 /// shape. 843 static DenseElementsAttr get(ShapedType type, 844 ArrayRef<std::complex<APInt>> values); 845 846 /// Constructs a dense float elements attribute from an array of APFloat 847 /// values. Each APFloat value is expected to have the same bitwidth as the 848 /// element type of 'type'. 'type' must be a vector or tensor with static 849 /// shape. 850 static DenseElementsAttr get(ShapedType type, ArrayRef<APFloat> values); 851 852 /// Constructs a dense complex elements attribute from an array of APFloat 853 /// values. Each APFloat value is expected to have the same bitwidth as the 854 /// element type of 'type'. 'type' must be a vector or tensor with static 855 /// shape. 856 static DenseElementsAttr get(ShapedType type, 857 ArrayRef<std::complex<APFloat>> values); 858 859 /// Construct a dense elements attribute for an initializer_list of values. 860 /// Each value is expected to be the same bitwidth of the element type of 861 /// 'type'. 'type' must be a vector or tensor with static shape. 862 template <typename T> 863 static DenseElementsAttr get(const ShapedType &type, 864 const std::initializer_list<T> &list) { 865 return get(type, ArrayRef<T>(list)); 866 } 867 868 /// Construct a dense elements attribute from a raw buffer representing the 869 /// data for this attribute. Users should generally not use this methods as 870 /// the expected buffer format may not be a form the user expects. 871 static DenseElementsAttr getFromRawBuffer(ShapedType type, 872 ArrayRef<char> rawBuffer, 873 bool isSplatBuffer); 874 875 /// Returns true if the given buffer is a valid raw buffer for the given type. 876 /// `detectedSplat` is set if the buffer is valid and represents a splat 877 /// buffer. 878 static bool isValidRawBuffer(ShapedType type, ArrayRef<char> rawBuffer, 879 bool &detectedSplat); 880 881 //===--------------------------------------------------------------------===// 882 // Iterators 883 //===--------------------------------------------------------------------===// 884 885 /// A utility iterator that allows walking over the internal Attribute values 886 /// of a DenseElementsAttr. 887 class AttributeElementIterator 888 : public llvm::indexed_accessor_iterator<AttributeElementIterator, 889 const void *, Attribute, 890 Attribute, Attribute> { 891 public: 892 /// Accesses the Attribute value at this iterator position. 893 Attribute operator*() const; 894 895 private: 896 friend DenseElementsAttr; 897 898 /// Constructs a new iterator. 899 AttributeElementIterator(DenseElementsAttr attr, size_t index); 900 }; 901 902 /// Iterator for walking raw element values of the specified type 'T', which 903 /// may be any c++ data type matching the stored representation: int32_t, 904 /// float, etc. 905 template <typename T> 906 class ElementIterator 907 : public detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, 908 const T> { 909 public: 910 /// Accesses the raw value at this iterator position. 911 const T &operator*() const { 912 return reinterpret_cast<const T *>(this->getData())[this->getDataIndex()]; 913 } 914 915 private: 916 friend DenseElementsAttr; 917 918 /// Constructs a new iterator. 919 ElementIterator(const char *data, bool isSplat, size_t dataIndex) 920 : detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, const T>( 921 data, isSplat, dataIndex) {} 922 }; 923 924 /// A utility iterator that allows walking over the internal bool values. 925 class BoolElementIterator 926 : public detail::DenseElementIndexedIteratorImpl<BoolElementIterator, 927 bool, bool, bool> { 928 public: 929 /// Accesses the bool value at this iterator position. 930 bool operator*() const; 931 932 private: 933 friend DenseElementsAttr; 934 935 /// Constructs a new iterator. 936 BoolElementIterator(DenseElementsAttr attr, size_t dataIndex); 937 }; 938 939 /// A utility iterator that allows walking over the internal raw APInt values. 940 class IntElementIterator 941 : public detail::DenseElementIndexedIteratorImpl<IntElementIterator, 942 APInt, APInt, APInt> { 943 public: 944 /// Accesses the raw APInt value at this iterator position. 945 APInt operator*() const; 946 947 private: 948 friend DenseElementsAttr; 949 950 /// Constructs a new iterator. 951 IntElementIterator(DenseElementsAttr attr, size_t dataIndex); 952 953 /// The bitwidth of the element type. 954 size_t bitWidth; 955 }; 956 957 /// A utility iterator that allows walking over the internal raw complex APInt 958 /// values. 959 class ComplexIntElementIterator 960 : public detail::DenseElementIndexedIteratorImpl< 961 ComplexIntElementIterator, std::complex<APInt>, std::complex<APInt>, 962 std::complex<APInt>> { 963 public: 964 /// Accesses the raw std::complex<APInt> value at this iterator position. 965 std::complex<APInt> operator*() const; 966 967 private: 968 friend DenseElementsAttr; 969 970 /// Constructs a new iterator. 971 ComplexIntElementIterator(DenseElementsAttr attr, size_t dataIndex); 972 973 /// The bitwidth of the element type. 974 size_t bitWidth; 975 }; 976 977 /// Iterator for walking over APFloat values. 978 class FloatElementIterator final 979 : public llvm::mapped_iterator<IntElementIterator, 980 std::function<APFloat(const APInt &)>> { 981 friend DenseElementsAttr; 982 983 /// Initializes the float element iterator to the specified iterator. 984 FloatElementIterator(const llvm::fltSemantics &smt, IntElementIterator it); 985 986 public: 987 using reference = APFloat; 988 }; 989 990 /// Iterator for walking over complex APFloat values. 991 class ComplexFloatElementIterator final 992 : public llvm::mapped_iterator< 993 ComplexIntElementIterator, 994 std::function<std::complex<APFloat>(const std::complex<APInt> &)>> { 995 friend DenseElementsAttr; 996 997 /// Initializes the float element iterator to the specified iterator. 998 ComplexFloatElementIterator(const llvm::fltSemantics &smt, 999 ComplexIntElementIterator it); 1000 1001 public: 1002 using reference = std::complex<APFloat>; 1003 }; 1004 1005 //===--------------------------------------------------------------------===// 1006 // Value Querying 1007 //===--------------------------------------------------------------------===// 1008 1009 /// Returns if this attribute corresponds to a splat, i.e. if all element 1010 /// values are the same. 1011 bool isSplat() const; 1012 1013 /// Return the splat value for this attribute. This asserts that the attribute 1014 /// corresponds to a splat. 1015 Attribute getSplatValue() const { return getSplatValue<Attribute>(); } 1016 template <typename T> 1017 typename std::enable_if<!std::is_base_of<Attribute, T>::value || 1018 std::is_same<Attribute, T>::value, 1019 T>::type 1020 getSplatValue() const { 1021 assert(isSplat() && "expected the attribute to be a splat"); 1022 return *getValues<T>().begin(); 1023 } 1024 /// Return the splat value for derived attribute element types. 1025 template <typename T> 1026 typename std::enable_if<std::is_base_of<Attribute, T>::value && 1027 !std::is_same<Attribute, T>::value, 1028 T>::type 1029 getSplatValue() const { 1030 return getSplatValue().template cast<T>(); 1031 } 1032 1033 /// Return the value at the given index. The 'index' is expected to refer to a 1034 /// valid element. 1035 Attribute getValue(ArrayRef<uint64_t> index) const { 1036 return getValue<Attribute>(index); 1037 } 1038 template <typename T> T getValue(ArrayRef<uint64_t> index) const { 1039 // Skip to the element corresponding to the flattened index. 1040 return *std::next(getValues<T>().begin(), getFlattenedIndex(index)); 1041 } 1042 1043 /// Return the held element values as a range of integer or floating-point 1044 /// values. 1045 template <typename T, typename = typename std::enable_if< 1046 (!std::is_same<T, bool>::value && 1047 std::numeric_limits<T>::is_integer) || 1048 llvm::is_one_of<T, float, double>::value>::type> 1049 llvm::iterator_range<ElementIterator<T>> getValues() const { 1050 assert(isValidIntOrFloat(sizeof(T), std::numeric_limits<T>::is_integer, 1051 std::numeric_limits<T>::is_signed)); 1052 const char *rawData = getRawData().data(); 1053 bool splat = isSplat(); 1054 return {ElementIterator<T>(rawData, splat, 0), 1055 ElementIterator<T>(rawData, splat, getNumElements())}; 1056 } 1057 1058 /// Return the held element values as a range of std::complex. 1059 template <typename T, typename ElementT = typename T::value_type, 1060 typename = typename std::enable_if< 1061 detail::is_complex_t<T>::value && 1062 (std::numeric_limits<ElementT>::is_integer || 1063 llvm::is_one_of<ElementT, float, double>::value)>::type> 1064 llvm::iterator_range<ElementIterator<T>> getValues() const { 1065 assert(isValidComplex(sizeof(T), std::numeric_limits<ElementT>::is_integer, 1066 std::numeric_limits<ElementT>::is_signed)); 1067 const char *rawData = getRawData().data(); 1068 bool splat = isSplat(); 1069 return {ElementIterator<T>(rawData, splat, 0), 1070 ElementIterator<T>(rawData, splat, getNumElements())}; 1071 } 1072 1073 /// Return the held element values as a range of StringRef. 1074 template <typename T, typename = typename std::enable_if< 1075 std::is_same<T, StringRef>::value>::type> 1076 llvm::iterator_range<ElementIterator<StringRef>> getValues() const { 1077 auto stringRefs = getRawStringData(); 1078 const char *ptr = reinterpret_cast<const char *>(stringRefs.data()); 1079 bool splat = isSplat(); 1080 return {ElementIterator<StringRef>(ptr, splat, 0), 1081 ElementIterator<StringRef>(ptr, splat, getNumElements())}; 1082 } 1083 1084 /// Return the held element values as a range of Attributes. 1085 llvm::iterator_range<AttributeElementIterator> getAttributeValues() const; 1086 template <typename T, typename = typename std::enable_if< 1087 std::is_same<T, Attribute>::value>::type> 1088 llvm::iterator_range<AttributeElementIterator> getValues() const { 1089 return getAttributeValues(); 1090 } 1091 AttributeElementIterator attr_value_begin() const; 1092 AttributeElementIterator attr_value_end() const; 1093 1094 /// Return the held element values a range of T, where T is a derived 1095 /// attribute type. 1096 template <typename T> 1097 using DerivedAttributeElementIterator = 1098 llvm::mapped_iterator<AttributeElementIterator, T (*)(Attribute)>; 1099 template <typename T, typename = typename std::enable_if< 1100 std::is_base_of<Attribute, T>::value && 1101 !std::is_same<Attribute, T>::value>::type> 1102 llvm::iterator_range<DerivedAttributeElementIterator<T>> getValues() const { 1103 auto castFn = [](Attribute attr) { return attr.template cast<T>(); }; 1104 return llvm::map_range(getAttributeValues(), 1105 static_cast<T (*)(Attribute)>(castFn)); 1106 } 1107 1108 /// Return the held element values as a range of bool. The element type of 1109 /// this attribute must be of integer type of bitwidth 1. 1110 llvm::iterator_range<BoolElementIterator> getBoolValues() const; 1111 template <typename T, typename = typename std::enable_if< 1112 std::is_same<T, bool>::value>::type> 1113 llvm::iterator_range<BoolElementIterator> getValues() const { 1114 return getBoolValues(); 1115 } 1116 1117 /// Return the held element values as a range of APInts. The element type of 1118 /// this attribute must be of integer type. 1119 llvm::iterator_range<IntElementIterator> getIntValues() const; 1120 template <typename T, typename = typename std::enable_if< 1121 std::is_same<T, APInt>::value>::type> 1122 llvm::iterator_range<IntElementIterator> getValues() const { 1123 return getIntValues(); 1124 } 1125 IntElementIterator int_value_begin() const; 1126 IntElementIterator int_value_end() const; 1127 1128 /// Return the held element values as a range of complex APInts. The element 1129 /// type of this attribute must be a complex of integer type. 1130 llvm::iterator_range<ComplexIntElementIterator> getComplexIntValues() const; 1131 template <typename T, typename = typename std::enable_if< 1132 std::is_same<T, std::complex<APInt>>::value>::type> 1133 llvm::iterator_range<ComplexIntElementIterator> getValues() const { 1134 return getComplexIntValues(); 1135 } 1136 1137 /// Return the held element values as a range of APFloat. The element type of 1138 /// this attribute must be of float type. 1139 llvm::iterator_range<FloatElementIterator> getFloatValues() const; 1140 template <typename T, typename = typename std::enable_if< 1141 std::is_same<T, APFloat>::value>::type> 1142 llvm::iterator_range<FloatElementIterator> getValues() const { 1143 return getFloatValues(); 1144 } 1145 FloatElementIterator float_value_begin() const; 1146 FloatElementIterator float_value_end() const; 1147 1148 /// Return the held element values as a range of complex APFloat. The element 1149 /// type of this attribute must be a complex of float type. 1150 llvm::iterator_range<ComplexFloatElementIterator> 1151 getComplexFloatValues() const; 1152 template <typename T, typename = typename std::enable_if<std::is_same< 1153 T, std::complex<APFloat>>::value>::type> 1154 llvm::iterator_range<ComplexFloatElementIterator> getValues() const { 1155 return getComplexFloatValues(); 1156 } 1157 1158 /// Return the raw storage data held by this attribute. Users should generally 1159 /// not use this directly, as the internal storage format is not always in the 1160 /// form the user might expect. 1161 ArrayRef<char> getRawData() const; 1162 1163 /// Return the raw StringRef data held by this attribute. 1164 ArrayRef<StringRef> getRawStringData() const; 1165 1166 //===--------------------------------------------------------------------===// 1167 // Mutation Utilities 1168 //===--------------------------------------------------------------------===// 1169 1170 /// Return a new DenseElementsAttr that has the same data as the current 1171 /// attribute, but has been reshaped to 'newType'. The new type must have the 1172 /// same total number of elements as well as element type. 1173 DenseElementsAttr reshape(ShapedType newType); 1174 1175 /// Generates a new DenseElementsAttr by mapping each int value to a new 1176 /// underlying APInt. The new values can represent either an integer or float. 1177 /// This underlying type must be an DenseIntElementsAttr. 1178 DenseElementsAttr mapValues(Type newElementType, 1179 function_ref<APInt(const APInt &)> mapping) const; 1180 1181 /// Generates a new DenseElementsAttr by mapping each float value to a new 1182 /// underlying APInt. the new values can represent either an integer or float. 1183 /// This underlying type must be an DenseFPElementsAttr. 1184 DenseElementsAttr 1185 mapValues(Type newElementType, 1186 function_ref<APInt(const APFloat &)> mapping) const; 1187 1188 protected: 1189 /// Get iterators to the raw APInt values for each element in this attribute. 1190 IntElementIterator raw_int_begin() const { 1191 return IntElementIterator(*this, 0); 1192 } 1193 IntElementIterator raw_int_end() const { 1194 return IntElementIterator(*this, getNumElements()); 1195 } 1196 1197 /// Overload of the raw 'get' method that asserts that the given type is of 1198 /// complex type. This method is used to verify type invariants that the 1199 /// templatized 'get' method cannot. 1200 static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef<char> data, 1201 int64_t dataEltSize, bool isInt, 1202 bool isSigned); 1203 1204 /// Overload of the raw 'get' method that asserts that the given type is of 1205 /// integer or floating-point type. This method is used to verify type 1206 /// invariants that the templatized 'get' method cannot. 1207 static DenseElementsAttr getRawIntOrFloat(ShapedType type, 1208 ArrayRef<char> data, 1209 int64_t dataEltSize, bool isInt, 1210 bool isSigned); 1211 1212 /// Check the information for a C++ data type, check if this type is valid for 1213 /// the current attribute. This method is used to verify specific type 1214 /// invariants that the templatized 'getValues' method cannot. 1215 bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const; 1216 1217 /// Check the information for a C++ data type, check if this type is valid for 1218 /// the current attribute. This method is used to verify specific type 1219 /// invariants that the templatized 'getValues' method cannot. 1220 bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const; 1221 }; 1222 1223 /// An attribute class for representing dense arrays of strings. The structure 1224 /// storing and querying a list of densely packed strings. 1225 class DenseStringElementsAttr 1226 : public Attribute::AttrBase<DenseStringElementsAttr, DenseElementsAttr, 1227 detail::DenseStringElementsAttributeStorage> { 1228 1229 public: 1230 using Base::Base; 1231 1232 /// Method for support type inquiry through isa, cast and dyn_cast. 1233 static bool kindof(unsigned kind) { 1234 return kind == StandardAttributes::DenseStringElements; 1235 } 1236 1237 /// Overload of the raw 'get' method that asserts that the given type is of 1238 /// integer or floating-point type. This method is used to verify type 1239 /// invariants that the templatized 'get' method cannot. 1240 static DenseStringElementsAttr get(ShapedType type, ArrayRef<StringRef> data); 1241 1242 protected: 1243 friend DenseElementsAttr; 1244 }; 1245 1246 /// An attribute class for specializing behavior of Int and Floating-point 1247 /// densely packed string arrays. 1248 class DenseIntOrFPElementsAttr 1249 : public Attribute::AttrBase<DenseIntOrFPElementsAttr, DenseElementsAttr, 1250 detail::DenseIntOrFPElementsAttributeStorage> { 1251 1252 public: 1253 using Base::Base; 1254 1255 /// Method for support type inquiry through isa, cast and dyn_cast. 1256 static bool kindof(unsigned kind) { 1257 return kind == StandardAttributes::DenseIntOrFPElements; 1258 } 1259 1260 protected: 1261 friend DenseElementsAttr; 1262 1263 /// Constructs a dense elements attribute from an array of raw APFloat values. 1264 /// Each APFloat value is expected to have the same bitwidth as the element 1265 /// type of 'type'. 'type' must be a vector or tensor with static shape. 1266 static DenseElementsAttr getRaw(ShapedType type, size_t storageWidth, 1267 ArrayRef<APFloat> values, bool isSplat); 1268 1269 /// Constructs a dense elements attribute from an array of raw APInt values. 1270 /// Each APInt value is expected to have the same bitwidth as the element type 1271 /// of 'type'. 'type' must be a vector or tensor with static shape. 1272 static DenseElementsAttr getRaw(ShapedType type, size_t storageWidth, 1273 ArrayRef<APInt> values, bool isSplat); 1274 1275 /// Get or create a new dense elements attribute instance with the given raw 1276 /// data buffer. 'type' must be a vector or tensor with static shape. 1277 static DenseElementsAttr getRaw(ShapedType type, ArrayRef<char> data, 1278 bool isSplat); 1279 1280 /// Overload of the raw 'get' method that asserts that the given type is of 1281 /// complex type. This method is used to verify type invariants that the 1282 /// templatized 'get' method cannot. 1283 static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef<char> data, 1284 int64_t dataEltSize, bool isInt, 1285 bool isSigned); 1286 1287 /// Overload of the raw 'get' method that asserts that the given type is of 1288 /// integer or floating-point type. This method is used to verify type 1289 /// invariants that the templatized 'get' method cannot. 1290 static DenseElementsAttr getRawIntOrFloat(ShapedType type, 1291 ArrayRef<char> data, 1292 int64_t dataEltSize, bool isInt, 1293 bool isSigned); 1294 }; 1295 1296 /// An attribute that represents a reference to a dense float vector or tensor 1297 /// object. Each element is stored as a double. 1298 class DenseFPElementsAttr : public DenseIntOrFPElementsAttr { 1299 public: 1300 using iterator = DenseElementsAttr::FloatElementIterator; 1301 1302 using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; 1303 1304 /// Get an instance of a DenseFPElementsAttr with the given arguments. This 1305 /// simply wraps the DenseElementsAttr::get calls. 1306 template <typename Arg> 1307 static DenseFPElementsAttr get(const ShapedType &type, Arg &&arg) { 1308 return DenseElementsAttr::get(type, llvm::makeArrayRef(arg)) 1309 .template cast<DenseFPElementsAttr>(); 1310 } 1311 template <typename T> 1312 static DenseFPElementsAttr get(const ShapedType &type, 1313 const std::initializer_list<T> &list) { 1314 return DenseElementsAttr::get(type, list) 1315 .template cast<DenseFPElementsAttr>(); 1316 } 1317 1318 /// Generates a new DenseElementsAttr by mapping each value attribute, and 1319 /// constructing the DenseElementsAttr given the new element type. 1320 DenseElementsAttr 1321 mapValues(Type newElementType, 1322 function_ref<APInt(const APFloat &)> mapping) const; 1323 1324 /// Iterator access to the float element values. 1325 iterator begin() const { return float_value_begin(); } 1326 iterator end() const { return float_value_end(); } 1327 1328 /// Method for supporting type inquiry through isa, cast and dyn_cast. 1329 static bool classof(Attribute attr); 1330 }; 1331 1332 /// An attribute that represents a reference to a dense integer vector or tensor 1333 /// object. 1334 class DenseIntElementsAttr : public DenseIntOrFPElementsAttr { 1335 public: 1336 /// DenseIntElementsAttr iterates on APInt, so we can use the raw element 1337 /// iterator directly. 1338 using iterator = DenseElementsAttr::IntElementIterator; 1339 1340 using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; 1341 1342 /// Get an instance of a DenseIntElementsAttr with the given arguments. This 1343 /// simply wraps the DenseElementsAttr::get calls. 1344 template <typename Arg> 1345 static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg) { 1346 return DenseElementsAttr::get(type, llvm::makeArrayRef(arg)) 1347 .template cast<DenseIntElementsAttr>(); 1348 } 1349 template <typename T> 1350 static DenseIntElementsAttr get(const ShapedType &type, 1351 const std::initializer_list<T> &list) { 1352 return DenseElementsAttr::get(type, list) 1353 .template cast<DenseIntElementsAttr>(); 1354 } 1355 1356 /// Generates a new DenseElementsAttr by mapping each value attribute, and 1357 /// constructing the DenseElementsAttr given the new element type. 1358 DenseElementsAttr mapValues(Type newElementType, 1359 function_ref<APInt(const APInt &)> mapping) const; 1360 1361 /// Iterator access to the integer element values. 1362 iterator begin() const { return raw_int_begin(); } 1363 iterator end() const { return raw_int_end(); } 1364 1365 /// Method for supporting type inquiry through isa, cast and dyn_cast. 1366 static bool classof(Attribute attr); 1367 }; 1368 1369 /// An opaque attribute that represents a reference to a vector or tensor 1370 /// constant with opaque content. This representation is for tensor constants 1371 /// which the compiler may not need to interpret. This attribute is always 1372 /// associated with a particular dialect, which provides a method to convert 1373 /// tensor representation to a non-opaque format. 1374 class OpaqueElementsAttr 1375 : public Attribute::AttrBase<OpaqueElementsAttr, ElementsAttr, 1376 detail::OpaqueElementsAttributeStorage> { 1377 public: 1378 using Base::Base; 1379 using ValueType = StringRef; 1380 1381 static OpaqueElementsAttr get(Dialect *dialect, ShapedType type, 1382 StringRef bytes); 1383 1384 StringRef getValue() const; 1385 1386 /// Return the value at the given index. The 'index' is expected to refer to a 1387 /// valid element. 1388 Attribute getValue(ArrayRef<uint64_t> index) const; 1389 1390 /// Decodes the attribute value using dialect-specific decoding hook. 1391 /// Returns false if decoding is successful. If not, returns true and leaves 1392 /// 'result' argument unspecified. 1393 bool decode(ElementsAttr &result); 1394 1395 /// Returns dialect associated with this opaque constant. 1396 Dialect *getDialect() const; 1397 1398 /// Method for support type inquiry through isa, cast and dyn_cast. 1399 static bool kindof(unsigned kind) { 1400 return kind == StandardAttributes::OpaqueElements; 1401 } 1402 }; 1403 1404 /// An attribute that represents a reference to a sparse vector or tensor 1405 /// object. 1406 /// 1407 /// This class uses COO (coordinate list) encoding to represent the sparse 1408 /// elements in an element attribute. Specifically, the sparse vector/tensor 1409 /// stores the indices and values as two separate dense elements attributes of 1410 /// tensor type (even if the sparse attribute is of vector type, in order to 1411 /// support empty lists). The dense elements attribute indices is a 2-D tensor 1412 /// of 64-bit integer elements with shape [N, ndims], which specifies the 1413 /// indices of the elements in the sparse tensor that contains nonzero values. 1414 /// The dense elements attribute values is a 1-D tensor with shape [N], and it 1415 /// supplies the corresponding values for the indices. 1416 /// 1417 /// For example, 1418 /// `sparse<tensor<3x4xi32>, [[0, 0], [1, 2]], [1, 5]>` represents tensor 1419 /// [[1, 0, 0, 0], 1420 /// [0, 0, 5, 0], 1421 /// [0, 0, 0, 0]]. 1422 class SparseElementsAttr 1423 : public Attribute::AttrBase<SparseElementsAttr, ElementsAttr, 1424 detail::SparseElementsAttributeStorage> { 1425 public: 1426 using Base::Base; 1427 1428 template <typename T> 1429 using iterator = 1430 llvm::mapped_iterator<llvm::detail::value_sequence_iterator<ptrdiff_t>, 1431 std::function<T(ptrdiff_t)>>; 1432 1433 /// 'type' must be a vector or tensor with static shape. 1434 static SparseElementsAttr get(ShapedType type, DenseElementsAttr indices, 1435 DenseElementsAttr values); 1436 1437 DenseIntElementsAttr getIndices() const; 1438 1439 DenseElementsAttr getValues() const; 1440 1441 /// Return the values of this attribute in the form of the given type 'T'. 'T' 1442 /// may be any of Attribute, APInt, APFloat, c++ integer/float types, etc. 1443 template <typename T> llvm::iterator_range<iterator<T>> getValues() const { 1444 auto zeroValue = getZeroValue<T>(); 1445 auto valueIt = getValues().getValues<T>().begin(); 1446 const std::vector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices()); 1447 // TODO: Move-capture flatSparseIndices when c++14 is available. 1448 std::function<T(ptrdiff_t)> mapFn = [=](ptrdiff_t index) { 1449 // Try to map the current index to one of the sparse indices. 1450 for (unsigned i = 0, e = flatSparseIndices.size(); i != e; ++i) 1451 if (flatSparseIndices[i] == index) 1452 return *std::next(valueIt, i); 1453 // Otherwise, return the zero value. 1454 return zeroValue; 1455 }; 1456 return llvm::map_range(llvm::seq<ptrdiff_t>(0, getNumElements()), mapFn); 1457 } 1458 1459 /// Return the value of the element at the given index. The 'index' is 1460 /// expected to refer to a valid element. 1461 Attribute getValue(ArrayRef<uint64_t> index) const; 1462 1463 /// Method for support type inquiry through isa, cast and dyn_cast. 1464 static bool kindof(unsigned kind) { 1465 return kind == StandardAttributes::SparseElements; 1466 } 1467 1468 private: 1469 /// Get a zero APFloat for the given sparse attribute. 1470 APFloat getZeroAPFloat() const; 1471 1472 /// Get a zero APInt for the given sparse attribute. 1473 APInt getZeroAPInt() const; 1474 1475 /// Get a zero attribute for the given sparse attribute. 1476 Attribute getZeroAttr() const; 1477 1478 /// Utility methods to generate a zero value of some type 'T'. This is used by 1479 /// the 'iterator' class. 1480 /// Get a zero for a given attribute type. 1481 template <typename T> 1482 typename std::enable_if<std::is_base_of<Attribute, T>::value, T>::type 1483 getZeroValue() const { 1484 return getZeroAttr().template cast<T>(); 1485 } 1486 /// Get a zero for an APInt. 1487 template <typename T> 1488 typename std::enable_if<std::is_same<APInt, T>::value, T>::type 1489 getZeroValue() const { 1490 return getZeroAPInt(); 1491 } 1492 template <typename T> 1493 typename std::enable_if<std::is_same<std::complex<APInt>, T>::value, T>::type 1494 getZeroValue() const { 1495 APInt intZero = getZeroAPInt(); 1496 return {intZero, intZero}; 1497 } 1498 /// Get a zero for an APFloat. 1499 template <typename T> 1500 typename std::enable_if<std::is_same<APFloat, T>::value, T>::type 1501 getZeroValue() const { 1502 return getZeroAPFloat(); 1503 } 1504 template <typename T> 1505 typename std::enable_if<std::is_same<std::complex<APFloat>, T>::value, 1506 T>::type 1507 getZeroValue() const { 1508 APFloat floatZero = getZeroAPFloat(); 1509 return {floatZero, floatZero}; 1510 } 1511 1512 /// Get a zero for an C++ integer, float, StringRef, or complex type. 1513 template <typename T> 1514 typename std::enable_if< 1515 std::numeric_limits<T>::is_integer || 1516 llvm::is_one_of<T, float, double, StringRef>::value || 1517 (detail::is_complex_t<T>::value && 1518 !llvm::is_one_of<T, std::complex<APInt>, 1519 std::complex<APFloat>>::value), 1520 T>::type 1521 getZeroValue() const { 1522 return T(); 1523 } 1524 1525 /// Flatten, and return, all of the sparse indices in this attribute in 1526 /// row-major order. 1527 std::vector<ptrdiff_t> getFlattenedSparseIndices() const; 1528 }; 1529 1530 /// An attribute that represents a reference to a splat vector or tensor 1531 /// constant, meaning all of the elements have the same value. 1532 class SplatElementsAttr : public DenseElementsAttr { 1533 public: 1534 using DenseElementsAttr::DenseElementsAttr; 1535 1536 /// Method for support type inquiry through isa, cast and dyn_cast. 1537 static bool classof(Attribute attr) { 1538 auto denseAttr = attr.dyn_cast<DenseElementsAttr>(); 1539 return denseAttr && denseAttr.isSplat(); 1540 } 1541 }; 1542 1543 namespace detail { 1544 /// This class represents a general iterator over the values of an ElementsAttr. 1545 /// It supports all subclasses aside from OpaqueElementsAttr. 1546 template <typename T> 1547 class ElementsAttrIterator 1548 : public llvm::iterator_facade_base<ElementsAttrIterator<T>, 1549 std::random_access_iterator_tag, T, 1550 std::ptrdiff_t, T, T> { 1551 // NOTE: We use a dummy enable_if here because MSVC cannot use 'decltype' 1552 // inside of a conversion operator. 1553 using DenseIteratorT = typename std::enable_if< 1554 true, 1555 decltype(std::declval<DenseElementsAttr>().getValues<T>().begin())>::type; 1556 using SparseIteratorT = SparseElementsAttr::iterator<T>; 1557 1558 /// A union containing the specific iterators for each derived attribute kind. 1559 union Iterator { 1560 Iterator(DenseIteratorT &&it) : denseIt(std::move(it)) {} 1561 Iterator(SparseIteratorT &&it) : sparseIt(std::move(it)) {} 1562 Iterator() {} 1563 ~Iterator() {} 1564 1565 operator const DenseIteratorT &() const { return denseIt; } 1566 operator const SparseIteratorT &() const { return sparseIt; } 1567 operator DenseIteratorT &() { return denseIt; } 1568 operator SparseIteratorT &() { return sparseIt; } 1569 1570 /// An instance of a dense elements iterator. 1571 DenseIteratorT denseIt; 1572 /// An instance of a sparse elements iterator. 1573 SparseIteratorT sparseIt; 1574 }; 1575 1576 /// Utility method to process a functor on each of the internal iterator 1577 /// types. 1578 template <typename RetT, template <typename> class ProcessFn, 1579 typename... Args> 1580 RetT process(Args &... args) const { 1581 switch (attrKind) { 1582 case StandardAttributes::DenseIntOrFPElements: 1583 return ProcessFn<DenseIteratorT>()(args...); 1584 case StandardAttributes::SparseElements: 1585 return ProcessFn<SparseIteratorT>()(args...); 1586 } 1587 llvm_unreachable("unexpected attribute kind"); 1588 } 1589 1590 /// Utility functors used to generically implement the iterators methods. 1591 template <typename ItT> struct PlusAssign { 1592 void operator()(ItT &it, ptrdiff_t offset) { it += offset; } 1593 }; 1594 template <typename ItT> struct Minus { 1595 ptrdiff_t operator()(const ItT &lhs, const ItT &rhs) { return lhs - rhs; } 1596 }; 1597 template <typename ItT> struct MinusAssign { 1598 void operator()(ItT &it, ptrdiff_t offset) { it -= offset; } 1599 }; 1600 template <typename ItT> struct Dereference { 1601 T operator()(ItT &it) { return *it; } 1602 }; 1603 template <typename ItT> struct ConstructIter { 1604 void operator()(ItT &dest, const ItT &it) { ::new (&dest) ItT(it); } 1605 }; 1606 template <typename ItT> struct DestructIter { 1607 void operator()(ItT &it) { it.~ItT(); } 1608 }; 1609 1610 public: 1611 ElementsAttrIterator(const ElementsAttrIterator<T> &rhs) 1612 : attrKind(rhs.attrKind) { 1613 process<void, ConstructIter>(it, rhs.it); 1614 } 1615 ~ElementsAttrIterator() { process<void, DestructIter>(it); } 1616 1617 /// Methods necessary to support random access iteration. 1618 ptrdiff_t operator-(const ElementsAttrIterator<T> &rhs) const { 1619 assert(attrKind == rhs.attrKind && "incompatible iterators"); 1620 return process<ptrdiff_t, Minus>(it, rhs.it); 1621 } 1622 bool operator==(const ElementsAttrIterator<T> &rhs) const { 1623 return rhs.attrKind == attrKind && process<bool, std::equal_to>(it, rhs.it); 1624 } 1625 bool operator<(const ElementsAttrIterator<T> &rhs) const { 1626 assert(attrKind == rhs.attrKind && "incompatible iterators"); 1627 return process<bool, std::less>(it, rhs.it); 1628 } 1629 ElementsAttrIterator<T> &operator+=(ptrdiff_t offset) { 1630 process<void, PlusAssign>(it, offset); 1631 return *this; 1632 } 1633 ElementsAttrIterator<T> &operator-=(ptrdiff_t offset) { 1634 process<void, MinusAssign>(it, offset); 1635 return *this; 1636 } 1637 1638 /// Dereference the iterator at the current index. 1639 T operator*() { return process<T, Dereference>(it); } 1640 1641 private: 1642 template <typename IteratorT> 1643 ElementsAttrIterator(unsigned attrKind, IteratorT &&it) 1644 : attrKind(attrKind), it(std::forward<IteratorT>(it)) {} 1645 1646 /// Allow accessing the constructor. 1647 friend ElementsAttr; 1648 1649 /// The kind of derived elements attribute. 1650 unsigned attrKind; 1651 1652 /// A union containing the specific iterators for each derived kind. 1653 Iterator it; 1654 }; 1655 1656 template <typename T> 1657 class ElementsAttrRange : public llvm::iterator_range<ElementsAttrIterator<T>> { 1658 using llvm::iterator_range<ElementsAttrIterator<T>>::iterator_range; 1659 }; 1660 } // namespace detail 1661 1662 /// Return the elements of this attribute as a value of type 'T'. 1663 template <typename T> 1664 auto ElementsAttr::getValues() const -> iterator_range<T> { 1665 if (DenseElementsAttr denseAttr = dyn_cast<DenseElementsAttr>()) { 1666 auto values = denseAttr.getValues<T>(); 1667 return {iterator<T>(getKind(), values.begin()), 1668 iterator<T>(getKind(), values.end())}; 1669 } 1670 if (SparseElementsAttr sparseAttr = dyn_cast<SparseElementsAttr>()) { 1671 auto values = sparseAttr.getValues<T>(); 1672 return {iterator<T>(getKind(), values.begin()), 1673 iterator<T>(getKind(), values.end())}; 1674 } 1675 llvm_unreachable("unexpected attribute kind"); 1676 } 1677 1678 //===----------------------------------------------------------------------===// 1679 // Attributes Utils 1680 //===----------------------------------------------------------------------===// 1681 1682 template <typename U> bool Attribute::isa() const { 1683 assert(impl && "isa<> used on a null attribute."); 1684 return U::classof(*this); 1685 } 1686 1687 template <typename First, typename Second, typename... Rest> 1688 bool Attribute::isa() const { 1689 return isa<First>() || isa<Second, Rest...>(); 1690 } 1691 1692 template <typename U> U Attribute::dyn_cast() const { 1693 return isa<U>() ? U(impl) : U(nullptr); 1694 } 1695 template <typename U> U Attribute::dyn_cast_or_null() const { 1696 return (impl && isa<U>()) ? U(impl) : U(nullptr); 1697 } 1698 template <typename U> U Attribute::cast() const { 1699 assert(isa<U>()); 1700 return U(impl); 1701 } 1702 1703 // Make Attribute hashable. 1704 inline ::llvm::hash_code hash_value(Attribute arg) { 1705 return ::llvm::hash_value(arg.impl); 1706 } 1707 1708 //===----------------------------------------------------------------------===// 1709 // MutableDictionaryAttr 1710 //===----------------------------------------------------------------------===// 1711 1712 /// A MutableDictionaryAttr is a mutable wrapper around a DictionaryAttr. It 1713 /// provides additional interfaces for adding, removing, replacing attributes 1714 /// within a DictionaryAttr. 1715 /// 1716 /// We assume there will be relatively few attributes on a given operation 1717 /// (maybe a dozen or so, but not hundreds or thousands) so we use linear 1718 /// searches for everything. 1719 class MutableDictionaryAttr { 1720 public: 1721 MutableDictionaryAttr(DictionaryAttr attrs = nullptr) 1722 : attrs((attrs && !attrs.empty()) ? attrs : nullptr) {} 1723 MutableDictionaryAttr(ArrayRef<NamedAttribute> attributes); 1724 1725 bool operator!=(const MutableDictionaryAttr &other) const { 1726 return !(*this == other); 1727 } 1728 bool operator==(const MutableDictionaryAttr &other) const { 1729 return attrs == other.attrs; 1730 } 1731 1732 /// Return the underlying dictionary attribute. 1733 DictionaryAttr getDictionary(MLIRContext *context) const; 1734 1735 /// Return all of the attributes on this operation. 1736 ArrayRef<NamedAttribute> getAttrs() const; 1737 1738 /// Replace the held attributes with ones provided in 'newAttrs'. 1739 void setAttrs(ArrayRef<NamedAttribute> attributes); 1740 1741 /// Return the specified attribute if present, null otherwise. 1742 Attribute get(StringRef name) const; 1743 Attribute get(Identifier name) const; 1744 1745 /// Return the specified named attribute if present, None otherwise. 1746 Optional<NamedAttribute> getNamed(StringRef name) const; 1747 Optional<NamedAttribute> getNamed(Identifier name) const; 1748 1749 /// If the an attribute exists with the specified name, change it to the new 1750 /// value. Otherwise, add a new attribute with the specified name/value. 1751 void set(Identifier name, Attribute value); 1752 1753 enum class RemoveResult { Removed, NotFound }; 1754 1755 /// Remove the attribute with the specified name if it exists. The return 1756 /// value indicates whether the attribute was present or not. 1757 RemoveResult remove(Identifier name); 1758 1759 bool empty() const { return attrs == nullptr; } 1760 1761 private: 1762 friend ::llvm::hash_code hash_value(const MutableDictionaryAttr &arg); 1763 1764 DictionaryAttr attrs; 1765 }; 1766 1767 inline ::llvm::hash_code hash_value(const MutableDictionaryAttr &arg) { 1768 if (!arg.attrs) 1769 return ::llvm::hash_value((void *)nullptr); 1770 return hash_value(arg.attrs); 1771 } 1772 1773 } // end namespace mlir. 1774 1775 namespace llvm { 1776 1777 // Attribute hash just like pointers. 1778 template <> struct DenseMapInfo<mlir::Attribute> { 1779 static mlir::Attribute getEmptyKey() { 1780 auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); 1781 return mlir::Attribute(static_cast<mlir::Attribute::ImplType *>(pointer)); 1782 } 1783 static mlir::Attribute getTombstoneKey() { 1784 auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); 1785 return mlir::Attribute(static_cast<mlir::Attribute::ImplType *>(pointer)); 1786 } 1787 static unsigned getHashValue(mlir::Attribute val) { 1788 return mlir::hash_value(val); 1789 } 1790 static bool isEqual(mlir::Attribute LHS, mlir::Attribute RHS) { 1791 return LHS == RHS; 1792 } 1793 }; 1794 1795 /// Allow LLVM to steal the low bits of Attributes. 1796 template <> struct PointerLikeTypeTraits<mlir::Attribute> { 1797 static inline void *getAsVoidPointer(mlir::Attribute attr) { 1798 return const_cast<void *>(attr.getAsOpaquePointer()); 1799 } 1800 static inline mlir::Attribute getFromVoidPointer(void *ptr) { 1801 return mlir::Attribute::getFromOpaquePointer(ptr); 1802 } 1803 static constexpr int NumLowBitsAvailable = 3; 1804 }; 1805 1806 template <> 1807 struct PointerLikeTypeTraits<mlir::SymbolRefAttr> 1808 : public PointerLikeTypeTraits<mlir::Attribute> { 1809 static inline mlir::SymbolRefAttr getFromVoidPointer(void *ptr) { 1810 return PointerLikeTypeTraits<mlir::Attribute>::getFromVoidPointer(ptr) 1811 .cast<mlir::SymbolRefAttr>(); 1812 } 1813 }; 1814 1815 } // namespace llvm 1816 1817 #endif 1818