| //===- Attributes.h - MLIR Attribute Classes --------------------*- C++ -*-===// |
| // |
| // Copyright 2019 The MLIR Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ============================================================================= |
| |
| #ifndef MLIR_IR_ATTRIBUTES_H |
| #define MLIR_IR_ATTRIBUTES_H |
| |
| #include "mlir/IR/AttributeSupport.h" |
| #include "llvm/ADT/APFloat.h" |
| |
| namespace mlir { |
| class AffineMap; |
| class Dialect; |
| class FunctionType; |
| class Identifier; |
| class IntegerSet; |
| class Location; |
| class MLIRContext; |
| class ShapedType; |
| class Type; |
| |
| namespace detail { |
| |
| struct AffineMapAttributeStorage; |
| struct ArrayAttributeStorage; |
| struct BoolAttributeStorage; |
| struct DictionaryAttributeStorage; |
| struct IntegerAttributeStorage; |
| struct IntegerSetAttributeStorage; |
| struct FloatAttributeStorage; |
| struct OpaqueAttributeStorage; |
| struct StringAttributeStorage; |
| struct TypeAttributeStorage; |
| |
| /// Elements Attributes. |
| struct DenseElementsAttributeStorage; |
| struct OpaqueElementsAttributeStorage; |
| struct SparseElementsAttributeStorage; |
| } // namespace detail |
| |
| /// Attributes are known-constant values of operations and functions. |
| /// |
| /// Instances of the Attribute class are references to immutable, uniqued, |
| /// and immortal values owned by MLIRContext. As such, an Attribute is a thin |
| /// wrapper around an underlying storage pointer. Attributes are usually passed |
| /// by value. |
| class Attribute { |
| public: |
| /// Integer identifier for all the concrete attribute kinds. |
| enum Kind { |
| // Reserve attribute kinds for dialect specific extensions. |
| #define DEFINE_SYM_KIND_RANGE(Dialect) \ |
| FIRST_##Dialect##_ATTR, LAST_##Dialect##_ATTR = FIRST_##Dialect##_ATTR + 0xff, |
| #include "DialectSymbolRegistry.def" |
| }; |
| |
| /// Utility class for implementing attributes. |
| template <typename ConcreteType, typename BaseType = Attribute, |
| typename StorageType = AttributeStorage> |
| using AttrBase = detail::StorageUserBase<ConcreteType, BaseType, StorageType, |
| detail::AttributeUniquer>; |
| |
| using ImplType = AttributeStorage; |
| using ValueType = void; |
| |
| Attribute() : impl(nullptr) {} |
| /* implicit */ Attribute(const ImplType *impl) |
| : impl(const_cast<ImplType *>(impl)) {} |
| |
| Attribute(const Attribute &other) : impl(other.impl) {} |
| Attribute &operator=(Attribute other) { |
| impl = other.impl; |
| return *this; |
| } |
| |
| bool operator==(Attribute other) const { return impl == other.impl; } |
| bool operator!=(Attribute other) const { return !(*this == other); } |
| explicit operator bool() const { return impl; } |
| |
| bool operator!() const { return impl == nullptr; } |
| |
| template <typename U> bool isa() const; |
| template <typename U> U dyn_cast() const; |
| template <typename U> U dyn_cast_or_null() const; |
| template <typename U> U cast() const; |
| |
| // Support dyn_cast'ing Attribute to itself. |
| static bool classof(Attribute) { return true; } |
| |
| /// Return the classification for this attribute. |
| unsigned getKind() const { return impl->getKind(); } |
| |
| /// Return the type of this attribute. |
| Type getType() const; |
| |
| /// Return the context this attribute belongs to. |
| MLIRContext *getContext() const; |
| |
| /// Get the dialect this attribute is registered to. |
| Dialect &getDialect() const; |
| |
| /// Print the attribute. |
| void print(raw_ostream &os) const; |
| void dump() const; |
| |
| /// Get an opaque pointer to the attribute. |
| const void *getAsOpaquePointer() const { return impl; } |
| /// Construct an attribute from the opaque pointer representation. |
| static Attribute getFromOpaquePointer(const void *ptr) { |
| return Attribute(reinterpret_cast<const ImplType *>(ptr)); |
| } |
| |
| friend ::llvm::hash_code hash_value(Attribute arg); |
| |
| protected: |
| ImplType *impl; |
| }; |
| |
| inline raw_ostream &operator<<(raw_ostream &os, Attribute attr) { |
| attr.print(os); |
| return os; |
| } |
| |
| namespace StandardAttributes { |
| enum Kind { |
| AffineMap = Attribute::FIRST_STANDARD_ATTR, |
| Array, |
| Bool, |
| Dictionary, |
| Float, |
| Integer, |
| IntegerSet, |
| Opaque, |
| String, |
| SymbolRef, |
| Type, |
| Unit, |
| |
| /// Elements Attributes. |
| DenseElements, |
| OpaqueElements, |
| SparseElements, |
| FIRST_ELEMENTS_ATTR = DenseElements, |
| LAST_ELEMENTS_ATTR = SparseElements, |
| |
| /// Locations. |
| CallSiteLocation, |
| FileLineColLocation, |
| FusedLocation, |
| NameLocation, |
| UnknownLocation, |
| |
| // Represents a location as a 'void*' pointer to a front-end's opaque |
| // location information, which must live longer than the MLIR objects that |
| // refer to it. OpaqueLocation's are never serialized. |
| // |
| // TODO: OpaqueLocation, |
| |
| // Represents a value inlined through a function call. |
| // TODO: InlinedLocation, |
| |
| FIRST_LOCATION_ATTR = CallSiteLocation, |
| LAST_LOCATION_ATTR = UnknownLocation, |
| }; |
| } // namespace StandardAttributes |
| |
| class AffineMapAttr |
| : public Attribute::AttrBase<AffineMapAttr, Attribute, |
| detail::AffineMapAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = AffineMap; |
| |
| static AffineMapAttr get(AffineMap value); |
| |
| AffineMap getValue() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::AffineMap; |
| } |
| }; |
| |
| /// Array attributes are lists of other attributes. They are not necessarily |
| /// type homogenous given that attributes don't, in general, carry types. |
| class ArrayAttr : public Attribute::AttrBase<ArrayAttr, Attribute, |
| detail::ArrayAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = ArrayRef<Attribute>; |
| |
| static ArrayAttr get(ArrayRef<Attribute> value, MLIRContext *context); |
| |
| ArrayRef<Attribute> getValue() const; |
| |
| /// Support range iteration. |
| using iterator = llvm::ArrayRef<Attribute>::iterator; |
| iterator begin() const { return getValue().begin(); } |
| iterator end() const { return getValue().end(); } |
| size_t size() const { return getValue().size(); } |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::Array; |
| } |
| }; |
| |
| class BoolAttr : public Attribute::AttrBase<BoolAttr, Attribute, |
| detail::BoolAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = bool; |
| |
| static BoolAttr get(bool value, MLIRContext *context); |
| |
| bool getValue() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { return kind == StandardAttributes::Bool; } |
| }; |
| |
| /// NamedAttribute is used for dictionary attributes, it holds an identifier for |
| /// the name and a value for the attribute. The attribute pointer should always |
| /// be non-null. |
| using NamedAttribute = std::pair<Identifier, Attribute>; |
| |
| /// Dictionary attribute is an attribute that represents a sorted collection of |
| /// named attribute values. The elements are sorted by name, and each name must |
| /// be unique within the collection. |
| class DictionaryAttr |
| : public Attribute::AttrBase<DictionaryAttr, Attribute, |
| detail::DictionaryAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = ArrayRef<NamedAttribute>; |
| |
| static DictionaryAttr get(ArrayRef<NamedAttribute> value, |
| MLIRContext *context); |
| |
| ArrayRef<NamedAttribute> getValue() const; |
| |
| /// Return the specified attribute if present, null otherwise. |
| Attribute get(StringRef name) const; |
| Attribute get(Identifier name) const; |
| |
| /// Support range iteration. |
| using iterator = llvm::ArrayRef<NamedAttribute>::iterator; |
| iterator begin() const; |
| iterator end() const; |
| bool empty() const { return size() == 0; } |
| size_t size() const; |
| |
| /// Methods for supporting type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::Dictionary; |
| } |
| }; |
| |
| class FloatAttr : public Attribute::AttrBase<FloatAttr, Attribute, |
| detail::FloatAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = APFloat; |
| |
| /// Return a float attribute for the specified value in the specified type. |
| /// These methods should only be used for simple constant values, e.g 1.0/2.0, |
| /// that are known-valid both as host double and the 'type' format. |
| static FloatAttr get(Type type, double value); |
| static FloatAttr getChecked(Type type, double value, Location loc); |
| |
| /// Return a float attribute for the specified value in the specified type. |
| static FloatAttr get(Type type, const APFloat &value); |
| static FloatAttr getChecked(Type type, const APFloat &value, Location loc); |
| |
| APFloat getValue() const; |
| |
| /// This function is used to convert the value to a double, even if it loses |
| /// precision. |
| double getValueAsDouble() const; |
| static double getValueAsDouble(APFloat val); |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::Float; |
| } |
| |
| /// Verify the construction invariants for a double value. |
| static LogicalResult |
| verifyConstructionInvariants(llvm::Optional<Location> loc, MLIRContext *ctx, |
| Type type, double value); |
| static LogicalResult |
| verifyConstructionInvariants(llvm::Optional<Location> loc, MLIRContext *ctx, |
| Type type, const APFloat &value); |
| }; |
| |
| class IntegerAttr |
| : public Attribute::AttrBase<IntegerAttr, Attribute, |
| detail::IntegerAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = APInt; |
| |
| static IntegerAttr get(Type type, int64_t value); |
| static IntegerAttr get(Type type, const APInt &value); |
| |
| APInt getValue() const; |
| // TODO(jpienaar): Change callers to use getValue instead. |
| int64_t getInt() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::Integer; |
| } |
| }; |
| |
| class IntegerSetAttr |
| : public Attribute::AttrBase<IntegerSetAttr, Attribute, |
| detail::IntegerSetAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = IntegerSet; |
| |
| static IntegerSetAttr get(IntegerSet value); |
| |
| IntegerSet getValue() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::IntegerSet; |
| } |
| }; |
| |
| /// Opaque attributes represent attributes of non-registered dialects. These are |
| /// attribute represented in their raw string form, and can only usefully be |
| /// tested for attribute equality. |
| class OpaqueAttr : public Attribute::AttrBase<OpaqueAttr, Attribute, |
| detail::OpaqueAttributeStorage> { |
| public: |
| using Base::Base; |
| |
| /// Get or create a new OpaqueAttr with the provided dialect and string data. |
| static OpaqueAttr get(Identifier dialect, StringRef attrData, Type type, |
| MLIRContext *context); |
| |
| /// Get or create a new OpaqueAttr with the provided dialect and string data. |
| /// If the given identifier is not a valid namespace for a dialect, then a |
| /// null attribute is returned. |
| static OpaqueAttr getChecked(Identifier dialect, StringRef attrData, |
| Type type, Location location); |
| |
| /// Returns the dialect namespace of the opaque attribute. |
| Identifier getDialectNamespace() const; |
| |
| /// Returns the raw attribute data of the opaque attribute. |
| StringRef getAttrData() const; |
| |
| /// Verify the construction of an opaque attribute. |
| static LogicalResult |
| verifyConstructionInvariants(llvm::Optional<Location> loc, |
| MLIRContext *context, Identifier dialect, |
| StringRef attrData, Type type); |
| |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::Opaque; |
| } |
| }; |
| |
| class StringAttr : public Attribute::AttrBase<StringAttr, Attribute, |
| detail::StringAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = StringRef; |
| |
| /// Get an instance of a StringAttr with the given string. |
| static StringAttr get(StringRef bytes, MLIRContext *context); |
| |
| /// Get an instance of a StringAttr with the given string and Type. |
| static StringAttr get(StringRef bytes, Type type); |
| |
| StringRef getValue() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::String; |
| } |
| }; |
| |
| /// A symbol reference attribute represents a symbolic reference to another |
| /// operation. |
| class SymbolRefAttr |
| : public Attribute::AttrBase<SymbolRefAttr, Attribute, |
| detail::StringAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = StringRef; |
| |
| static SymbolRefAttr get(StringRef value, MLIRContext *ctx); |
| |
| /// Returns the name of the held symbol reference. |
| StringRef getValue() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::SymbolRef; |
| } |
| }; |
| |
| class TypeAttr : public Attribute::AttrBase<TypeAttr, Attribute, |
| detail::TypeAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = Type; |
| |
| static TypeAttr get(Type value); |
| |
| Type getValue() const; |
| |
| /// Methods for support type inquiry through isa, cast, and dyn_cast. |
| static bool kindof(unsigned kind) { return kind == StandardAttributes::Type; } |
| }; |
| |
| /// Unit attributes are attributes that hold no specific value and are given |
| /// meaning by their existence. |
| class UnitAttr : public Attribute::AttrBase<UnitAttr> { |
| public: |
| using Base::Base; |
| |
| static UnitAttr get(MLIRContext *context); |
| |
| static bool kindof(unsigned kind) { return kind == StandardAttributes::Unit; } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // Elements Attributes |
| //===----------------------------------------------------------------------===// |
| |
| /// A base attribute that represents a reference to a static shaped tensor or |
| /// vector constant. |
| class ElementsAttr : public Attribute { |
| public: |
| using Attribute::Attribute; |
| |
| /// Return the type of this ElementsAttr, guaranteed to be a vector or tensor |
| /// with static shape. |
| ShapedType getType() const; |
| |
| /// Return the value at the given index. The index is expected to refer to a |
| /// valid element. |
| Attribute getValue(ArrayRef<uint64_t> index) const; |
| |
| /// Return the value of type 'T' at the given index, where 'T' corresponds to |
| /// an Attribute type. |
| template <typename T> T getValue(ArrayRef<uint64_t> index) const { |
| return getValue(index).template cast<T>(); |
| } |
| |
| /// Return if the given 'index' refers to a valid element in this attribute. |
| bool isValidIndex(ArrayRef<uint64_t> index) const; |
| |
| /// Returns the number of elements held by this attribute. |
| int64_t getNumElements() const; |
| |
| /// Generates a new ElementsAttr by mapping each int value to a new |
| /// underlying APInt. The new values can represent either a integer or float. |
| /// This ElementsAttr should contain integers. |
| ElementsAttr |
| mapValues(Type newElementType, |
| llvm::function_ref<APInt(const APInt &)> mapping) const; |
| |
| /// Generates a new ElementsAttr by mapping each float value to a new |
| /// underlying APInt. The new values can represent either a integer or float. |
| /// This ElementsAttr should contain floats. |
| ElementsAttr |
| mapValues(Type newElementType, |
| llvm::function_ref<APInt(const APFloat &)> mapping) const; |
| |
| /// Method for support type inquiry through isa, cast and dyn_cast. |
| static bool classof(Attribute attr) { |
| return attr.getKind() >= StandardAttributes::FIRST_ELEMENTS_ATTR && |
| attr.getKind() <= StandardAttributes::LAST_ELEMENTS_ATTR; |
| } |
| }; |
| |
| namespace detail { |
| /// DenseElementsAttr data is aligned to uint64_t, so this traits class is |
| /// necessary to interop with PointerIntPair. |
| class DenseElementDataPointerTypeTraits { |
| public: |
| static inline const void *getAsVoidPointer(const char *ptr) { return ptr; } |
| static inline const char *getFromVoidPointer(const void *ptr) { |
| return static_cast<const char *>(ptr); |
| } |
| |
| // Note: We could steal more bits if the need arises. |
| enum { NumLowBitsAvailable = 1 }; |
| }; |
| |
| /// Pair of raw pointer and a boolean flag of whether the pointer holds a splat, |
| using DenseIterPtrAndSplat = |
| llvm::PointerIntPair<const char *, 1, bool, |
| DenseElementDataPointerTypeTraits>; |
| |
| /// Impl iterator for indexed DenseElementAttr iterators that records a data |
| /// pointer and data index that is adjusted for the case of a splat attribute. |
| template <typename ConcreteT, typename T, typename PointerT = T *, |
| typename ReferenceT = T &> |
| class DenseElementIndexedIteratorImpl |
| : public indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, |
| PointerT, ReferenceT> { |
| protected: |
| DenseElementIndexedIteratorImpl(const char *data, bool isSplat, |
| size_t dataIndex) |
| : indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T, PointerT, |
| ReferenceT>({data, isSplat}, dataIndex) {} |
| |
| /// Return the current index for this iterator, adjusted for the case of a |
| /// splat. |
| ptrdiff_t getDataIndex() const { |
| bool isSplat = this->object.getInt(); |
| return isSplat ? 0 : this->index; |
| } |
| |
| /// Return the data object pointer. |
| const char *getData() const { return this->object.getPointer(); } |
| }; |
| } // namespace detail |
| |
| /// An attribute that represents a reference to a dense vector or tensor object. |
| /// |
| class DenseElementsAttr |
| : public Attribute::AttrBase<DenseElementsAttr, ElementsAttr, |
| detail::DenseElementsAttributeStorage> { |
| public: |
| using Base::Base; |
| |
| /// Method for support type inquiry through isa, cast and dyn_cast. |
| static bool classof(Attribute attr) { |
| return attr.getKind() == StandardAttributes::DenseElements; |
| } |
| |
| /// Constructs a dense elements attribute from an array of element values. |
| /// Each element attribute value is expected to be an element of 'type'. |
| /// 'type' must be a vector or tensor with static shape. |
| static DenseElementsAttr get(ShapedType type, ArrayRef<Attribute> values); |
| |
| /// Constructs a dense integer elements attribute from an array of integer |
| /// or floating-point values. Each value is expected to be the same bitwidth |
| /// of the element type of 'type'. 'type' must be a vector or tensor with |
| /// static shape. |
| template <typename T, typename = typename std::enable_if< |
| std::numeric_limits<T>::is_integer || |
| llvm::is_one_of<T, float, double>::value>::type> |
| static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) { |
| const char *data = reinterpret_cast<const char *>(values.data()); |
| return getRawIntOrFloat( |
| type, ArrayRef<char>(data, values.size() * sizeof(T)), sizeof(T), |
| /*isInt=*/std::numeric_limits<T>::is_integer); |
| } |
| |
| /// Constructs a dense integer elements attribute from a single element. |
| template <typename T, typename = typename std::enable_if< |
| std::numeric_limits<T>::is_integer || |
| llvm::is_one_of<T, float, double>::value>::type> |
| static DenseElementsAttr get(const ShapedType &type, T value) { |
| return get(type, llvm::makeArrayRef(value)); |
| } |
| |
| /// Overload of the above 'get' method that is specialized for boolean values. |
| static DenseElementsAttr get(ShapedType type, ArrayRef<bool> values); |
| |
| /// Constructs a dense integer elements attribute from an array of APInt |
| /// values. Each APInt value is expected to have the same bitwidth as the |
| /// element type of 'type'. 'type' must be a vector or tensor with static |
| /// shape. |
| static DenseElementsAttr get(ShapedType type, ArrayRef<APInt> values); |
| |
| /// Constructs a dense float elements attribute from an array of APFloat |
| /// values. Each APFloat value is expected to have the same bitwidth as the |
| /// element type of 'type'. 'type' must be a vector or tensor with static |
| /// shape. |
| static DenseElementsAttr get(ShapedType type, ArrayRef<APFloat> values); |
| |
| /// Construct a dense elements attribute for an initializer_list of values. |
| /// Each value is expected to be the same bitwidth of the element type of |
| /// 'type'. 'type' must be a vector or tensor with static shape. |
| template <typename T> |
| static DenseElementsAttr get(const ShapedType &type, |
| const std::initializer_list<T> &list) { |
| return get(type, ArrayRef<T>(list)); |
| } |
| |
| //===--------------------------------------------------------------------===// |
| // Iterators |
| //===--------------------------------------------------------------------===// |
| |
| /// A utility iterator that allows walking over the internal Attribute values |
| /// of a DenseElementsAttr. |
| class AttributeElementIterator |
| : public indexed_accessor_iterator<AttributeElementIterator, const void *, |
| Attribute, Attribute, Attribute> { |
| public: |
| /// Accesses the Attribute value at this iterator position. |
| Attribute operator*() const; |
| |
| private: |
| friend DenseElementsAttr; |
| |
| /// Constructs a new iterator. |
| AttributeElementIterator(DenseElementsAttr attr, size_t index); |
| }; |
| |
| /// Iterator for walking raw element values of the specified type 'T', which |
| /// may be any c++ data type matching the stored representation: int32_t, |
| /// float, etc. |
| template <typename T> |
| class ElementIterator |
| : public detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, |
| const T> { |
| public: |
| /// Accesses the raw value at this iterator position. |
| const T &operator*() const { |
| return reinterpret_cast<const T *>(this->getData())[this->getDataIndex()]; |
| } |
| |
| private: |
| friend DenseElementsAttr; |
| |
| /// Constructs a new iterator. |
| ElementIterator(const char *data, bool isSplat, size_t dataIndex) |
| : detail::DenseElementIndexedIteratorImpl<ElementIterator<T>, const T>( |
| data, isSplat, dataIndex) {} |
| }; |
| |
| /// A utility iterator that allows walking over the internal bool values. |
| class BoolElementIterator |
| : public detail::DenseElementIndexedIteratorImpl<BoolElementIterator, |
| bool, bool, bool> { |
| public: |
| /// Accesses the bool value at this iterator position. |
| bool operator*() const; |
| |
| private: |
| friend DenseElementsAttr; |
| |
| /// Constructs a new iterator. |
| BoolElementIterator(DenseElementsAttr attr, size_t dataIndex); |
| }; |
| |
| /// A utility iterator that allows walking over the internal raw APInt values. |
| class IntElementIterator |
| : public detail::DenseElementIndexedIteratorImpl<IntElementIterator, |
| APInt, APInt, APInt> { |
| public: |
| /// Accesses the raw APInt value at this iterator position. |
| APInt operator*() const; |
| |
| private: |
| friend DenseElementsAttr; |
| |
| /// Constructs a new iterator. |
| IntElementIterator(DenseElementsAttr attr, size_t dataIndex); |
| |
| /// The bitwidth of the element type. |
| size_t bitWidth; |
| }; |
| |
| /// Iterator for walking over APFloat values. |
| class FloatElementIterator final |
| : public llvm::mapped_iterator<IntElementIterator, |
| std::function<APFloat(const APInt &)>> { |
| friend DenseElementsAttr; |
| |
| /// Initializes the float element iterator to the specified iterator. |
| FloatElementIterator(const llvm::fltSemantics &smt, IntElementIterator it); |
| |
| public: |
| using reference = APFloat; |
| }; |
| |
| //===--------------------------------------------------------------------===// |
| // Value Querying |
| //===--------------------------------------------------------------------===// |
| |
| /// Returns if this attribute corresponds to a splat, i.e. if all element |
| /// values are the same. |
| bool isSplat() const; |
| |
| /// Return the splat value for this attribute. This asserts that the attribute |
| /// corresponds to a splat. |
| Attribute getSplatValue() const { return getSplatValue<Attribute>(); } |
| template <typename T> |
| typename std::enable_if<!std::is_base_of<Attribute, T>::value || |
| std::is_same<Attribute, T>::value, |
| T>::type |
| getSplatValue() const { |
| assert(isSplat() && "expected the attribute to be a splat"); |
| return *getValues<T>().begin(); |
| } |
| /// Return the splat value for derived attribute element types. |
| template <typename T> |
| typename std::enable_if<std::is_base_of<Attribute, T>::value && |
| !std::is_same<Attribute, T>::value, |
| T>::type |
| getSplatValue() const { |
| return getSplatValue().template cast<T>(); |
| } |
| |
| /// Return the value at the given index. The 'index' is expected to refer to a |
| /// valid element. |
| Attribute getValue(ArrayRef<uint64_t> index) const { |
| return getValue<Attribute>(index); |
| } |
| template <typename T> T getValue(ArrayRef<uint64_t> index) const { |
| // Skip to the element corresponding to the flattened index. |
| return *std::next(getValues<T>().begin(), getFlattenedIndex(index)); |
| } |
| |
| /// Return the held element values as a range of integer or floating-point |
| /// values. |
| template <typename T, typename = typename std::enable_if< |
| (!std::is_same<T, bool>::value && |
| std::numeric_limits<T>::is_integer) || |
| llvm::is_one_of<T, float, double>::value>::type> |
| llvm::iterator_range<ElementIterator<T>> getValues() const { |
| assert(isValidIntOrFloat(sizeof(T), std::numeric_limits<T>::is_integer)); |
| auto rawData = getRawData().data(); |
| bool splat = isSplat(); |
| return {ElementIterator<T>(rawData, splat, 0), |
| ElementIterator<T>(rawData, splat, getNumElements())}; |
| } |
| |
| /// Return the held element values as a range of Attributes. |
| llvm::iterator_range<AttributeElementIterator> getAttributeValues() const; |
| template <typename T, typename = typename std::enable_if< |
| std::is_same<T, Attribute>::value>::type> |
| llvm::iterator_range<AttributeElementIterator> getValues() const { |
| return getAttributeValues(); |
| } |
| AttributeElementIterator attr_value_begin() const; |
| AttributeElementIterator attr_value_end() const; |
| |
| /// Return the held element values a range of T, where T is a derived |
| /// attribute type. |
| template <typename T> |
| using DerivedAttributeElementIterator = |
| llvm::mapped_iterator<AttributeElementIterator, T (*)(Attribute)>; |
| template <typename T, typename = typename std::enable_if< |
| std::is_base_of<Attribute, T>::value && |
| !std::is_same<Attribute, T>::value>::type> |
| llvm::iterator_range<DerivedAttributeElementIterator<T>> getValues() const { |
| auto castFn = [](Attribute attr) { return attr.template cast<T>(); }; |
| return llvm::map_range(getAttributeValues(), |
| static_cast<T (*)(Attribute)>(castFn)); |
| } |
| |
| /// Return the held element values as a range of bool. The element type of |
| /// this attribute must be of integer type of bitwidth 1. |
| llvm::iterator_range<BoolElementIterator> getBoolValues() const; |
| template <typename T, typename = typename std::enable_if< |
| std::is_same<T, bool>::value>::type> |
| llvm::iterator_range<BoolElementIterator> getValues() const { |
| return getBoolValues(); |
| } |
| |
| /// Return the held element values as a range of APInts. The element type of |
| /// this attribute must be of integer type. |
| llvm::iterator_range<IntElementIterator> getIntValues() const; |
| template <typename T, typename = typename std::enable_if< |
| std::is_same<T, APInt>::value>::type> |
| llvm::iterator_range<IntElementIterator> getValues() const { |
| return getIntValues(); |
| } |
| IntElementIterator int_value_begin() const; |
| IntElementIterator int_value_end() const; |
| |
| /// Return the held element values as a range of APFloat. The element type of |
| /// this attribute must be of float type. |
| llvm::iterator_range<FloatElementIterator> getFloatValues() const; |
| template <typename T, typename = typename std::enable_if< |
| std::is_same<T, APFloat>::value>::type> |
| llvm::iterator_range<FloatElementIterator> getValues() const { |
| return getFloatValues(); |
| } |
| FloatElementIterator float_value_begin() const; |
| FloatElementIterator float_value_end() const; |
| |
| //===--------------------------------------------------------------------===// |
| // Mutation Utilities |
| //===--------------------------------------------------------------------===// |
| |
| /// Return a new DenseElementsAttr that has the same data as the current |
| /// attribute, but has been reshaped to 'newType'. The new type must have the |
| /// same total number of elements as well as element type. |
| DenseElementsAttr reshape(ShapedType newType); |
| |
| /// Generates a new DenseElementsAttr by mapping each int value to a new |
| /// underlying APInt. The new values can represent either a integer or float. |
| /// This underlying type must be an DenseIntElementsAttr. |
| DenseElementsAttr |
| mapValues(Type newElementType, |
| llvm::function_ref<APInt(const APInt &)> mapping) const; |
| |
| /// Generates a new DenseElementsAttr by mapping each float value to a new |
| /// underlying APInt. the new values can represent either a integer or float. |
| /// This underlying type must be an DenseFPElementsAttr. |
| DenseElementsAttr |
| mapValues(Type newElementType, |
| llvm::function_ref<APInt(const APFloat &)> mapping) const; |
| |
| protected: |
| /// Return the raw storage data held by this attribute. |
| ArrayRef<char> getRawData() const; |
| |
| /// Get iterators to the raw APInt values for each element in this attribute. |
| IntElementIterator raw_int_begin() const { |
| return IntElementIterator(*this, 0); |
| } |
| IntElementIterator raw_int_end() const { |
| return IntElementIterator(*this, getNumElements()); |
| } |
| |
| /// Constructs a dense elements attribute from an array of raw APInt values. |
| /// Each APInt value is expected to have the same bitwidth as the element type |
| /// of 'type'. 'type' must be a vector or tensor with static shape. |
| static DenseElementsAttr getRaw(ShapedType type, ArrayRef<APInt> values); |
| |
| /// Get or create a new dense elements attribute instance with the given raw |
| /// data buffer. 'type' must be a vector or tensor with static shape. |
| static DenseElementsAttr getRaw(ShapedType type, ArrayRef<char> data, |
| bool isSplat); |
| |
| /// Overload of the raw 'get' method that asserts that the given type is of |
| /// integer or floating-point type. This method is used to verify type |
| /// invariants that the templatized 'get' method cannot. |
| static DenseElementsAttr getRawIntOrFloat(ShapedType type, |
| ArrayRef<char> data, |
| int64_t dataEltSize, bool isInt); |
| |
| /// Check the information for a c++ data type, check if this type is valid for |
| /// the current attribute. This method is used to verify specific type |
| /// invariants that the templatized 'getValues' method cannot. |
| bool isValidIntOrFloat(int64_t dataEltSize, bool isInt) const; |
| |
| /// Returns the 1 dimenional flattened index from the given multi-dimensional |
| /// index. |
| uint64_t getFlattenedIndex(ArrayRef<uint64_t> index) const; |
| }; |
| |
| /// An attribute that represents a reference to a dense float vector or tensor |
| /// object. Each element is stored as a double. |
| class DenseFPElementsAttr : public DenseElementsAttr { |
| public: |
| using iterator = DenseElementsAttr::FloatElementIterator; |
| |
| using DenseElementsAttr::DenseElementsAttr; |
| |
| /// Generates a new DenseElementsAttr by mapping each value attribute, and |
| /// constructing the DenseElementsAttr given the new element type. |
| DenseElementsAttr |
| mapValues(Type newElementType, |
| llvm::function_ref<APInt(const APFloat &)> mapping) const; |
| |
| /// Iterator access to the float element values. |
| iterator begin() const { return float_value_begin(); } |
| iterator end() const { return float_value_end(); } |
| |
| /// Method for supporting type inquiry through isa, cast and dyn_cast. |
| static bool classof(Attribute attr); |
| }; |
| |
| /// An attribute that represents a reference to a dense integer vector or tensor |
| /// object. |
| class DenseIntElementsAttr : public DenseElementsAttr { |
| public: |
| /// DenseIntElementsAttr iterates on APInt, so we can use the raw element |
| /// iterator directly. |
| using iterator = DenseElementsAttr::IntElementIterator; |
| |
| using DenseElementsAttr::DenseElementsAttr; |
| |
| /// Generates a new DenseElementsAttr by mapping each value attribute, and |
| /// constructing the DenseElementsAttr given the new element type. |
| DenseElementsAttr |
| mapValues(Type newElementType, |
| llvm::function_ref<APInt(const APInt &)> mapping) const; |
| |
| /// Iterator access to the integer element values. |
| iterator begin() const { return raw_int_begin(); } |
| iterator end() const { return raw_int_end(); } |
| |
| /// Method for supporting type inquiry through isa, cast and dyn_cast. |
| static bool classof(Attribute attr); |
| }; |
| |
| /// An opaque attribute that represents a reference to a vector or tensor |
| /// constant with opaque content. This respresentation is for tensor constants |
| /// which the compiler may not need to interpret. This attribute is always |
| /// associated with a particular dialect, which provides a method to convert |
| /// tensor representation to a non-opaque format. |
| class OpaqueElementsAttr |
| : public Attribute::AttrBase<OpaqueElementsAttr, ElementsAttr, |
| detail::OpaqueElementsAttributeStorage> { |
| public: |
| using Base::Base; |
| using ValueType = StringRef; |
| |
| static OpaqueElementsAttr get(Dialect *dialect, ShapedType type, |
| StringRef bytes); |
| |
| StringRef getValue() const; |
| |
| /// Return the value at the given index. The 'index' is expected to refer to a |
| /// valid element. |
| Attribute getValue(ArrayRef<uint64_t> index) const; |
| |
| /// Decodes the attribute value using dialect-specific decoding hook. |
| /// Returns false if decoding is successful. If not, returns true and leaves |
| /// 'result' argument unspecified. |
| bool decode(ElementsAttr &result); |
| |
| /// Returns dialect associated with this opaque constant. |
| Dialect *getDialect() const; |
| |
| /// Method for support type inquiry through isa, cast and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::OpaqueElements; |
| } |
| }; |
| |
| /// An attribute that represents a reference to a sparse vector or tensor |
| /// object. |
| /// |
| /// This class uses COO (coordinate list) encoding to represent the sparse |
| /// elements in an element attribute. Specifically, the sparse vector/tensor |
| /// stores the indices and values as two separate dense elements attributes of |
| /// tensor type (even if the sparse attribute is of vector type, in order to |
| /// support empty lists). The dense elements attribute indices is a 2-D tensor |
| /// of 64-bit integer elements with shape [N, ndims], which specifies the |
| /// indices of the elements in the sparse tensor that contains nonzero values. |
| /// The dense elements attribute values is a 1-D tensor with shape [N], and it |
| /// supplies the corresponding values for the indices. |
| /// |
| /// For example, |
| /// `sparse<tensor<3x4xi32>, [[0, 0], [1, 2]], [1, 5]>` represents tensor |
| /// [[1, 0, 0, 0], |
| /// [0, 0, 5, 0], |
| /// [0, 0, 0, 0]]. |
| class SparseElementsAttr |
| : public Attribute::AttrBase<SparseElementsAttr, ElementsAttr, |
| detail::SparseElementsAttributeStorage> { |
| public: |
| using Base::Base; |
| |
| /// 'type' must be a vector or tensor with static shape. |
| static SparseElementsAttr get(ShapedType type, DenseElementsAttr indices, |
| DenseElementsAttr values); |
| |
| DenseIntElementsAttr getIndices() const; |
| |
| DenseElementsAttr getValues() const; |
| |
| /// Return the value of the element at the given index. The 'index' is |
| /// expected to refer to a valid element. |
| Attribute getValue(ArrayRef<uint64_t> index) const; |
| |
| /// Method for support type inquiry through isa, cast and dyn_cast. |
| static bool kindof(unsigned kind) { |
| return kind == StandardAttributes::SparseElements; |
| } |
| }; |
| |
| /// An attribute that represents a reference to a splat vector or tensor |
| /// constant, meaning all of the elements have the same value. |
| class SplatElementsAttr : public DenseElementsAttr { |
| public: |
| using DenseElementsAttr::DenseElementsAttr; |
| |
| /// Method for support type inquiry through isa, cast and dyn_cast. |
| static bool classof(Attribute attr) { |
| auto denseAttr = attr.dyn_cast<DenseElementsAttr>(); |
| return denseAttr && denseAttr.isSplat(); |
| } |
| }; |
| |
| template <typename U> bool Attribute::isa() const { |
| assert(impl && "isa<> used on a null attribute."); |
| return U::classof(*this); |
| } |
| template <typename U> U Attribute::dyn_cast() const { |
| return isa<U>() ? U(impl) : U(nullptr); |
| } |
| template <typename U> U Attribute::dyn_cast_or_null() const { |
| return (impl && isa<U>()) ? U(impl) : U(nullptr); |
| } |
| template <typename U> U Attribute::cast() const { |
| assert(isa<U>()); |
| return U(impl); |
| } |
| |
| // Make Attribute hashable. |
| inline ::llvm::hash_code hash_value(Attribute arg) { |
| return ::llvm::hash_value(arg.impl); |
| } |
| |
| /// A NamedAttributeList is used to manage a list of named attributes. This |
| /// provides simple interfaces for adding/removing/finding attributes from |
| /// within a DictionaryAttr. |
| /// |
| /// We assume there will be relatively few attributes on a given operation |
| /// (maybe a dozen or so, but not hundreds or thousands) so we use linear |
| /// searches for everything. |
| class NamedAttributeList { |
| public: |
| NamedAttributeList(DictionaryAttr attrs = nullptr) |
| : attrs((attrs && !attrs.empty()) ? attrs : nullptr) {} |
| NamedAttributeList(ArrayRef<NamedAttribute> attributes); |
| |
| /// Return the underlying dictionary attribute. This may be null, if this list |
| /// has no attributes. |
| DictionaryAttr getDictionary() const { return attrs; } |
| |
| /// Return all of the attributes on this operation. |
| ArrayRef<NamedAttribute> getAttrs() const; |
| |
| /// Replace the held attributes with ones provided in 'newAttrs'. |
| void setAttrs(ArrayRef<NamedAttribute> attributes); |
| |
| /// Return the specified attribute if present, null otherwise. |
| Attribute get(StringRef name) const; |
| Attribute get(Identifier name) const; |
| |
| /// If the an attribute exists with the specified name, change it to the new |
| /// value. Otherwise, add a new attribute with the specified name/value. |
| void set(Identifier name, Attribute value); |
| |
| enum class RemoveResult { Removed, NotFound }; |
| |
| /// Remove the attribute with the specified name if it exists. The return |
| /// value indicates whether the attribute was present or not. |
| RemoveResult remove(Identifier name); |
| |
| private: |
| DictionaryAttr attrs; |
| }; |
| |
| } // end namespace mlir. |
| |
| namespace llvm { |
| |
| // Attribute hash just like pointers. |
| template <> struct DenseMapInfo<mlir::Attribute> { |
| static mlir::Attribute getEmptyKey() { |
| auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey(); |
| return mlir::Attribute(static_cast<mlir::Attribute::ImplType *>(pointer)); |
| } |
| static mlir::Attribute getTombstoneKey() { |
| auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey(); |
| return mlir::Attribute(static_cast<mlir::Attribute::ImplType *>(pointer)); |
| } |
| static unsigned getHashValue(mlir::Attribute val) { |
| return mlir::hash_value(val); |
| } |
| static bool isEqual(mlir::Attribute LHS, mlir::Attribute RHS) { |
| return LHS == RHS; |
| } |
| }; |
| |
| /// Allow LLVM to steal the low bits of Attributes. |
| template <> struct PointerLikeTypeTraits<mlir::Attribute> { |
| public: |
| static inline void *getAsVoidPointer(mlir::Attribute attr) { |
| return const_cast<void *>(attr.getAsOpaquePointer()); |
| } |
| static inline mlir::Attribute getFromVoidPointer(void *ptr) { |
| return mlir::Attribute::getFromOpaquePointer(ptr); |
| } |
| enum { NumLowBitsAvailable = 3 }; |
| }; |
| |
| } // namespace llvm |
| |
| #endif |