//===- BuiltinAttributes.h - MLIR Builtin Attribute Classes -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef MLIR_IR_BUILTINATTRIBUTES_H #define MLIR_IR_BUILTINATTRIBUTES_H #include "mlir/IR/BuiltinAttributeInterfaces.h" #include "mlir/Support/Complex.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/Sequence.h" #include namespace mlir { class AffineMap; class AsmResourceBlob; class BoolAttr; class BuiltinDialect; class DenseIntElementsAttr; template struct DialectResourceBlobHandle; class FlatSymbolRefAttr; class FunctionType; class IntegerSet; class IntegerType; class Location; class Operation; class RankedTensorType; namespace detail { struct DenseTypedElementsAttrStorage; struct DenseStringElementsAttrStorage; struct StringAttrStorage; } // namespace detail //===----------------------------------------------------------------------===// // Elements Attributes //===----------------------------------------------------------------------===// namespace detail { /// Pair of raw pointer and a boolean flag of whether the pointer holds a splat, using DenseIterPtrAndSplat = std::pair; /// Impl iterator for indexed DenseElementsAttr iterators that records a data /// pointer and data index that is adjusted for the case of a splat attribute. template class DenseElementIndexedIteratorImpl : public llvm::indexed_accessor_iterator { protected: DenseElementIndexedIteratorImpl(const char *data, bool isSplat, size_t dataIndex) : llvm::indexed_accessor_iterator({data, isSplat}, dataIndex) {} /// Return the current index for this iterator, adjusted for the case of a /// splat. ptrdiff_t getDataIndex() const { bool isSplat = this->base.second; return isSplat ? 0 : this->index; } /// Return the data base pointer. const char *getData() const { return this->base.first; } }; /// Type trait detector that checks if a given type T is a complex type. template struct is_complex_t : public std::false_type {}; template struct is_complex_t> : public std::true_type {}; template struct is_complex_t> : public std::true_type {}; } // namespace detail /// An attribute that represents a reference to a dense vector or tensor /// object. class DenseElementsAttr : public Attribute { public: using Attribute::Attribute; /// Allow implicit conversion to ElementsAttr. operator ElementsAttr() const { return cast_if_present(*this); } /// Allow implicit conversion to TypedAttr. operator TypedAttr() const { return ElementsAttr(*this); } /// Type trait used to check if the given type T is a potentially valid C++ /// floating point type that can be used to access the underlying element /// types of a DenseElementsAttr. template struct is_valid_cpp_fp_type { /// The type is a valid floating point type if it is a builtin floating /// point type, or is a potentially user defined floating point type. The /// latter allows for supporting users that have custom types defined for /// bfloat16/half/etc. static constexpr bool value = llvm::is_one_of::value || (std::numeric_limits::is_specialized && !std::numeric_limits::is_integer); }; /// Method for support type inquiry through isa, cast and dyn_cast. static bool classof(Attribute attr); /// 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. If the element of /// `type` is non-integer/index/float it is assumed to be a string type. static DenseElementsAttr get(ShapedType type, ArrayRef 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 ::is_integer || is_valid_cpp_fp_type::value>> static DenseElementsAttr get(const ShapedType &type, ArrayRef values) { const char *data = reinterpret_cast(values.data()); return getRawIntOrFloat( type, ArrayRef(data, values.size() * sizeof(T)), sizeof(T), std::numeric_limits::is_integer, std::numeric_limits::is_signed); } /// Constructs a dense integer elements attribute from a single element. template ::is_integer || is_valid_cpp_fp_type::value || detail::is_complex_t::value>> static DenseElementsAttr get(const ShapedType &type, T value) { return get(type, llvm::ArrayRef(value)); } /// Constructs a dense complex elements attribute from an array of complex /// 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 ElementT = typename T::value_type, typename = std::enable_if_t::value && (std::numeric_limits::is_integer || is_valid_cpp_fp_type::value)>> static DenseElementsAttr get(const ShapedType &type, ArrayRef values) { const char *data = reinterpret_cast(values.data()); return getRawComplex(type, ArrayRef(data, values.size() * sizeof(T)), sizeof(T), std::numeric_limits::is_integer, std::numeric_limits::is_signed); } /// Overload of the above 'get' method that is specialized for boolean values. static DenseElementsAttr get(ShapedType type, ArrayRef values); /// Overload of the above 'get' method that is specialized for StringRef /// values. static DenseElementsAttr get(ShapedType type, ArrayRef 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 values); /// Constructs a dense complex 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> 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 values); /// Constructs a dense complex 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> 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 static DenseElementsAttr get(const ShapedType &type, const std::initializer_list &list) { return get(type, ArrayRef(list)); } /// Construct a dense elements attribute from a raw buffer representing the /// data for this attribute. Users are encouraged to use one of the /// constructors above, which provide more safeties. However, this /// constructor is useful for tools which may want to interop and can /// follow the precise definition. /// /// The format of the raw buffer is a densely packed array of values that /// can be bitcast to the storage format of the element type specified. /// Types that are not byte aligned will be rounded up to the next byte. static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef rawBuffer); /// Returns true if the given buffer is a valid raw buffer for the given type. static bool isValidRawBuffer(ShapedType type, ArrayRef rawBuffer); //===--------------------------------------------------------------------===// // Iterators //===--------------------------------------------------------------------===// /// The iterator range over the given iterator type T. template using iterator_range_impl = detail::ElementsAttrRange; /// The iterator for the given element type T. template using iterator = decltype(std::declval().template value_begin()); /// The iterator range over the given element T. template using iterator_range = decltype(std::declval().template getValues()); /// A utility iterator that allows walking over the internal Attribute values /// of a DenseElementsAttr. class AttributeElementIterator : public llvm::indexed_accessor_iterator { 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 class ElementIterator : public detail::DenseElementIndexedIteratorImpl, const T> { public: /// Accesses the raw value at this iterator position. const T &operator*() const { return reinterpret_cast(this->getData())[this->getDataIndex()]; } private: friend DenseElementsAttr; /// Constructs a new iterator. ElementIterator(const char *data, bool isSplat, size_t dataIndex) : detail::DenseElementIndexedIteratorImpl, const T>( data, isSplat, dataIndex) {} }; /// A utility iterator that allows walking over the internal bool values. class BoolElementIterator : public detail::DenseElementIndexedIteratorImpl { 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 { 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; }; /// A utility iterator that allows walking over the internal raw complex APInt /// values. class ComplexIntElementIterator : public detail::DenseElementIndexedIteratorImpl< ComplexIntElementIterator, mlir::Complex, mlir::Complex, mlir::Complex> { public: /// Accesses the raw mlir::Complex value at this iterator position. mlir::Complex operator*() const; private: friend DenseElementsAttr; /// Constructs a new iterator. ComplexIntElementIterator(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_base { public: /// Map the element to the iterator result type. APFloat mapElement(const APInt &value) const { return APFloat(*smt, value); } private: friend DenseElementsAttr; /// Initializes the float element iterator to the specified iterator. FloatElementIterator(const llvm::fltSemantics &smt, IntElementIterator it) : BaseT(it), smt(&smt) {} /// The float semantics to use when constructing the APFloat. const llvm::fltSemantics *smt; }; /// Iterator for walking over complex APFloat values. class ComplexFloatElementIterator final : public llvm::mapped_iterator_base> { public: /// Map the element to the iterator result type. mlir::Complex mapElement(const mlir::Complex &value) const { return {APFloat(*smt, value.real()), APFloat(*smt, value.imag())}; } private: friend DenseElementsAttr; /// Initializes the float element iterator to the specified iterator. ComplexFloatElementIterator(const llvm::fltSemantics &smt, ComplexIntElementIterator it) : BaseT(it), smt(&smt) {} /// The float semantics to use when constructing the APFloat. const llvm::fltSemantics *smt; }; //===--------------------------------------------------------------------===// // Value Querying //===--------------------------------------------------------------------===// /// Returns true 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. template std::enable_if_t::value || std::is_same::value, T> getSplatValue() const { assert(isSplat() && "expected the attribute to be a splat"); return *value_begin(); } /// Return the splat value for derived attribute element types. template std::enable_if_t::value && !std::is_same::value, T> getSplatValue() const { return llvm::cast(getSplatValue()); } /// Try to get an iterator of the given type to the start of the held element /// values. Return failure if the type cannot be iterated. template auto try_value_begin() const { auto range = tryGetValues(); using iterator = decltype(range->begin()); return failed(range) ? FailureOr(failure()) : range->begin(); } /// Try to get an iterator of the given type to the end of the held element /// values. Return failure if the type cannot be iterated. template auto try_value_end() const { auto range = tryGetValues(); using iterator = decltype(range->begin()); return failed(range) ? FailureOr(failure()) : range->end(); } /// Return the held element values as a range of the given type. template auto getValues() const { auto range = tryGetValues(); assert(succeeded(range) && "element type cannot be iterated"); return std::move(*range); } /// Get an iterator of the given type to the start of the held element values. template auto value_begin() const { return getValues().begin(); } /// Get an iterator of the given type to the end of the held element values. template auto value_end() const { return getValues().end(); } /// Try to get the held element values as a range of integer or floating-point /// values. template using IntFloatValueTemplateCheckT = std::enable_if_t<(!std::is_same::value && std::numeric_limits::is_integer) || is_valid_cpp_fp_type::value>; template > FailureOr>> tryGetValues() const { if (!isValidIntOrFloat(sizeof(T), std::numeric_limits::is_integer, std::numeric_limits::is_signed)) return failure(); const char *rawData = getRawData().data(); bool splat = isSplat(); return iterator_range_impl>( getType(), ElementIterator(rawData, splat, 0), ElementIterator(rawData, splat, getNumElements())); } /// Try to get the held element values as a range of mlir::Complex. template using ComplexValueTemplateCheckT = std::enable_if_t::value && (std::numeric_limits::is_integer || is_valid_cpp_fp_type::value)>; template > FailureOr>> tryGetValues() const { if (!isValidComplex(sizeof(T), std::numeric_limits::is_integer, std::numeric_limits::is_signed)) return failure(); const char *rawData = getRawData().data(); bool splat = isSplat(); return iterator_range_impl>( getType(), ElementIterator(rawData, splat, 0), ElementIterator(rawData, splat, getNumElements())); } /// Try to get the held element values as a range of StringRef. template using StringRefValueTemplateCheckT = std::enable_if_t::value>; template > FailureOr>> tryGetValues() const { auto stringRefs = getRawStringData(); const char *ptr = reinterpret_cast(stringRefs.data()); bool splat = isSplat(); return iterator_range_impl>( getType(), ElementIterator(ptr, splat, 0), ElementIterator(ptr, splat, getNumElements())); } /// Try to get the held element values as a range of Attributes. template using AttributeValueTemplateCheckT = std::enable_if_t::value>; template > FailureOr> tryGetValues() const { return iterator_range_impl( getType(), AttributeElementIterator(*this, 0), AttributeElementIterator(*this, getNumElements())); } /// Try to get the held element values a range of T, where T is a derived /// attribute type. template using DerivedAttrValueTemplateCheckT = std::enable_if_t::value && !std::is_same::value>; template struct DerivedAttributeElementIterator : public llvm::mapped_iterator_base, AttributeElementIterator, T> { using llvm::mapped_iterator_base, AttributeElementIterator, T>::mapped_iterator_base; /// Map the element to the iterator result type. T mapElement(Attribute attr) const { return llvm::cast(attr); } }; template > FailureOr>> tryGetValues() const { using DerivedIterT = DerivedAttributeElementIterator; return iterator_range_impl( getType(), DerivedIterT(value_begin()), DerivedIterT(value_end())); } /// Try to get the held element values as a range of bool. The element type of /// this attribute must be of integer type of bitwidth 1. template using BoolValueTemplateCheckT = std::enable_if_t::value>; template > FailureOr> tryGetValues() const { if (!isValidBool()) return failure(); return iterator_range_impl( getType(), BoolElementIterator(*this, 0), BoolElementIterator(*this, getNumElements())); } /// Try to get the held element values as a range of APInts. The element type /// of this attribute must be of integer type. template using APIntValueTemplateCheckT = std::enable_if_t::value>; template > FailureOr> tryGetValues() const { if (!getElementType().isIntOrIndex()) return failure(); return iterator_range_impl(getType(), raw_int_begin(), raw_int_end()); } /// Try to get the held element values as a range of complex APInts. The /// element type of this attribute must be a complex of integer type. template using ComplexAPIntValueTemplateCheckT = std::enable_if_t>::value>; template > FailureOr> tryGetValues() const { return tryGetComplexIntValues(); } /// Try to get the held element values as a range of APFloat. The element type /// of this attribute must be of float type. template using APFloatValueTemplateCheckT = std::enable_if_t::value>; template > FailureOr> tryGetValues() const { return tryGetFloatValues(); } /// Try to get the held element values as a range of complex APFloat. The /// element type of this attribute must be a complex of float type. template using ComplexAPFloatValueTemplateCheckT = std::enable_if_t>::value>; template > FailureOr> tryGetValues() const { return tryGetComplexFloatValues(); } /// Return the raw storage data held by this attribute. Users should generally /// not use this directly, as the internal storage format is not always in the /// form the user might expect. ArrayRef getRawData() const; /// Return the raw StringRef data held by this attribute. ArrayRef getRawStringData() const; /// Return the type of this ElementsAttr, guaranteed to be a vector or tensor /// with static shape. ShapedType getType() const; /// Return the element type of this DenseElementsAttr. Type getElementType() const; /// Returns the number of elements held by this attribute. int64_t getNumElements() const; /// Returns the number of elements held by this attribute. int64_t size() const { return getNumElements(); } /// Returns if the number of elements held by this attribute is 0. bool empty() const { return size() == 0; } //===--------------------------------------------------------------------===// // 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); /// Return a new DenseElementsAttr that has the same data as the current /// attribute, but with a different shape for a splat type. The new type must /// have the same element type. DenseElementsAttr resizeSplat(ShapedType newType); /// Return a new DenseElementsAttr that has the same data as the current /// attribute, but has bitcast elements to 'newElType'. The new type must have /// the same bitwidth as the current element type. DenseElementsAttr bitcast(Type newElType); /// Generates a new DenseElementsAttr by mapping each int value to a new /// underlying APInt. The new values can represent either an integer or float. /// This underlying type must be an DenseIntElementsAttr. DenseElementsAttr mapValues(Type newElementType, function_ref mapping) const; /// Generates a new DenseElementsAttr by mapping each float value to a new /// underlying APInt. the new values can represent either an integer or float. /// This underlying type must be an DenseFPElementsAttr. DenseElementsAttr mapValues(Type newElementType, function_ref mapping) const; protected: /// Iterators to various elements that require out-of-line definition. These /// are hidden from the user to encourage consistent use of the /// getValues/value_begin/value_end API. IntElementIterator raw_int_begin() const { return IntElementIterator(*this, 0); } IntElementIterator raw_int_end() const { return IntElementIterator(*this, getNumElements()); } FailureOr> tryGetComplexIntValues() const; FailureOr> tryGetFloatValues() const; FailureOr> tryGetComplexFloatValues() const; /// Overload of the raw 'get' method that asserts that the given type is of /// complex type. This method is used to verify type invariants that the /// templatized 'get' method cannot. static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef data, int64_t dataEltSize, bool isInt, bool isSigned); /// 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 data, int64_t dataEltSize, bool isInt, bool isSigned); /// 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 isValidBool() const { return getElementType().isInteger(1); } bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const; bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const; }; /// 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 = llvm::dyn_cast(attr); return denseAttr && denseAttr.isSplat(); } }; //===----------------------------------------------------------------------===// // DenseResourceElementsAttr //===----------------------------------------------------------------------===// using DenseResourceElementsHandle = DialectResourceBlobHandle; } // namespace mlir //===----------------------------------------------------------------------===// // Tablegen Attribute Declarations //===----------------------------------------------------------------------===// #define GET_ATTRDEF_CLASSES #include "mlir/IR/BuiltinAttributes.h.inc" //===----------------------------------------------------------------------===// // C++ Attribute Declarations //===----------------------------------------------------------------------===// namespace mlir { /// DenseIntOrFPElementsAttr was renamed to DenseTypedElementsAttr. This alias /// is provided for backwards compatibility. It will be removed in the future. using DenseIntOrFPElementsAttr [[deprecated( "DenseIntOrFPElementsAttr has been renamed to DenseTypedElementsAttr")]] = DenseTypedElementsAttr; //===----------------------------------------------------------------------===// // DenseArrayAttr //===----------------------------------------------------------------------===// namespace detail { /// Base class for DenseArrayAttr that is instantiated and specialized for each /// supported element type below. template class DenseArrayAttrImpl : public DenseArrayAttr { public: using DenseArrayAttr::DenseArrayAttr; /// Implicit conversion to ArrayRef. operator ArrayRef() const; ArrayRef asArrayRef() const { return ArrayRef{*this}; } /// Random access to elements. T operator[](std::size_t index) const { return asArrayRef()[index]; } /// Builder from ArrayRef. static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef content); /// Print the short form `[42, 100, -1]` without any type prefix. void print(AsmPrinter &printer) const; void print(raw_ostream &os) const; /// Print the short form `42, 100, -1` without any braces or type prefix. void printWithoutBraces(raw_ostream &os) const; /// Parse the short form `[42, 100, -1]` without any type prefix. static Attribute parse(AsmParser &parser, Type type); /// Parse the short form `42, 100, -1` without any type prefix or braces. static Attribute parseWithoutBraces(AsmParser &parser, Type type); /// Support for isa<>/cast<>. static bool classof(Attribute attr); }; extern template class DenseArrayAttrImpl; extern template class DenseArrayAttrImpl; extern template class DenseArrayAttrImpl; extern template class DenseArrayAttrImpl; extern template class DenseArrayAttrImpl; extern template class DenseArrayAttrImpl; extern template class DenseArrayAttrImpl; } // namespace detail // Public name for all the supported DenseArrayAttr using DenseBoolArrayAttr = detail::DenseArrayAttrImpl; using DenseI8ArrayAttr = detail::DenseArrayAttrImpl; using DenseI16ArrayAttr = detail::DenseArrayAttrImpl; using DenseI32ArrayAttr = detail::DenseArrayAttrImpl; using DenseI64ArrayAttr = detail::DenseArrayAttrImpl; using DenseF32ArrayAttr = detail::DenseArrayAttrImpl; using DenseF64ArrayAttr = detail::DenseArrayAttrImpl; //===----------------------------------------------------------------------===// // DenseResourceElementsAttr //===----------------------------------------------------------------------===// namespace detail { /// Base class for DenseResourceElementsAttr that is instantiated and /// specialized for each supported element type below. template class DenseResourceElementsAttrBase : public DenseResourceElementsAttr { public: using DenseResourceElementsAttr::DenseResourceElementsAttr; /// A builder that inserts a new resource using the provided blob. The handle /// of the inserted blob is used when building the attribute. The provided /// `blobName` is used as a hint for the key of the new handle for the `blob` /// resource, but may be changed if necessary to ensure uniqueness during /// insertion. static DenseResourceElementsAttrBase get(ShapedType type, StringRef blobName, AsmResourceBlob blob); /// Return the data of this attribute as an ArrayRef if it is present, /// returns std::nullopt otherwise. std::optional> tryGetAsArrayRef() const; /// Support for isa<>/cast<>. static bool classof(Attribute attr); }; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; extern template class DenseResourceElementsAttrBase; } // namespace detail // Public names for all the supported DenseResourceElementsAttr. using DenseBoolResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseI8ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseI16ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseI32ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseI64ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseUI8ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseUI16ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseUI32ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseUI64ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseF32ResourceElementsAttr = detail::DenseResourceElementsAttrBase; using DenseF64ResourceElementsAttr = detail::DenseResourceElementsAttrBase; //===----------------------------------------------------------------------===// // BoolAttr //===----------------------------------------------------------------------===// /// Special case of IntegerAttr to represent boolean integers, i.e., signless i1 /// integers. class BoolAttr : public Attribute { public: using Attribute::Attribute; using ValueType = bool; static BoolAttr get(MLIRContext *context, bool value); /// Enable conversion to IntegerAttr and its interfaces. This uses conversion /// vs. inheritance to avoid bringing in all of IntegerAttrs methods. operator IntegerAttr() const { return IntegerAttr(impl); } operator TypedAttr() const { return IntegerAttr(impl); } /// Return the boolean value of this attribute. bool getValue() const; /// Methods for support type inquiry through isa, cast, and dyn_cast. static bool classof(Attribute attr); }; //===----------------------------------------------------------------------===// // FlatSymbolRefAttr //===----------------------------------------------------------------------===// /// A symbol reference with a reference path containing a single element. This /// is used to refer to an operation within the current symbol table. class FlatSymbolRefAttr : public SymbolRefAttr { public: using SymbolRefAttr::SymbolRefAttr; using ValueType = StringRef; /// Construct a symbol reference for the given value name. static FlatSymbolRefAttr get(StringAttr value) { return SymbolRefAttr::get(value); } static FlatSymbolRefAttr get(MLIRContext *ctx, StringRef value) { return SymbolRefAttr::get(ctx, value); } /// Convenience getter for building a SymbolRefAttr based on an operation /// that implements the SymbolTrait. static FlatSymbolRefAttr get(Operation *symbol) { return SymbolRefAttr::get(symbol); } /// Returns the name of the held symbol reference as a StringAttr. StringAttr getAttr() const { return getRootReference(); } /// Returns the name of the held symbol reference. StringRef getValue() const { return getAttr().getValue(); } /// Methods for support type inquiry through isa, cast, and dyn_cast. static bool classof(Attribute attr) { SymbolRefAttr refAttr = llvm::dyn_cast(attr); return refAttr && refAttr.getNestedReferences().empty(); } private: using SymbolRefAttr::get; using SymbolRefAttr::getNestedReferences; }; //===----------------------------------------------------------------------===// // DenseFPElementsAttr //===----------------------------------------------------------------------===// /// An attribute that represents a reference to a dense float vector or tensor /// object. Each element is stored as a double. class DenseFPElementsAttr : public DenseTypedElementsAttr { public: using iterator = DenseElementsAttr::FloatElementIterator; using DenseTypedElementsAttr::DenseTypedElementsAttr; /// Get an instance of a DenseFPElementsAttr with the given arguments. This /// simply wraps the DenseElementsAttr::get calls. template static DenseFPElementsAttr get(const ShapedType &type, Arg &&arg) { return llvm::cast( DenseElementsAttr::get(type, llvm::ArrayRef(arg))); } template static DenseFPElementsAttr get(const ShapedType &type, const std::initializer_list &list) { return llvm::cast(DenseElementsAttr::get(type, list)); } /// Generates a new DenseElementsAttr by mapping each value attribute, and /// constructing the DenseElementsAttr given the new element type. DenseElementsAttr mapValues(Type newElementType, function_ref mapping) const; /// Iterator access to the float element values. iterator begin() const { return tryGetFloatValues()->begin(); } iterator end() const { return tryGetFloatValues()->end(); } /// Method for supporting type inquiry through isa, cast and dyn_cast. static bool classof(Attribute attr); }; //===----------------------------------------------------------------------===// // DenseIntElementsAttr //===----------------------------------------------------------------------===// /// An attribute that represents a reference to a dense integer vector or tensor /// object. class DenseIntElementsAttr : public DenseTypedElementsAttr { public: /// DenseIntElementsAttr iterates on APInt, so we can use the raw element /// iterator directly. using iterator = DenseElementsAttr::IntElementIterator; using DenseTypedElementsAttr::DenseTypedElementsAttr; /// Get an instance of a DenseIntElementsAttr with the given arguments. This /// simply wraps the DenseElementsAttr::get calls. template static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg) { return llvm::cast( DenseElementsAttr::get(type, llvm::ArrayRef(arg))); } template static DenseIntElementsAttr get(const ShapedType &type, const std::initializer_list &list) { return llvm::cast(DenseElementsAttr::get(type, list)); } /// Generates a new DenseElementsAttr by mapping each value attribute, and /// constructing the DenseElementsAttr given the new element type. DenseElementsAttr mapValues(Type newElementType, function_ref 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); }; //===----------------------------------------------------------------------===// // SparseElementsAttr //===----------------------------------------------------------------------===// template auto SparseElementsAttr::try_value_begin_impl(OverloadToken) const -> FailureOr> { auto zeroValue = getZeroValue(); auto valueIt = getValues().try_value_begin(); if (failed(valueIt)) return failure(); const SmallVector flatSparseIndices(getFlattenedSparseIndices()); std::function mapFn = [flatSparseIndices{flatSparseIndices}, valueIt{std::move(*valueIt)}, zeroValue{std::move(zeroValue)}](ptrdiff_t index) { // Try to map the current index to one of the sparse indices. for (unsigned i = 0, e = flatSparseIndices.size(); i != e; ++i) if (flatSparseIndices[i] == index) return *std::next(valueIt, i); // Otherwise, return the zero value. return zeroValue; }; return iterator(llvm::seq(0, getNumElements()).begin(), mapFn); } //===----------------------------------------------------------------------===// // DistinctAttr //===----------------------------------------------------------------------===// namespace detail { struct DistinctAttrStorage; class DistinctAttributeUniquer; } // namespace detail /// An attribute that associates a referenced attribute with a unique /// identifier. Every call to the create function allocates a new distinct /// attribute instance. The address of the attribute instance serves as a /// temporary identifier. Similar to the names of SSA values, the final /// identifiers are generated during pretty printing. This delayed numbering /// ensures the printed identifiers are deterministic even if multiple distinct /// attribute instances are created in-parallel. /// /// Examples: /// /// #distinct = distinct[0]<42.0 : f32> /// #distinct1 = distinct[1]<42.0 : f32> /// #distinct2 = distinct[2]> /// /// NOTE: The distinct attribute cannot be defined using ODS since it uses a /// custom distinct attribute uniquer that cannot be set from ODS. class DistinctAttr : public detail::StorageUserBase { public: using Base::Base; /// Returns the referenced attribute. Attribute getReferencedAttr() const; /// Creates a distinct attribute that associates a referenced attribute with a /// unique identifier. static DistinctAttr create(Attribute referencedAttr); static constexpr StringLiteral name = "builtin.distinct"; }; //===----------------------------------------------------------------------===// // StringAttr //===----------------------------------------------------------------------===// /// Define comparisons for StringAttr against nullptr and itself to avoid the /// StringRef overloads from being chosen when not desirable. inline bool operator==(StringAttr lhs, std::nullptr_t) { return !lhs; } inline bool operator!=(StringAttr lhs, std::nullptr_t) { return static_cast(lhs); } inline bool operator==(StringAttr lhs, StringAttr rhs) { return (Attribute)lhs == (Attribute)rhs; } inline bool operator!=(StringAttr lhs, StringAttr rhs) { return !(lhs == rhs); } /// Allow direct comparison with StringRef. inline bool operator==(StringAttr lhs, StringRef rhs) { return lhs.getValue() == rhs; } inline bool operator!=(StringAttr lhs, StringRef rhs) { return !(lhs == rhs); } inline bool operator==(StringRef lhs, StringAttr rhs) { return rhs.getValue() == lhs; } inline bool operator!=(StringRef lhs, StringAttr rhs) { return !(lhs == rhs); } } // namespace mlir //===----------------------------------------------------------------------===// // Attribute Utilities //===----------------------------------------------------------------------===// namespace mlir { /// Given a list of strides (in which ShapedType::kDynamic /// represents a dynamic value), return the single result AffineMap which /// represents the linearized strided layout map. Dimensions correspond to the /// offset followed by the strides in order. Symbols are inserted for each /// dynamic dimension in order. A stride is always positive. /// /// Examples: /// ========= /// /// 1. For offset: 0 strides: ?, ?, 1 return /// (i, j, k)[M, N]->(M * i + N * j + k) /// /// 2. For offset: 3 strides: 32, ?, 16 return /// (i, j, k)[M]->(3 + 32 * i + M * j + 16 * k) /// /// 3. For offset: ? strides: ?, ?, ? return /// (i, j, k)[off, M, N, P]->(off + M * i + N * j + P * k) AffineMap makeStridedLinearLayoutMap(ArrayRef strides, int64_t offset, MLIRContext *context); } // namespace mlir namespace llvm { template <> struct DenseMapInfo : public DenseMapInfo { }; template <> struct PointerLikeTypeTraits : public PointerLikeTypeTraits { static inline mlir::StringAttr getFromVoidPointer(void *p) { return mlir::StringAttr::getFromOpaquePointer(p); } }; template <> struct PointerLikeTypeTraits : public PointerLikeTypeTraits { static inline mlir::IntegerAttr getFromVoidPointer(void *p) { return mlir::IntegerAttr::getFromOpaquePointer(p); } }; template <> struct PointerLikeTypeTraits : public PointerLikeTypeTraits { static inline mlir::SymbolRefAttr getFromVoidPointer(void *ptr) { return mlir::SymbolRefAttr::getFromOpaquePointer(ptr); } }; } // namespace llvm #endif // MLIR_IR_BUILTINATTRIBUTES_H