1 //===- BuiltinAttributes.h - MLIR Builtin 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_BUILTINATTRIBUTES_H 10 #define MLIR_IR_BUILTINATTRIBUTES_H 11 12 #include "mlir/IR/BuiltinAttributeInterfaces.h" 13 #include "mlir/IR/SubElementInterfaces.h" 14 #include "llvm/ADT/APFloat.h" 15 #include "llvm/ADT/Sequence.h" 16 #include <complex> 17 18 namespace mlir { 19 class AffineMap; 20 class BoolAttr; 21 class DenseIntElementsAttr; 22 class FlatSymbolRefAttr; 23 class FunctionType; 24 class IntegerSet; 25 class IntegerType; 26 class Location; 27 class Operation; 28 class ShapedType; 29 30 //===----------------------------------------------------------------------===// 31 // Elements Attributes 32 //===----------------------------------------------------------------------===// 33 34 namespace detail { 35 /// Pair of raw pointer and a boolean flag of whether the pointer holds a splat, 36 using DenseIterPtrAndSplat = std::pair<const char *, bool>; 37 38 /// Impl iterator for indexed DenseElementsAttr iterators that records a data 39 /// pointer and data index that is adjusted for the case of a splat attribute. 40 template <typename ConcreteT, typename T, typename PointerT = T *, 41 typename ReferenceT = T &> 42 class DenseElementIndexedIteratorImpl 43 : public llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, 44 PointerT, ReferenceT> { 45 protected: DenseElementIndexedIteratorImpl(const char * data,bool isSplat,size_t dataIndex)46 DenseElementIndexedIteratorImpl(const char *data, bool isSplat, 47 size_t dataIndex) 48 : llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, 49 PointerT, ReferenceT>({data, isSplat}, 50 dataIndex) {} 51 52 /// Return the current index for this iterator, adjusted for the case of a 53 /// splat. getDataIndex()54 ptrdiff_t getDataIndex() const { 55 bool isSplat = this->base.second; 56 return isSplat ? 0 : this->index; 57 } 58 59 /// Return the data base pointer. getData()60 const char *getData() const { return this->base.first; } 61 }; 62 63 /// Type trait detector that checks if a given type T is a complex type. 64 template <typename T> 65 struct is_complex_t : public std::false_type {}; 66 template <typename T> 67 struct is_complex_t<std::complex<T>> : public std::true_type {}; 68 } // namespace detail 69 70 /// An attribute that represents a reference to a dense vector or tensor 71 /// object. 72 class DenseElementsAttr : public Attribute { 73 public: 74 using Attribute::Attribute; 75 76 /// Allow implicit conversion to ElementsAttr. 77 operator ElementsAttr() const { 78 return *this ? cast<ElementsAttr>() : nullptr; 79 } 80 81 /// Type trait used to check if the given type T is a potentially valid C++ 82 /// floating point type that can be used to access the underlying element 83 /// types of a DenseElementsAttr. 84 // TODO: Use std::disjunction when C++17 is supported. 85 template <typename T> 86 struct is_valid_cpp_fp_type { 87 /// The type is a valid floating point type if it is a builtin floating 88 /// point type, or is a potentially user defined floating point type. The 89 /// latter allows for supporting users that have custom types defined for 90 /// bfloat16/half/etc. 91 static constexpr bool value = llvm::is_one_of<T, float, double>::value || 92 (std::numeric_limits<T>::is_specialized && 93 !std::numeric_limits<T>::is_integer); 94 }; 95 96 /// Method for support type inquiry through isa, cast and dyn_cast. 97 static bool classof(Attribute attr); 98 99 /// Constructs a dense elements attribute from an array of element values. 100 /// Each element attribute value is expected to be an element of 'type'. 101 /// 'type' must be a vector or tensor with static shape. If the element of 102 /// `type` is non-integer/index/float it is assumed to be a string type. 103 static DenseElementsAttr get(ShapedType type, ArrayRef<Attribute> values); 104 105 /// Constructs a dense integer elements attribute from an array of integer 106 /// or floating-point values. Each value is expected to be the same bitwidth 107 /// of the element type of 'type'. 'type' must be a vector or tensor with 108 /// static shape. 109 template <typename T, typename = typename std::enable_if< 110 std::numeric_limits<T>::is_integer || 111 is_valid_cpp_fp_type<T>::value>::type> 112 static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { 113 const char *data = reinterpret_cast<const char *>(values.data()); 114 return getRawIntOrFloat( 115 type, ArrayRef<char>(data, values.size() * sizeof(T)), sizeof(T), 116 std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed); 117 } 118 119 /// Constructs a dense integer elements attribute from a single element. 120 template <typename T, typename = typename std::enable_if< 121 std::numeric_limits<T>::is_integer || 122 is_valid_cpp_fp_type<T>::value || 123 detail::is_complex_t<T>::value>::type> 124 static DenseElementsAttr get(const ShapedType &type, T value) { 125 return get(type, llvm::makeArrayRef(value)); 126 } 127 128 /// Constructs a dense complex elements attribute from an array of complex 129 /// values. Each value is expected to be the same bitwidth of the element type 130 /// of 'type'. 'type' must be a vector or tensor with static shape. 131 template <typename T, typename ElementT = typename T::value_type, 132 typename = typename std::enable_if< 133 detail::is_complex_t<T>::value && 134 (std::numeric_limits<ElementT>::is_integer || 135 is_valid_cpp_fp_type<ElementT>::value)>::type> 136 static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { 137 const char *data = reinterpret_cast<const char *>(values.data()); 138 return getRawComplex(type, ArrayRef<char>(data, values.size() * sizeof(T)), 139 sizeof(T), std::numeric_limits<ElementT>::is_integer, 140 std::numeric_limits<ElementT>::is_signed); 141 } 142 143 /// Overload of the above 'get' method that is specialized for boolean values. 144 static DenseElementsAttr get(ShapedType type, ArrayRef<bool> values); 145 146 /// Overload of the above 'get' method that is specialized for StringRef 147 /// values. 148 static DenseElementsAttr get(ShapedType type, ArrayRef<StringRef> values); 149 150 /// Constructs a dense integer elements attribute from an array of APInt 151 /// values. Each APInt value is expected to have the same bitwidth as the 152 /// element type of 'type'. 'type' must be a vector or tensor with static 153 /// shape. 154 static DenseElementsAttr get(ShapedType type, ArrayRef<APInt> values); 155 156 /// Constructs a dense complex elements attribute from an array of APInt 157 /// values. Each APInt value is expected to have the same bitwidth as the 158 /// element type of 'type'. 'type' must be a vector or tensor with static 159 /// shape. 160 static DenseElementsAttr get(ShapedType type, 161 ArrayRef<std::complex<APInt>> values); 162 163 /// Constructs a dense float elements attribute from an array of APFloat 164 /// values. Each APFloat value is expected to have the same bitwidth as the 165 /// element type of 'type'. 'type' must be a vector or tensor with static 166 /// shape. 167 static DenseElementsAttr get(ShapedType type, ArrayRef<APFloat> values); 168 169 /// Constructs a dense complex elements attribute from an array of APFloat 170 /// values. Each APFloat value is expected to have the same bitwidth as the 171 /// element type of 'type'. 'type' must be a vector or tensor with static 172 /// shape. 173 static DenseElementsAttr get(ShapedType type, 174 ArrayRef<std::complex<APFloat>> values); 175 176 /// Construct a dense elements attribute for an initializer_list of values. 177 /// Each value is expected to be the same bitwidth of the element type of 178 /// 'type'. 'type' must be a vector or tensor with static shape. 179 template <typename T> 180 static DenseElementsAttr get(const ShapedType &type, 181 const std::initializer_list<T> &list) { 182 return get(type, ArrayRef<T>(list)); 183 } 184 185 /// Construct a dense elements attribute from a raw buffer representing the 186 /// data for this attribute. Users are encouraged to use one of the 187 /// constructors above, which provide more safeties. However, this 188 /// constructor is useful for tools which may want to interop and can 189 /// follow the precise definition. 190 /// 191 /// The format of the raw buffer is a densely packed array of values that 192 /// can be bitcast to the storage format of the element type specified. 193 /// Types that are not byte aligned will be: 194 /// - For bitwidth > 1: Rounded up to the next byte. 195 /// - For bitwidth = 1: Packed into 8bit bytes with bits corresponding to 196 /// the linear order of the shape type from MSB to LSB, padded to on the 197 /// right. 198 static DenseElementsAttr getFromRawBuffer(ShapedType type, 199 ArrayRef<char> rawBuffer); 200 201 /// Returns true if the given buffer is a valid raw buffer for the given type. 202 /// `detectedSplat` is set if the buffer is valid and represents a splat 203 /// buffer. The definition may be expanded over time, but currently, a 204 /// splat buffer is detected if: 205 /// - For >1bit: The buffer consists of a single element. 206 /// - For 1bit: The buffer consists of a single byte with value 0 or 255. 207 /// 208 /// User code should be prepared for additional, conformant patterns to be 209 /// identified as splats in the future. 210 static bool isValidRawBuffer(ShapedType type, ArrayRef<char> rawBuffer, 211 bool &detectedSplat); 212 213 //===--------------------------------------------------------------------===// 214 // Iterators 215 //===--------------------------------------------------------------------===// 216 217 /// The iterator range over the given iterator type T. 218 template <typename IteratorT> 219 using iterator_range_impl = detail::ElementsAttrRange<IteratorT>; 220 221 /// The iterator for the given element type T. 222 template <typename T, typename AttrT = DenseElementsAttr> 223 using iterator = decltype(std::declval<AttrT>().template value_begin<T>()); 224 /// The iterator range over the given element T. 225 template <typename T, typename AttrT = DenseElementsAttr> 226 using iterator_range = 227 decltype(std::declval<AttrT>().template getValues<T>()); 228 229 /// A utility iterator that allows walking over the internal Attribute values 230 /// of a DenseElementsAttr. 231 class AttributeElementIterator 232 : public llvm::indexed_accessor_iterator<AttributeElementIterator, 233 const void *, Attribute, 234 Attribute, Attribute> { 235 public: 236 /// Accesses the Attribute value at this iterator position. 237 Attribute operator*() const; 238 239 private: 240 friend DenseElementsAttr; 241 242 /// Constructs a new iterator. 243 AttributeElementIterator(DenseElementsAttr attr, size_t index); 244 }; 245 246 /// Iterator for walking raw element values of the specified type 'T', which 247 /// may be any c++ data type matching the stored representation: int32_t, 248 /// float, etc. 249 template <typename T> 250 class ElementIterator 251 : public detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, 252 const T> { 253 public: 254 /// Accesses the raw value at this iterator position. 255 const T &operator*() const { 256 return reinterpret_cast<const T *>(this->getData())[this->getDataIndex()]; 257 } 258 259 private: 260 friend DenseElementsAttr; 261 262 /// Constructs a new iterator. 263 ElementIterator(const char *data, bool isSplat, size_t dataIndex) 264 : detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, const T>( 265 data, isSplat, dataIndex) {} 266 }; 267 268 /// A utility iterator that allows walking over the internal bool values. 269 class BoolElementIterator 270 : public detail::DenseElementIndexedIteratorImpl<BoolElementIterator, 271 bool, bool, bool> { 272 public: 273 /// Accesses the bool value at this iterator position. 274 bool operator*() const; 275 276 private: 277 friend DenseElementsAttr; 278 279 /// Constructs a new iterator. 280 BoolElementIterator(DenseElementsAttr attr, size_t dataIndex); 281 }; 282 283 /// A utility iterator that allows walking over the internal raw APInt values. 284 class IntElementIterator 285 : public detail::DenseElementIndexedIteratorImpl<IntElementIterator, 286 APInt, APInt, APInt> { 287 public: 288 /// Accesses the raw APInt value at this iterator position. 289 APInt operator*() const; 290 291 private: 292 friend DenseElementsAttr; 293 294 /// Constructs a new iterator. 295 IntElementIterator(DenseElementsAttr attr, size_t dataIndex); 296 297 /// The bitwidth of the element type. 298 size_t bitWidth; 299 }; 300 301 /// A utility iterator that allows walking over the internal raw complex APInt 302 /// values. 303 class ComplexIntElementIterator 304 : public detail::DenseElementIndexedIteratorImpl< 305 ComplexIntElementIterator, std::complex<APInt>, std::complex<APInt>, 306 std::complex<APInt>> { 307 public: 308 /// Accesses the raw std::complex<APInt> value at this iterator position. 309 std::complex<APInt> operator*() const; 310 311 private: 312 friend DenseElementsAttr; 313 314 /// Constructs a new iterator. 315 ComplexIntElementIterator(DenseElementsAttr attr, size_t dataIndex); 316 317 /// The bitwidth of the element type. 318 size_t bitWidth; 319 }; 320 321 /// Iterator for walking over APFloat values. 322 class FloatElementIterator final 323 : public llvm::mapped_iterator_base<FloatElementIterator, 324 IntElementIterator, APFloat> { 325 public: 326 /// Map the element to the iterator result type. 327 APFloat mapElement(const APInt &value) const { 328 return APFloat(*smt, value); 329 } 330 331 private: 332 friend DenseElementsAttr; 333 334 /// Initializes the float element iterator to the specified iterator. 335 FloatElementIterator(const llvm::fltSemantics &smt, IntElementIterator it) 336 : BaseT(it), smt(&smt) {} 337 338 /// The float semantics to use when constructing the APFloat. 339 const llvm::fltSemantics *smt; 340 }; 341 342 /// Iterator for walking over complex APFloat values. 343 class ComplexFloatElementIterator final 344 : public llvm::mapped_iterator_base<ComplexFloatElementIterator, 345 ComplexIntElementIterator, 346 std::complex<APFloat>> { 347 public: 348 /// Map the element to the iterator result type. 349 std::complex<APFloat> mapElement(const std::complex<APInt> &value) const { 350 return {APFloat(*smt, value.real()), APFloat(*smt, value.imag())}; 351 } 352 353 private: 354 friend DenseElementsAttr; 355 356 /// Initializes the float element iterator to the specified iterator. 357 ComplexFloatElementIterator(const llvm::fltSemantics &smt, 358 ComplexIntElementIterator it) 359 : BaseT(it), smt(&smt) {} 360 361 /// The float semantics to use when constructing the APFloat. 362 const llvm::fltSemantics *smt; 363 }; 364 365 //===--------------------------------------------------------------------===// 366 // Value Querying 367 //===--------------------------------------------------------------------===// 368 369 /// Returns true if this attribute corresponds to a splat, i.e. if all element 370 /// values are the same. 371 bool isSplat() const; 372 373 /// Return the splat value for this attribute. This asserts that the attribute 374 /// corresponds to a splat. 375 template <typename T> 376 typename std::enable_if<!std::is_base_of<Attribute, T>::value || 377 std::is_same<Attribute, T>::value, 378 T>::type 379 getSplatValue() const { 380 assert(isSplat() && "expected the attribute to be a splat"); 381 return *value_begin<T>(); 382 } 383 /// Return the splat value for derived attribute element types. 384 template <typename T> 385 typename std::enable_if<std::is_base_of<Attribute, T>::value && 386 !std::is_same<Attribute, T>::value, 387 T>::type 388 getSplatValue() const { 389 return getSplatValue<Attribute>().template cast<T>(); 390 } 391 392 /// Return the held element values as a range of integer or floating-point 393 /// values. 394 template <typename T> 395 using IntFloatValueTemplateCheckT = 396 typename std::enable_if<(!std::is_same<T, bool>::value && 397 std::numeric_limits<T>::is_integer) || 398 is_valid_cpp_fp_type<T>::value>::type; 399 template <typename T, typename = IntFloatValueTemplateCheckT<T>> 400 iterator_range_impl<ElementIterator<T>> getValues() const { 401 assert(isValidIntOrFloat(sizeof(T), std::numeric_limits<T>::is_integer, 402 std::numeric_limits<T>::is_signed)); 403 const char *rawData = getRawData().data(); 404 bool splat = isSplat(); 405 return {Attribute::getType(), ElementIterator<T>(rawData, splat, 0), 406 ElementIterator<T>(rawData, splat, getNumElements())}; 407 } 408 template <typename T, typename = IntFloatValueTemplateCheckT<T>> 409 ElementIterator<T> value_begin() const { 410 assert(isValidIntOrFloat(sizeof(T), std::numeric_limits<T>::is_integer, 411 std::numeric_limits<T>::is_signed)); 412 return ElementIterator<T>(getRawData().data(), isSplat(), 0); 413 } 414 template <typename T, typename = IntFloatValueTemplateCheckT<T>> 415 ElementIterator<T> value_end() const { 416 assert(isValidIntOrFloat(sizeof(T), std::numeric_limits<T>::is_integer, 417 std::numeric_limits<T>::is_signed)); 418 return ElementIterator<T>(getRawData().data(), isSplat(), getNumElements()); 419 } 420 421 /// Return the held element values as a range of std::complex. 422 template <typename T, typename ElementT> 423 using ComplexValueTemplateCheckT = 424 typename std::enable_if<detail::is_complex_t<T>::value && 425 (std::numeric_limits<ElementT>::is_integer || 426 is_valid_cpp_fp_type<ElementT>::value)>::type; 427 template <typename T, typename ElementT = typename T::value_type, 428 typename = ComplexValueTemplateCheckT<T, ElementT>> 429 iterator_range_impl<ElementIterator<T>> getValues() const { 430 assert(isValidComplex(sizeof(T), std::numeric_limits<ElementT>::is_integer, 431 std::numeric_limits<ElementT>::is_signed)); 432 const char *rawData = getRawData().data(); 433 bool splat = isSplat(); 434 return {Attribute::getType(), ElementIterator<T>(rawData, splat, 0), 435 ElementIterator<T>(rawData, splat, getNumElements())}; 436 } 437 template <typename T, typename ElementT = typename T::value_type, 438 typename = ComplexValueTemplateCheckT<T, ElementT>> 439 ElementIterator<T> value_begin() const { 440 assert(isValidComplex(sizeof(T), std::numeric_limits<ElementT>::is_integer, 441 std::numeric_limits<ElementT>::is_signed)); 442 return ElementIterator<T>(getRawData().data(), isSplat(), 0); 443 } 444 template <typename T, typename ElementT = typename T::value_type, 445 typename = ComplexValueTemplateCheckT<T, ElementT>> 446 ElementIterator<T> value_end() const { 447 assert(isValidComplex(sizeof(T), std::numeric_limits<ElementT>::is_integer, 448 std::numeric_limits<ElementT>::is_signed)); 449 return ElementIterator<T>(getRawData().data(), isSplat(), getNumElements()); 450 } 451 452 /// Return the held element values as a range of StringRef. 453 template <typename T> 454 using StringRefValueTemplateCheckT = 455 typename std::enable_if<std::is_same<T, StringRef>::value>::type; 456 template <typename T, typename = StringRefValueTemplateCheckT<T>> 457 iterator_range_impl<ElementIterator<StringRef>> getValues() const { 458 auto stringRefs = getRawStringData(); 459 const char *ptr = reinterpret_cast<const char *>(stringRefs.data()); 460 bool splat = isSplat(); 461 return {Attribute::getType(), ElementIterator<StringRef>(ptr, splat, 0), 462 ElementIterator<StringRef>(ptr, splat, getNumElements())}; 463 } 464 template <typename T, typename = StringRefValueTemplateCheckT<T>> 465 ElementIterator<StringRef> value_begin() const { 466 const char *ptr = reinterpret_cast<const char *>(getRawStringData().data()); 467 return ElementIterator<StringRef>(ptr, isSplat(), 0); 468 } 469 template <typename T, typename = StringRefValueTemplateCheckT<T>> 470 ElementIterator<StringRef> value_end() const { 471 const char *ptr = reinterpret_cast<const char *>(getRawStringData().data()); 472 return ElementIterator<StringRef>(ptr, isSplat(), getNumElements()); 473 } 474 475 /// Return the held element values as a range of Attributes. 476 template <typename T> 477 using AttributeValueTemplateCheckT = 478 typename std::enable_if<std::is_same<T, Attribute>::value>::type; 479 template <typename T, typename = AttributeValueTemplateCheckT<T>> 480 iterator_range_impl<AttributeElementIterator> getValues() const { 481 return {Attribute::getType(), value_begin<Attribute>(), 482 value_end<Attribute>()}; 483 } 484 template <typename T, typename = AttributeValueTemplateCheckT<T>> 485 AttributeElementIterator value_begin() const { 486 return AttributeElementIterator(*this, 0); 487 } 488 template <typename T, typename = AttributeValueTemplateCheckT<T>> 489 AttributeElementIterator value_end() const { 490 return AttributeElementIterator(*this, getNumElements()); 491 } 492 493 /// Return the held element values a range of T, where T is a derived 494 /// attribute type. 495 template <typename T> 496 using DerivedAttrValueTemplateCheckT = 497 typename std::enable_if<std::is_base_of<Attribute, T>::value && 498 !std::is_same<Attribute, T>::value>::type; 499 template <typename T> 500 struct DerivedAttributeElementIterator 501 : public llvm::mapped_iterator_base<DerivedAttributeElementIterator<T>, 502 AttributeElementIterator, T> { 503 using llvm::mapped_iterator_base<DerivedAttributeElementIterator<T>, 504 AttributeElementIterator, 505 T>::mapped_iterator_base; 506 507 /// Map the element to the iterator result type. 508 T mapElement(Attribute attr) const { return attr.cast<T>(); } 509 }; 510 template <typename T, typename = DerivedAttrValueTemplateCheckT<T>> 511 iterator_range_impl<DerivedAttributeElementIterator<T>> getValues() const { 512 using DerivedIterT = DerivedAttributeElementIterator<T>; 513 return {Attribute::getType(), DerivedIterT(value_begin<Attribute>()), 514 DerivedIterT(value_end<Attribute>())}; 515 } 516 template <typename T, typename = DerivedAttrValueTemplateCheckT<T>> 517 DerivedAttributeElementIterator<T> value_begin() const { 518 return {value_begin<Attribute>()}; 519 } 520 template <typename T, typename = DerivedAttrValueTemplateCheckT<T>> 521 DerivedAttributeElementIterator<T> value_end() const { 522 return {value_end<Attribute>()}; 523 } 524 525 /// Return the held element values as a range of bool. The element type of 526 /// this attribute must be of integer type of bitwidth 1. 527 template <typename T> 528 using BoolValueTemplateCheckT = 529 typename std::enable_if<std::is_same<T, bool>::value>::type; 530 template <typename T, typename = BoolValueTemplateCheckT<T>> 531 iterator_range_impl<BoolElementIterator> getValues() const { 532 assert(isValidBool() && "bool is not the value of this elements attribute"); 533 return {Attribute::getType(), BoolElementIterator(*this, 0), 534 BoolElementIterator(*this, getNumElements())}; 535 } 536 template <typename T, typename = BoolValueTemplateCheckT<T>> 537 BoolElementIterator value_begin() const { 538 assert(isValidBool() && "bool is not the value of this elements attribute"); 539 return BoolElementIterator(*this, 0); 540 } 541 template <typename T, typename = BoolValueTemplateCheckT<T>> 542 BoolElementIterator value_end() const { 543 assert(isValidBool() && "bool is not the value of this elements attribute"); 544 return BoolElementIterator(*this, getNumElements()); 545 } 546 547 /// Return the held element values as a range of APInts. The element type of 548 /// this attribute must be of integer type. 549 template <typename T> 550 using APIntValueTemplateCheckT = 551 typename std::enable_if<std::is_same<T, APInt>::value>::type; 552 template <typename T, typename = APIntValueTemplateCheckT<T>> 553 iterator_range_impl<IntElementIterator> getValues() const { 554 assert(getElementType().isIntOrIndex() && "expected integral type"); 555 return {Attribute::getType(), raw_int_begin(), raw_int_end()}; 556 } 557 template <typename T, typename = APIntValueTemplateCheckT<T>> 558 IntElementIterator value_begin() const { 559 assert(getElementType().isIntOrIndex() && "expected integral type"); 560 return raw_int_begin(); 561 } 562 template <typename T, typename = APIntValueTemplateCheckT<T>> 563 IntElementIterator value_end() const { 564 assert(getElementType().isIntOrIndex() && "expected integral type"); 565 return raw_int_end(); 566 } 567 568 /// Return the held element values as a range of complex APInts. The element 569 /// type of this attribute must be a complex of integer type. 570 template <typename T> 571 using ComplexAPIntValueTemplateCheckT = typename std::enable_if< 572 std::is_same<T, std::complex<APInt>>::value>::type; 573 template <typename T, typename = ComplexAPIntValueTemplateCheckT<T>> 574 iterator_range_impl<ComplexIntElementIterator> getValues() const { 575 return getComplexIntValues(); 576 } 577 template <typename T, typename = ComplexAPIntValueTemplateCheckT<T>> 578 ComplexIntElementIterator value_begin() const { 579 return complex_value_begin(); 580 } 581 template <typename T, typename = ComplexAPIntValueTemplateCheckT<T>> 582 ComplexIntElementIterator value_end() const { 583 return complex_value_end(); 584 } 585 586 /// Return the held element values as a range of APFloat. The element type of 587 /// this attribute must be of float type. 588 template <typename T> 589 using APFloatValueTemplateCheckT = 590 typename std::enable_if<std::is_same<T, APFloat>::value>::type; 591 template <typename T, typename = APFloatValueTemplateCheckT<T>> 592 iterator_range_impl<FloatElementIterator> getValues() const { 593 return getFloatValues(); 594 } 595 template <typename T, typename = APFloatValueTemplateCheckT<T>> 596 FloatElementIterator value_begin() const { 597 return float_value_begin(); 598 } 599 template <typename T, typename = APFloatValueTemplateCheckT<T>> 600 FloatElementIterator value_end() const { 601 return float_value_end(); 602 } 603 604 /// Return the held element values as a range of complex APFloat. The element 605 /// type of this attribute must be a complex of float type. 606 template <typename T> 607 using ComplexAPFloatValueTemplateCheckT = typename std::enable_if< 608 std::is_same<T, std::complex<APFloat>>::value>::type; 609 template <typename T, typename = ComplexAPFloatValueTemplateCheckT<T>> 610 iterator_range_impl<ComplexFloatElementIterator> getValues() const { 611 return getComplexFloatValues(); 612 } 613 template <typename T, typename = ComplexAPFloatValueTemplateCheckT<T>> 614 ComplexFloatElementIterator value_begin() const { 615 return complex_float_value_begin(); 616 } 617 template <typename T, typename = ComplexAPFloatValueTemplateCheckT<T>> 618 ComplexFloatElementIterator value_end() const { 619 return complex_float_value_end(); 620 } 621 622 /// Return the raw storage data held by this attribute. Users should generally 623 /// not use this directly, as the internal storage format is not always in the 624 /// form the user might expect. 625 ArrayRef<char> getRawData() const; 626 627 /// Return the raw StringRef data held by this attribute. 628 ArrayRef<StringRef> getRawStringData() const; 629 630 /// Return the type of this ElementsAttr, guaranteed to be a vector or tensor 631 /// with static shape. 632 ShapedType getType() const; 633 634 /// Return the element type of this DenseElementsAttr. 635 Type getElementType() const; 636 637 /// Returns the number of elements held by this attribute. 638 int64_t getNumElements() const; 639 640 /// Returns the number of elements held by this attribute. 641 int64_t size() const { return getNumElements(); } 642 643 /// Returns if the number of elements held by this attribute is 0. 644 bool empty() const { return size() == 0; } 645 646 //===--------------------------------------------------------------------===// 647 // Mutation Utilities 648 //===--------------------------------------------------------------------===// 649 650 /// Return a new DenseElementsAttr that has the same data as the current 651 /// attribute, but has been reshaped to 'newType'. The new type must have the 652 /// same total number of elements as well as element type. 653 DenseElementsAttr reshape(ShapedType newType); 654 655 /// Return a new DenseElementsAttr that has the same data as the current 656 /// attribute, but with a different shape for a splat type. The new type must 657 /// have the same element type. 658 DenseElementsAttr resizeSplat(ShapedType newType); 659 660 /// Return a new DenseElementsAttr that has the same data as the current 661 /// attribute, but has bitcast elements to 'newElType'. The new type must have 662 /// the same bitwidth as the current element type. 663 DenseElementsAttr bitcast(Type newElType); 664 665 /// Generates a new DenseElementsAttr by mapping each int value to a new 666 /// underlying APInt. The new values can represent either an integer or float. 667 /// This underlying type must be an DenseIntElementsAttr. 668 DenseElementsAttr mapValues(Type newElementType, 669 function_ref<APInt(const APInt &)> mapping) const; 670 671 /// Generates a new DenseElementsAttr by mapping each float value to a new 672 /// underlying APInt. the new values can represent either an integer or float. 673 /// This underlying type must be an DenseFPElementsAttr. 674 DenseElementsAttr 675 mapValues(Type newElementType, 676 function_ref<APInt(const APFloat &)> mapping) const; 677 678 protected: 679 /// Iterators to various elements that require out-of-line definition. These 680 /// are hidden from the user to encourage consistent use of the 681 /// getValues/value_begin/value_end API. 682 IntElementIterator raw_int_begin() const { 683 return IntElementIterator(*this, 0); 684 } 685 IntElementIterator raw_int_end() const { 686 return IntElementIterator(*this, getNumElements()); 687 } 688 iterator_range_impl<ComplexIntElementIterator> getComplexIntValues() const; 689 ComplexIntElementIterator complex_value_begin() const; 690 ComplexIntElementIterator complex_value_end() const; 691 iterator_range_impl<FloatElementIterator> getFloatValues() const; 692 FloatElementIterator float_value_begin() const; 693 FloatElementIterator float_value_end() const; 694 iterator_range_impl<ComplexFloatElementIterator> 695 getComplexFloatValues() const; 696 ComplexFloatElementIterator complex_float_value_begin() const; 697 ComplexFloatElementIterator complex_float_value_end() const; 698 699 /// Overload of the raw 'get' method that asserts that the given type is of 700 /// complex type. This method is used to verify type invariants that the 701 /// templatized 'get' method cannot. 702 static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef<char> data, 703 int64_t dataEltSize, bool isInt, 704 bool isSigned); 705 706 /// Overload of the raw 'get' method that asserts that the given type is of 707 /// integer or floating-point type. This method is used to verify type 708 /// invariants that the templatized 'get' method cannot. 709 static DenseElementsAttr getRawIntOrFloat(ShapedType type, 710 ArrayRef<char> data, 711 int64_t dataEltSize, bool isInt, 712 bool isSigned); 713 714 /// Check the information for a C++ data type, check if this type is valid for 715 /// the current attribute. This method is used to verify specific type 716 /// invariants that the templatized 'getValues' method cannot. 717 bool isValidBool() const { return getElementType().isInteger(1); } 718 bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const; 719 bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const; 720 }; 721 722 /// An attribute that represents a reference to a splat vector or tensor 723 /// constant, meaning all of the elements have the same value. 724 class SplatElementsAttr : public DenseElementsAttr { 725 public: 726 using DenseElementsAttr::DenseElementsAttr; 727 728 /// Method for support type inquiry through isa, cast and dyn_cast. 729 static bool classof(Attribute attr) { 730 auto denseAttr = attr.dyn_cast<DenseElementsAttr>(); 731 return denseAttr && denseAttr.isSplat(); 732 } 733 }; 734 } // namespace mlir 735 736 //===----------------------------------------------------------------------===// 737 // Tablegen Attribute Declarations 738 //===----------------------------------------------------------------------===// 739 740 #define GET_ATTRDEF_CLASSES 741 #include "mlir/IR/BuiltinAttributes.h.inc" 742 743 //===----------------------------------------------------------------------===// 744 // C++ Attribute Declarations 745 //===----------------------------------------------------------------------===// 746 747 namespace mlir { 748 namespace detail { 749 /// Base class for DenseArrayAttr that is instantiated and specialized for each 750 /// supported element type below. 751 template <typename T> 752 class DenseArrayAttr : public DenseArrayBaseAttr { 753 public: 754 using DenseArrayBaseAttr::DenseArrayBaseAttr; 755 756 /// Implicit conversion to ArrayRef<T>. 757 operator ArrayRef<T>() const; 758 ArrayRef<T> asArrayRef() { return ArrayRef<T>{*this}; } 759 760 /// Builder from ArrayRef<T>. 761 static DenseArrayAttr get(MLIRContext *context, ArrayRef<T> content); 762 763 /// Print the short form `[42, 100, -1]` without any type prefix. 764 void print(AsmPrinter &printer) const; 765 void print(raw_ostream &os) const; 766 /// Print the short form `42, 100, -1` without any braces or type prefix. 767 void printWithoutBraces(raw_ostream &os) const; 768 769 /// Parse the short form `[42, 100, -1]` without any type prefix. 770 static Attribute parse(AsmParser &parser, Type odsType); 771 772 /// Parse the short form `42, 100, -1` without any type prefix or braces. 773 static Attribute parseWithoutBraces(AsmParser &parser, Type odsType); 774 775 /// Support for isa<>/cast<>. 776 static bool classof(Attribute attr); 777 }; 778 template <> 779 void DenseArrayAttr<int8_t>::printWithoutBraces(raw_ostream &os) const; 780 781 extern template class DenseArrayAttr<int8_t>; 782 extern template class DenseArrayAttr<int16_t>; 783 extern template class DenseArrayAttr<int32_t>; 784 extern template class DenseArrayAttr<int64_t>; 785 extern template class DenseArrayAttr<float>; 786 extern template class DenseArrayAttr<double>; 787 } // namespace detail 788 789 // Public name for all the supported DenseArrayAttr 790 using DenseI8ArrayAttr = detail::DenseArrayAttr<int8_t>; 791 using DenseI16ArrayAttr = detail::DenseArrayAttr<int16_t>; 792 using DenseI32ArrayAttr = detail::DenseArrayAttr<int32_t>; 793 using DenseI64ArrayAttr = detail::DenseArrayAttr<int64_t>; 794 using DenseF32ArrayAttr = detail::DenseArrayAttr<float>; 795 using DenseF64ArrayAttr = detail::DenseArrayAttr<double>; 796 797 //===----------------------------------------------------------------------===// 798 // BoolAttr 799 //===----------------------------------------------------------------------===// 800 801 /// Special case of IntegerAttr to represent boolean integers, i.e., signless i1 802 /// integers. 803 class BoolAttr : public Attribute { 804 public: 805 using Attribute::Attribute; 806 using ValueType = bool; 807 808 static BoolAttr get(MLIRContext *context, bool value); 809 810 /// Enable conversion to IntegerAttr. This uses conversion vs. inheritance to 811 /// avoid bringing in all of IntegerAttrs methods. 812 operator IntegerAttr() const { return IntegerAttr(impl); } 813 814 /// Return the boolean value of this attribute. 815 bool getValue() const; 816 817 /// Methods for support type inquiry through isa, cast, and dyn_cast. 818 static bool classof(Attribute attr); 819 }; 820 821 //===----------------------------------------------------------------------===// 822 // FlatSymbolRefAttr 823 //===----------------------------------------------------------------------===// 824 825 /// A symbol reference with a reference path containing a single element. This 826 /// is used to refer to an operation within the current symbol table. 827 class FlatSymbolRefAttr : public SymbolRefAttr { 828 public: 829 using SymbolRefAttr::SymbolRefAttr; 830 using ValueType = StringRef; 831 832 /// Construct a symbol reference for the given value name. 833 static FlatSymbolRefAttr get(StringAttr value) { 834 return SymbolRefAttr::get(value); 835 } 836 static FlatSymbolRefAttr get(MLIRContext *ctx, StringRef value) { 837 return SymbolRefAttr::get(ctx, value); 838 } 839 840 /// Convenience getter for building a SymbolRefAttr based on an operation 841 /// that implements the SymbolTrait. 842 static FlatSymbolRefAttr get(Operation *symbol) { 843 return SymbolRefAttr::get(symbol); 844 } 845 846 /// Returns the name of the held symbol reference as a StringAttr. 847 StringAttr getAttr() const { return getRootReference(); } 848 849 /// Returns the name of the held symbol reference. 850 StringRef getValue() const { return getAttr().getValue(); } 851 852 /// Methods for support type inquiry through isa, cast, and dyn_cast. 853 static bool classof(Attribute attr) { 854 SymbolRefAttr refAttr = attr.dyn_cast<SymbolRefAttr>(); 855 return refAttr && refAttr.getNestedReferences().empty(); 856 } 857 858 private: 859 using SymbolRefAttr::get; 860 using SymbolRefAttr::getNestedReferences; 861 }; 862 863 //===----------------------------------------------------------------------===// 864 // DenseFPElementsAttr 865 //===----------------------------------------------------------------------===// 866 867 /// An attribute that represents a reference to a dense float vector or tensor 868 /// object. Each element is stored as a double. 869 class DenseFPElementsAttr : public DenseIntOrFPElementsAttr { 870 public: 871 using iterator = DenseElementsAttr::FloatElementIterator; 872 873 using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; 874 875 /// Get an instance of a DenseFPElementsAttr with the given arguments. This 876 /// simply wraps the DenseElementsAttr::get calls. 877 template <typename Arg> 878 static DenseFPElementsAttr get(const ShapedType &type, Arg &&arg) { 879 return DenseElementsAttr::get(type, llvm::makeArrayRef(arg)) 880 .template cast<DenseFPElementsAttr>(); 881 } 882 template <typename T> 883 static DenseFPElementsAttr get(const ShapedType &type, 884 const std::initializer_list<T> &list) { 885 return DenseElementsAttr::get(type, list) 886 .template cast<DenseFPElementsAttr>(); 887 } 888 889 /// Generates a new DenseElementsAttr by mapping each value attribute, and 890 /// constructing the DenseElementsAttr given the new element type. 891 DenseElementsAttr 892 mapValues(Type newElementType, 893 function_ref<APInt(const APFloat &)> mapping) const; 894 895 /// Iterator access to the float element values. 896 iterator begin() const { return float_value_begin(); } 897 iterator end() const { return float_value_end(); } 898 899 /// Method for supporting type inquiry through isa, cast and dyn_cast. 900 static bool classof(Attribute attr); 901 }; 902 903 //===----------------------------------------------------------------------===// 904 // DenseIntElementsAttr 905 //===----------------------------------------------------------------------===// 906 907 /// An attribute that represents a reference to a dense integer vector or tensor 908 /// object. 909 class DenseIntElementsAttr : public DenseIntOrFPElementsAttr { 910 public: 911 /// DenseIntElementsAttr iterates on APInt, so we can use the raw element 912 /// iterator directly. 913 using iterator = DenseElementsAttr::IntElementIterator; 914 915 using DenseIntOrFPElementsAttr::DenseIntOrFPElementsAttr; 916 917 /// Get an instance of a DenseIntElementsAttr with the given arguments. This 918 /// simply wraps the DenseElementsAttr::get calls. 919 template <typename Arg> 920 static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg) { 921 return DenseElementsAttr::get(type, llvm::makeArrayRef(arg)) 922 .template cast<DenseIntElementsAttr>(); 923 } 924 template <typename T> 925 static DenseIntElementsAttr get(const ShapedType &type, 926 const std::initializer_list<T> &list) { 927 return DenseElementsAttr::get(type, list) 928 .template cast<DenseIntElementsAttr>(); 929 } 930 931 /// Generates a new DenseElementsAttr by mapping each value attribute, and 932 /// constructing the DenseElementsAttr given the new element type. 933 DenseElementsAttr mapValues(Type newElementType, 934 function_ref<APInt(const APInt &)> mapping) const; 935 936 /// Iterator access to the integer element values. 937 iterator begin() const { return raw_int_begin(); } 938 iterator end() const { return raw_int_end(); } 939 940 /// Method for supporting type inquiry through isa, cast and dyn_cast. 941 static bool classof(Attribute attr); 942 }; 943 944 //===----------------------------------------------------------------------===// 945 // SparseElementsAttr 946 //===----------------------------------------------------------------------===// 947 948 template <typename T> 949 auto SparseElementsAttr::value_begin() const -> iterator<T> { 950 auto zeroValue = getZeroValue<T>(); 951 auto valueIt = getValues().value_begin<T>(); 952 const std::vector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices()); 953 std::function<T(ptrdiff_t)> mapFn = 954 [flatSparseIndices{flatSparseIndices}, valueIt{std::move(valueIt)}, 955 zeroValue{std::move(zeroValue)}](ptrdiff_t index) { 956 // Try to map the current index to one of the sparse indices. 957 for (unsigned i = 0, e = flatSparseIndices.size(); i != e; ++i) 958 if (flatSparseIndices[i] == index) 959 return *std::next(valueIt, i); 960 // Otherwise, return the zero value. 961 return zeroValue; 962 }; 963 return iterator<T>(llvm::seq<ptrdiff_t>(0, getNumElements()).begin(), mapFn); 964 } 965 966 //===----------------------------------------------------------------------===// 967 // StringAttr 968 //===----------------------------------------------------------------------===// 969 970 /// Define comparisons for StringAttr against nullptr and itself to avoid the 971 /// StringRef overloads from being chosen when not desirable. 972 inline bool operator==(StringAttr lhs, std::nullptr_t) { return !lhs; } 973 inline bool operator!=(StringAttr lhs, std::nullptr_t) { 974 return static_cast<bool>(lhs); 975 } 976 inline bool operator==(StringAttr lhs, StringAttr rhs) { 977 return (Attribute)lhs == (Attribute)rhs; 978 } 979 inline bool operator!=(StringAttr lhs, StringAttr rhs) { return !(lhs == rhs); } 980 981 /// Allow direct comparison with StringRef. 982 inline bool operator==(StringAttr lhs, StringRef rhs) { 983 return lhs.getValue() == rhs; 984 } 985 inline bool operator!=(StringAttr lhs, StringRef rhs) { return !(lhs == rhs); } 986 inline bool operator==(StringRef lhs, StringAttr rhs) { 987 return rhs.getValue() == lhs; 988 } 989 inline bool operator!=(StringRef lhs, StringAttr rhs) { return !(lhs == rhs); } 990 991 inline Type StringAttr::getType() const { return Attribute::getType(); } 992 993 } // namespace mlir 994 995 //===----------------------------------------------------------------------===// 996 // Attribute Utilities 997 //===----------------------------------------------------------------------===// 998 999 namespace llvm { 1000 1001 template <> 1002 struct DenseMapInfo<mlir::StringAttr> : public DenseMapInfo<mlir::Attribute> { 1003 static mlir::StringAttr getEmptyKey() { 1004 const void *pointer = llvm::DenseMapInfo<const void *>::getEmptyKey(); 1005 return mlir::StringAttr::getFromOpaquePointer(pointer); 1006 } 1007 static mlir::StringAttr getTombstoneKey() { 1008 const void *pointer = llvm::DenseMapInfo<const void *>::getTombstoneKey(); 1009 return mlir::StringAttr::getFromOpaquePointer(pointer); 1010 } 1011 }; 1012 template <> 1013 struct PointerLikeTypeTraits<mlir::StringAttr> 1014 : public PointerLikeTypeTraits<mlir::Attribute> { 1015 static inline mlir::StringAttr getFromVoidPointer(void *p) { 1016 return mlir::StringAttr::getFromOpaquePointer(p); 1017 } 1018 }; 1019 1020 template <> 1021 struct PointerLikeTypeTraits<mlir::SymbolRefAttr> 1022 : public PointerLikeTypeTraits<mlir::Attribute> { 1023 static inline mlir::SymbolRefAttr getFromVoidPointer(void *ptr) { 1024 return mlir::SymbolRefAttr::getFromOpaquePointer(ptr); 1025 } 1026 }; 1027 1028 } // namespace llvm 1029 1030 #endif // MLIR_IR_BUILTINATTRIBUTES_H 1031