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