1135 lines
46 KiB
C++
1135 lines
46 KiB
C++
//===- 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 <optional>
|
|
|
|
namespace mlir {
|
|
class AffineMap;
|
|
class AsmResourceBlob;
|
|
class BoolAttr;
|
|
class BuiltinDialect;
|
|
class DenseIntElementsAttr;
|
|
template <typename T>
|
|
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<const char *, bool>;
|
|
|
|
/// 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 <typename ConcreteT, typename T, typename PointerT = T *,
|
|
typename ReferenceT = T &>
|
|
class DenseElementIndexedIteratorImpl
|
|
: public llvm::indexed_accessor_iterator<ConcreteT, DenseIterPtrAndSplat, T,
|
|
PointerT, ReferenceT> {
|
|
protected:
|
|
DenseElementIndexedIteratorImpl(const char *data, bool isSplat,
|
|
size_t dataIndex)
|
|
: llvm::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->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 <typename T>
|
|
struct is_complex_t : public std::false_type {};
|
|
template <typename T>
|
|
struct is_complex_t<std::complex<T>> : public std::true_type {};
|
|
template <typename T>
|
|
struct is_complex_t<mlir::NonFloatComplex<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<ElementsAttr>(*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 <typename T>
|
|
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<T, float, double>::value ||
|
|
(std::numeric_limits<T>::is_specialized &&
|
|
!std::numeric_limits<T>::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<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 = std::enable_if_t<std::numeric_limits<T>::is_integer ||
|
|
is_valid_cpp_fp_type<T>::value>>
|
|
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),
|
|
std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed);
|
|
}
|
|
|
|
/// Constructs a dense integer elements attribute from a single element.
|
|
template <typename T,
|
|
typename = std::enable_if_t<std::numeric_limits<T>::is_integer ||
|
|
is_valid_cpp_fp_type<T>::value ||
|
|
detail::is_complex_t<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<detail::is_complex_t<T>::value &&
|
|
(std::numeric_limits<ElementT>::is_integer ||
|
|
is_valid_cpp_fp_type<ElementT>::value)>>
|
|
static DenseElementsAttr get(const ShapedType &type, ArrayRef<T> values) {
|
|
const char *data = reinterpret_cast<const char *>(values.data());
|
|
return getRawComplex(type, ArrayRef<char>(data, values.size() * sizeof(T)),
|
|
sizeof(T), std::numeric_limits<ElementT>::is_integer,
|
|
std::numeric_limits<ElementT>::is_signed);
|
|
}
|
|
|
|
/// Overload of the above 'get' method that is specialized for boolean values.
|
|
static DenseElementsAttr get(ShapedType type, ArrayRef<bool> values);
|
|
|
|
/// Overload of the above 'get' method that is specialized for StringRef
|
|
/// values.
|
|
static DenseElementsAttr get(ShapedType type, ArrayRef<StringRef> 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 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<mlir::Complex<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);
|
|
|
|
/// 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<mlir::Complex<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));
|
|
}
|
|
|
|
/// 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<char> rawBuffer);
|
|
|
|
/// Returns true if the given buffer is a valid raw buffer for the given type.
|
|
static bool isValidRawBuffer(ShapedType type, ArrayRef<char> rawBuffer);
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Iterators
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
/// The iterator range over the given iterator type T.
|
|
template <typename IteratorT>
|
|
using iterator_range_impl = detail::ElementsAttrRange<IteratorT>;
|
|
|
|
/// The iterator for the given element type T.
|
|
template <typename T, typename AttrT = DenseElementsAttr>
|
|
using iterator = decltype(std::declval<AttrT>().template value_begin<T>());
|
|
/// The iterator range over the given element T.
|
|
template <typename T, typename AttrT = DenseElementsAttr>
|
|
using iterator_range =
|
|
decltype(std::declval<AttrT>().template getValues<T>());
|
|
|
|
/// A utility iterator that allows walking over the internal Attribute values
|
|
/// of a DenseElementsAttr.
|
|
class AttributeElementIterator
|
|
: public llvm::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;
|
|
};
|
|
|
|
/// A utility iterator that allows walking over the internal raw complex APInt
|
|
/// values.
|
|
class ComplexIntElementIterator
|
|
: public detail::DenseElementIndexedIteratorImpl<
|
|
ComplexIntElementIterator, mlir::Complex<APInt>,
|
|
mlir::Complex<APInt>, mlir::Complex<APInt>> {
|
|
public:
|
|
/// Accesses the raw mlir::Complex<APInt> value at this iterator position.
|
|
mlir::Complex<APInt> 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<FloatElementIterator,
|
|
IntElementIterator, APFloat> {
|
|
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<ComplexFloatElementIterator,
|
|
ComplexIntElementIterator,
|
|
mlir::Complex<APFloat>> {
|
|
public:
|
|
/// Map the element to the iterator result type.
|
|
mlir::Complex<APFloat> mapElement(const mlir::Complex<APInt> &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 <typename T>
|
|
std::enable_if_t<!std::is_base_of<Attribute, T>::value ||
|
|
std::is_same<Attribute, T>::value,
|
|
T>
|
|
getSplatValue() const {
|
|
assert(isSplat() && "expected the attribute to be a splat");
|
|
return *value_begin<T>();
|
|
}
|
|
/// Return the splat value for derived attribute element types.
|
|
template <typename T>
|
|
std::enable_if_t<std::is_base_of<Attribute, T>::value &&
|
|
!std::is_same<Attribute, T>::value,
|
|
T>
|
|
getSplatValue() const {
|
|
return llvm::cast<T>(getSplatValue<Attribute>());
|
|
}
|
|
|
|
/// 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 <typename T>
|
|
auto try_value_begin() const {
|
|
auto range = tryGetValues<T>();
|
|
using iterator = decltype(range->begin());
|
|
return failed(range) ? FailureOr<iterator>(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 <typename T>
|
|
auto try_value_end() const {
|
|
auto range = tryGetValues<T>();
|
|
using iterator = decltype(range->begin());
|
|
return failed(range) ? FailureOr<iterator>(failure()) : range->end();
|
|
}
|
|
|
|
/// Return the held element values as a range of the given type.
|
|
template <typename T>
|
|
auto getValues() const {
|
|
auto range = tryGetValues<T>();
|
|
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 <typename T>
|
|
auto value_begin() const {
|
|
return getValues<T>().begin();
|
|
}
|
|
|
|
/// Get an iterator of the given type to the end of the held element values.
|
|
template <typename T>
|
|
auto value_end() const {
|
|
return getValues<T>().end();
|
|
}
|
|
|
|
/// Try to get the held element values as a range of integer or floating-point
|
|
/// values.
|
|
template <typename T>
|
|
using IntFloatValueTemplateCheckT =
|
|
std::enable_if_t<(!std::is_same<T, bool>::value &&
|
|
std::numeric_limits<T>::is_integer) ||
|
|
is_valid_cpp_fp_type<T>::value>;
|
|
template <typename T, typename = IntFloatValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<ElementIterator<T>>> tryGetValues() const {
|
|
if (!isValidIntOrFloat(sizeof(T), std::numeric_limits<T>::is_integer,
|
|
std::numeric_limits<T>::is_signed))
|
|
return failure();
|
|
const char *rawData = getRawData().data();
|
|
bool splat = isSplat();
|
|
return iterator_range_impl<ElementIterator<T>>(
|
|
getType(), ElementIterator<T>(rawData, splat, 0),
|
|
ElementIterator<T>(rawData, splat, getNumElements()));
|
|
}
|
|
|
|
/// Try to get the held element values as a range of mlir::Complex.
|
|
template <typename T, typename ElementT>
|
|
using ComplexValueTemplateCheckT =
|
|
std::enable_if_t<detail::is_complex_t<T>::value &&
|
|
(std::numeric_limits<ElementT>::is_integer ||
|
|
is_valid_cpp_fp_type<ElementT>::value)>;
|
|
template <typename T, typename ElementT = typename T::value_type,
|
|
typename = ComplexValueTemplateCheckT<T, ElementT>>
|
|
FailureOr<iterator_range_impl<ElementIterator<T>>> tryGetValues() const {
|
|
if (!isValidComplex(sizeof(T), std::numeric_limits<ElementT>::is_integer,
|
|
std::numeric_limits<ElementT>::is_signed))
|
|
return failure();
|
|
const char *rawData = getRawData().data();
|
|
bool splat = isSplat();
|
|
return iterator_range_impl<ElementIterator<T>>(
|
|
getType(), ElementIterator<T>(rawData, splat, 0),
|
|
ElementIterator<T>(rawData, splat, getNumElements()));
|
|
}
|
|
|
|
/// Try to get the held element values as a range of StringRef.
|
|
template <typename T>
|
|
using StringRefValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, StringRef>::value>;
|
|
template <typename T, typename = StringRefValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<ElementIterator<StringRef>>>
|
|
tryGetValues() const {
|
|
auto stringRefs = getRawStringData();
|
|
const char *ptr = reinterpret_cast<const char *>(stringRefs.data());
|
|
bool splat = isSplat();
|
|
return iterator_range_impl<ElementIterator<StringRef>>(
|
|
getType(), ElementIterator<StringRef>(ptr, splat, 0),
|
|
ElementIterator<StringRef>(ptr, splat, getNumElements()));
|
|
}
|
|
|
|
/// Try to get the held element values as a range of Attributes.
|
|
template <typename T>
|
|
using AttributeValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, Attribute>::value>;
|
|
template <typename T, typename = AttributeValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<AttributeElementIterator>>
|
|
tryGetValues() const {
|
|
return iterator_range_impl<AttributeElementIterator>(
|
|
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 <typename T>
|
|
using DerivedAttrValueTemplateCheckT =
|
|
std::enable_if_t<std::is_base_of<Attribute, T>::value &&
|
|
!std::is_same<Attribute, T>::value>;
|
|
template <typename T>
|
|
struct DerivedAttributeElementIterator
|
|
: public llvm::mapped_iterator_base<DerivedAttributeElementIterator<T>,
|
|
AttributeElementIterator, T> {
|
|
using llvm::mapped_iterator_base<DerivedAttributeElementIterator<T>,
|
|
AttributeElementIterator,
|
|
T>::mapped_iterator_base;
|
|
|
|
/// Map the element to the iterator result type.
|
|
T mapElement(Attribute attr) const { return llvm::cast<T>(attr); }
|
|
};
|
|
template <typename T, typename = DerivedAttrValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<DerivedAttributeElementIterator<T>>>
|
|
tryGetValues() const {
|
|
using DerivedIterT = DerivedAttributeElementIterator<T>;
|
|
return iterator_range_impl<DerivedIterT>(
|
|
getType(), DerivedIterT(value_begin<Attribute>()),
|
|
DerivedIterT(value_end<Attribute>()));
|
|
}
|
|
|
|
/// 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 <typename T>
|
|
using BoolValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, bool>::value>;
|
|
template <typename T, typename = BoolValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<BoolElementIterator>> tryGetValues() const {
|
|
if (!isValidBool())
|
|
return failure();
|
|
return iterator_range_impl<BoolElementIterator>(
|
|
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 <typename T>
|
|
using APIntValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, APInt>::value>;
|
|
template <typename T, typename = APIntValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<IntElementIterator>> tryGetValues() const {
|
|
if (!getElementType().isIntOrIndex())
|
|
return failure();
|
|
return iterator_range_impl<IntElementIterator>(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 <typename T>
|
|
using ComplexAPIntValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, mlir::Complex<APInt>>::value>;
|
|
template <typename T, typename = ComplexAPIntValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<ComplexIntElementIterator>>
|
|
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 <typename T>
|
|
using APFloatValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, APFloat>::value>;
|
|
template <typename T, typename = APFloatValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<FloatElementIterator>> 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 <typename T>
|
|
using ComplexAPFloatValueTemplateCheckT =
|
|
std::enable_if_t<std::is_same<T, mlir::Complex<APFloat>>::value>;
|
|
template <typename T, typename = ComplexAPFloatValueTemplateCheckT<T>>
|
|
FailureOr<iterator_range_impl<ComplexFloatElementIterator>>
|
|
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<char> getRawData() const;
|
|
|
|
/// Return the raw StringRef data held by this attribute.
|
|
ArrayRef<StringRef> 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<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 an integer or float.
|
|
/// This underlying type must be an DenseFPElementsAttr.
|
|
DenseElementsAttr
|
|
mapValues(Type newElementType,
|
|
function_ref<APInt(const APFloat &)> 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<iterator_range_impl<ComplexIntElementIterator>>
|
|
tryGetComplexIntValues() const;
|
|
FailureOr<iterator_range_impl<FloatElementIterator>>
|
|
tryGetFloatValues() const;
|
|
FailureOr<iterator_range_impl<ComplexFloatElementIterator>>
|
|
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<char> 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<char> 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<DenseElementsAttr>(attr);
|
|
return denseAttr && denseAttr.isSplat();
|
|
}
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// DenseResourceElementsAttr
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
using DenseResourceElementsHandle = DialectResourceBlobHandle<BuiltinDialect>;
|
|
|
|
} // 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 <typename T>
|
|
class DenseArrayAttrImpl : public DenseArrayAttr {
|
|
public:
|
|
using DenseArrayAttr::DenseArrayAttr;
|
|
|
|
/// Implicit conversion to ArrayRef<T>.
|
|
operator ArrayRef<T>() const;
|
|
ArrayRef<T> asArrayRef() const { return ArrayRef<T>{*this}; }
|
|
|
|
/// Random access to elements.
|
|
T operator[](std::size_t index) const { return asArrayRef()[index]; }
|
|
|
|
/// Builder from ArrayRef<T>.
|
|
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef<T> 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<bool>;
|
|
extern template class DenseArrayAttrImpl<int8_t>;
|
|
extern template class DenseArrayAttrImpl<int16_t>;
|
|
extern template class DenseArrayAttrImpl<int32_t>;
|
|
extern template class DenseArrayAttrImpl<int64_t>;
|
|
extern template class DenseArrayAttrImpl<float>;
|
|
extern template class DenseArrayAttrImpl<double>;
|
|
} // namespace detail
|
|
|
|
// Public name for all the supported DenseArrayAttr
|
|
using DenseBoolArrayAttr = detail::DenseArrayAttrImpl<bool>;
|
|
using DenseI8ArrayAttr = detail::DenseArrayAttrImpl<int8_t>;
|
|
using DenseI16ArrayAttr = detail::DenseArrayAttrImpl<int16_t>;
|
|
using DenseI32ArrayAttr = detail::DenseArrayAttrImpl<int32_t>;
|
|
using DenseI64ArrayAttr = detail::DenseArrayAttrImpl<int64_t>;
|
|
using DenseF32ArrayAttr = detail::DenseArrayAttrImpl<float>;
|
|
using DenseF64ArrayAttr = detail::DenseArrayAttrImpl<double>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// DenseResourceElementsAttr
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace detail {
|
|
/// Base class for DenseResourceElementsAttr that is instantiated and
|
|
/// specialized for each supported element type below.
|
|
template <typename T>
|
|
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<T>
|
|
get(ShapedType type, StringRef blobName, AsmResourceBlob blob);
|
|
|
|
/// Return the data of this attribute as an ArrayRef<T> if it is present,
|
|
/// returns std::nullopt otherwise.
|
|
std::optional<ArrayRef<T>> tryGetAsArrayRef() const;
|
|
|
|
/// Support for isa<>/cast<>.
|
|
static bool classof(Attribute attr);
|
|
};
|
|
|
|
extern template class DenseResourceElementsAttrBase<bool>;
|
|
extern template class DenseResourceElementsAttrBase<int8_t>;
|
|
extern template class DenseResourceElementsAttrBase<int16_t>;
|
|
extern template class DenseResourceElementsAttrBase<int32_t>;
|
|
extern template class DenseResourceElementsAttrBase<int64_t>;
|
|
extern template class DenseResourceElementsAttrBase<uint8_t>;
|
|
extern template class DenseResourceElementsAttrBase<uint16_t>;
|
|
extern template class DenseResourceElementsAttrBase<uint32_t>;
|
|
extern template class DenseResourceElementsAttrBase<uint64_t>;
|
|
extern template class DenseResourceElementsAttrBase<float>;
|
|
extern template class DenseResourceElementsAttrBase<double>;
|
|
} // namespace detail
|
|
|
|
// Public names for all the supported DenseResourceElementsAttr.
|
|
|
|
using DenseBoolResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<bool>;
|
|
using DenseI8ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<int8_t>;
|
|
using DenseI16ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<int16_t>;
|
|
using DenseI32ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<int32_t>;
|
|
using DenseI64ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<int64_t>;
|
|
using DenseUI8ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<uint8_t>;
|
|
using DenseUI16ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<uint16_t>;
|
|
using DenseUI32ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<uint32_t>;
|
|
using DenseUI64ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<uint64_t>;
|
|
using DenseF32ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<float>;
|
|
using DenseF64ResourceElementsAttr =
|
|
detail::DenseResourceElementsAttrBase<double>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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<SymbolRefAttr>(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 <typename Arg>
|
|
static DenseFPElementsAttr get(const ShapedType &type, Arg &&arg) {
|
|
return llvm::cast<DenseFPElementsAttr>(
|
|
DenseElementsAttr::get(type, llvm::ArrayRef(arg)));
|
|
}
|
|
template <typename T>
|
|
static DenseFPElementsAttr get(const ShapedType &type,
|
|
const std::initializer_list<T> &list) {
|
|
return llvm::cast<DenseFPElementsAttr>(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<APInt(const APFloat &)> 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 <typename Arg>
|
|
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg) {
|
|
return llvm::cast<DenseIntElementsAttr>(
|
|
DenseElementsAttr::get(type, llvm::ArrayRef(arg)));
|
|
}
|
|
template <typename T>
|
|
static DenseIntElementsAttr get(const ShapedType &type,
|
|
const std::initializer_list<T> &list) {
|
|
return llvm::cast<DenseIntElementsAttr>(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<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);
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SparseElementsAttr
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
template <typename T>
|
|
auto SparseElementsAttr::try_value_begin_impl(OverloadToken<T>) const
|
|
-> FailureOr<iterator<T>> {
|
|
auto zeroValue = getZeroValue<T>();
|
|
auto valueIt = getValues().try_value_begin<T>();
|
|
if (failed(valueIt))
|
|
return failure();
|
|
const SmallVector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices());
|
|
std::function<T(ptrdiff_t)> 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<T>(llvm::seq<ptrdiff_t>(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]<array<i32: 10, 42>>
|
|
///
|
|
/// 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<DistinctAttr, Attribute,
|
|
detail::DistinctAttrStorage,
|
|
detail::DistinctAttributeUniquer> {
|
|
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<bool>(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<int64_t> strides, int64_t offset,
|
|
MLIRContext *context);
|
|
|
|
} // namespace mlir
|
|
|
|
namespace llvm {
|
|
|
|
template <>
|
|
struct DenseMapInfo<mlir::StringAttr> : public DenseMapInfo<mlir::Attribute> {
|
|
};
|
|
template <>
|
|
struct PointerLikeTypeTraits<mlir::StringAttr>
|
|
: public PointerLikeTypeTraits<mlir::Attribute> {
|
|
static inline mlir::StringAttr getFromVoidPointer(void *p) {
|
|
return mlir::StringAttr::getFromOpaquePointer(p);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct PointerLikeTypeTraits<mlir::IntegerAttr>
|
|
: public PointerLikeTypeTraits<mlir::Attribute> {
|
|
static inline mlir::IntegerAttr getFromVoidPointer(void *p) {
|
|
return mlir::IntegerAttr::getFromOpaquePointer(p);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct PointerLikeTypeTraits<mlir::SymbolRefAttr>
|
|
: public PointerLikeTypeTraits<mlir::Attribute> {
|
|
static inline mlir::SymbolRefAttr getFromVoidPointer(void *ptr) {
|
|
return mlir::SymbolRefAttr::getFromOpaquePointer(ptr);
|
|
}
|
|
};
|
|
|
|
} // namespace llvm
|
|
|
|
#endif // MLIR_IR_BUILTINATTRIBUTES_H
|