[mlir][IR] Move the remaining builtin attributes to ODS.

With this revision, all builtin attributes and types will have been moved to the ODS generator.

Differential Revision: https://reviews.llvm.org/D98474
This commit is contained in:
River Riddle 2021-03-16 16:30:46 -07:00
parent 425e11eea1
commit caa7038a89
14 changed files with 674 additions and 742 deletions

View File

@ -16,160 +16,14 @@
namespace mlir {
class AffineMap;
class BoolAttr;
class DenseIntElementsAttr;
class FlatSymbolRefAttr;
class FunctionType;
class IntegerSet;
class IntegerType;
class Location;
class ShapedType;
} // namespace mlir
//===----------------------------------------------------------------------===//
// Tablegen Attribute Declarations
//===----------------------------------------------------------------------===//
#define GET_ATTRDEF_CLASSES
#include "mlir/IR/BuiltinAttributes.h.inc"
//===----------------------------------------------------------------------===//
// C++ Attribute Declarations
//===----------------------------------------------------------------------===//
namespace mlir {
namespace detail {
struct IntegerAttributeStorage;
struct FloatAttributeStorage;
struct SymbolRefAttributeStorage;
struct TypeAttributeStorage;
/// Elements Attributes.
struct DenseIntOrFPElementsAttributeStorage;
struct DenseStringElementsAttributeStorage;
struct OpaqueElementsAttributeStorage;
struct SparseElementsAttributeStorage;
} // namespace detail
//===----------------------------------------------------------------------===//
// FloatAttr
//===----------------------------------------------------------------------===//
class FloatAttr : public Attribute::AttrBase<FloatAttr, Attribute,
detail::FloatAttributeStorage> {
public:
using Base::Base;
using Base::getChecked;
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(function_ref<InFlightDiagnostic()> emitError,
Type type, double value);
/// Return a float attribute for the specified value in the specified type.
static FloatAttr get(Type type, const APFloat &value);
static FloatAttr getChecked(function_ref<InFlightDiagnostic()> emitError,
Type type, const APFloat &value);
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);
/// Verify the construction invariants for a double value.
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
Type type, double value);
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
Type type, const APFloat &value);
};
//===----------------------------------------------------------------------===//
// IntegerAttr
//===----------------------------------------------------------------------===//
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;
/// Return the integer value as a 64-bit int. The attribute must be a signless
/// integer.
// TODO: Change callers to use getValue instead.
int64_t getInt() const;
/// Return the integer value as a signed 64-bit int. The attribute must be
/// a signed integer.
int64_t getSInt() const;
/// Return the integer value as a unsigned 64-bit int. The attribute must be
/// an unsigned integer.
uint64_t getUInt() const;
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
Type type, int64_t value);
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
Type type, const APInt &value);
};
//===----------------------------------------------------------------------===//
// 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. This uses conversion vs. inheritance to
/// avoid bringing in all of IntegerAttrs methods.
operator IntegerAttr() 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(MLIRContext *ctx, StringRef value) {
return SymbolRefAttr::get(ctx, value);
}
/// Returns the name of the held symbol reference.
StringRef getValue() const { return getRootReference(); }
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(Attribute attr) {
SymbolRefAttr refAttr = attr.dyn_cast<SymbolRefAttr>();
return refAttr && refAttr.getNestedReferences().empty();
}
private:
using SymbolRefAttr::get;
using SymbolRefAttr::getNestedReferences;
};
//===----------------------------------------------------------------------===//
// Elements Attributes
@ -751,88 +605,91 @@ protected:
bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const;
};
/// An attribute class for representing dense arrays of strings. The structure
/// storing and querying a list of densely packed strings.
class DenseStringElementsAttr
: public Attribute::AttrBase<DenseStringElementsAttr, DenseElementsAttr,
detail::DenseStringElementsAttributeStorage> {
/// 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 Base::Base;
using DenseElementsAttr::DenseElementsAttr;
/// 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 DenseStringElementsAttr get(ShapedType type, ArrayRef<StringRef> data);
protected:
friend 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();
}
};
/// An attribute class for specializing behavior of Int and Floating-point
/// densely packed string arrays.
class DenseIntOrFPElementsAttr
: public Attribute::AttrBase<DenseIntOrFPElementsAttr, DenseElementsAttr,
detail::DenseIntOrFPElementsAttributeStorage> {
} // namespace mlir
//===----------------------------------------------------------------------===//
// Tablegen Attribute Declarations
//===----------------------------------------------------------------------===//
#define GET_ATTRDEF_CLASSES
#include "mlir/IR/BuiltinAttributes.h.inc"
//===----------------------------------------------------------------------===//
// C++ Attribute Declarations
//===----------------------------------------------------------------------===//
namespace mlir {
//===----------------------------------------------------------------------===//
// BoolAttr
//===----------------------------------------------------------------------===//
/// Special case of IntegerAttr to represent boolean integers, i.e., signless i1
/// integers.
class BoolAttr : public Attribute {
public:
using Base::Base;
using Attribute::Attribute;
using ValueType = bool;
/// Convert endianess of input ArrayRef for big-endian(BE) machines. All of
/// the elements of `inRawData` has `type`. If `inRawData` is little endian
/// (LE), it is converted to big endian (BE). Conversely, if `inRawData` is
/// BE, converted to LE.
static void
convertEndianOfArrayRefForBEmachine(ArrayRef<char> inRawData,
MutableArrayRef<char> outRawData,
ShapedType type);
static BoolAttr get(MLIRContext *context, bool value);
/// Convert endianess of input for big-endian(BE) machines. The number of
/// elements of `inRawData` is `numElements`, and each element has
/// `elementBitWidth` bits. If `inRawData` is little endian (LE), it is
/// converted to big endian (BE) and saved in `outRawData`. Conversely, if
/// `inRawData` is BE, converted to LE.
static void convertEndianOfCharForBEmachine(const char *inRawData,
char *outRawData,
size_t elementBitWidth,
size_t numElements);
/// Enable conversion to IntegerAttr. This uses conversion vs. inheritance to
/// avoid bringing in all of IntegerAttrs methods.
operator IntegerAttr() const { return IntegerAttr(impl); }
protected:
friend DenseElementsAttr;
/// Return the boolean value of this attribute.
bool getValue() const;
/// Constructs a dense elements attribute from an array of raw 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 getRaw(ShapedType type, size_t storageWidth,
ArrayRef<APFloat> values, bool isSplat);
/// 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, size_t storageWidth,
ArrayRef<APInt> values, bool isSplat);
/// 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
/// 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);
/// 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(MLIRContext *ctx, StringRef value) {
return SymbolRefAttr::get(ctx, value);
}
/// Returns the name of the held symbol reference.
StringRef getValue() const { return getRootReference(); }
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(Attribute attr) {
SymbolRefAttr refAttr = attr.dyn_cast<SymbolRefAttr>();
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 DenseIntOrFPElementsAttr {
@ -869,6 +726,10 @@ public:
static bool classof(Attribute attr);
};
//===----------------------------------------------------------------------===//
// DenseIntElementsAttr
//===----------------------------------------------------------------------===//
/// An attribute that represents a reference to a dense integer vector or tensor
/// object.
class DenseIntElementsAttr : public DenseIntOrFPElementsAttr {
@ -906,170 +767,27 @@ public:
static bool classof(Attribute attr);
};
/// An opaque attribute that represents a reference to a vector or tensor
/// constant with opaque content. This representation 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;
//===----------------------------------------------------------------------===//
// SparseElementsAttr
//===----------------------------------------------------------------------===//
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;
};
/// 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;
template <typename T>
using iterator =
llvm::mapped_iterator<llvm::detail::value_sequence_iterator<ptrdiff_t>,
std::function<T(ptrdiff_t)>>;
/// '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 values of this attribute in the form of the given type 'T'. 'T'
/// may be any of Attribute, APInt, APFloat, c++ integer/float types, etc.
template <typename T> llvm::iterator_range<iterator<T>> getValues() const {
auto zeroValue = getZeroValue<T>();
auto valueIt = getValues().getValues<T>().begin();
const std::vector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices());
// TODO: Move-capture flatSparseIndices when c++14 is available.
std::function<T(ptrdiff_t)> mapFn = [=](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 llvm::map_range(llvm::seq<ptrdiff_t>(0, getNumElements()), mapFn);
}
/// 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;
private:
/// Get a zero APFloat for the given sparse attribute.
APFloat getZeroAPFloat() const;
/// Get a zero APInt for the given sparse attribute.
APInt getZeroAPInt() const;
/// Get a zero attribute for the given sparse attribute.
Attribute getZeroAttr() const;
/// Utility methods to generate a zero value of some type 'T'. This is used by
/// the 'iterator' class.
/// Get a zero for a given attribute type.
template <typename T>
typename std::enable_if<std::is_base_of<Attribute, T>::value, T>::type
getZeroValue() const {
return getZeroAttr().template cast<T>();
}
/// Get a zero for an APInt.
template <typename T>
typename std::enable_if<std::is_same<APInt, T>::value, T>::type
getZeroValue() const {
return getZeroAPInt();
}
template <typename T>
typename std::enable_if<std::is_same<std::complex<APInt>, T>::value, T>::type
getZeroValue() const {
APInt intZero = getZeroAPInt();
return {intZero, intZero};
}
/// Get a zero for an APFloat.
template <typename T>
typename std::enable_if<std::is_same<APFloat, T>::value, T>::type
getZeroValue() const {
return getZeroAPFloat();
}
template <typename T>
typename std::enable_if<std::is_same<std::complex<APFloat>, T>::value,
T>::type
getZeroValue() const {
APFloat floatZero = getZeroAPFloat();
return {floatZero, floatZero};
}
/// Get a zero for an C++ integer, float, StringRef, or complex type.
template <typename T>
typename std::enable_if<
std::numeric_limits<T>::is_integer ||
DenseElementsAttr::is_valid_cpp_fp_type<T>::value ||
std::is_same<T, StringRef>::value ||
(detail::is_complex_t<T>::value &&
!llvm::is_one_of<T, std::complex<APInt>,
std::complex<APFloat>>::value),
T>::type
getZeroValue() const {
return T();
}
/// Flatten, and return, all of the sparse indices in this attribute in
/// row-major order.
std::vector<ptrdiff_t> getFlattenedSparseIndices() 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 = attr.dyn_cast<DenseElementsAttr>();
return denseAttr && denseAttr.isSplat();
}
};
template <typename T>
auto SparseElementsAttr::getValues() const
-> llvm::iterator_range<iterator<T>> {
auto zeroValue = getZeroValue<T>();
auto valueIt = getValues().getValues<T>().begin();
const std::vector<ptrdiff_t> flatSparseIndices(getFlattenedSparseIndices());
// TODO: Move-capture flatSparseIndices when c++14 is available.
std::function<T(ptrdiff_t)> mapFn = [=](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 llvm::map_range(llvm::seq<ptrdiff_t>(0, getNumElements()), mapFn);
}
namespace detail {
/// This class represents a general iterator over the values of an ElementsAttr.

View File

@ -22,7 +22,8 @@ include "mlir/IR/BuiltinDialect.td"
// to this file instead.
// Base class for Builtin dialect attributes.
class Builtin_Attr<string name> : AttrDef<Builtin_Dialect, name> {
class Builtin_Attr<string name, string baseCppClass = "::mlir::Attribute">
: AttrDef<Builtin_Dialect, name, baseCppClass> {
let mnemonic = ?;
}
@ -127,6 +128,151 @@ def Builtin_ArrayAttr : Builtin_Attr<"Array"> {
}];
}
//===----------------------------------------------------------------------===//
// DenseIntOrFPElementsAttr
//===----------------------------------------------------------------------===//
def Builtin_DenseIntOrFPElementsAttr
: Builtin_Attr<"DenseIntOrFPElements", "DenseElementsAttr"> {
let summary = "An Attribute containing a dense multi-dimensional array of "
"integer or floating-point values";
let description = [{
Syntax:
```
dense-intorfloat-elements-attribute ::= `dense` `<` attribute-value `>` `:`
( tensor-type | vector-type )
```
A dense int-or-float elements attribute is an elements attribute containing
a densely packed vector or tensor of integer or floating-point values. The
element type of this attribute is required to be either an `IntegerType` or
a `FloatType`.
Examples:
```
// A splat tensor of integer values.
dense<10> : tensor<2xi32>
// A tensor of 2 float32 elements.
dense<[10.0, 11.0]> : tensor<2xf32>
```
}];
let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
"ArrayRef<char>":$rawData);
let extraClassDeclaration = [{
/// Convert endianess of input ArrayRef for big-endian(BE) machines. All of
/// the elements of `inRawData` has `type`. If `inRawData` is little endian
/// (LE), it is converted to big endian (BE). Conversely, if `inRawData` is
/// BE, converted to LE.
static void
convertEndianOfArrayRefForBEmachine(ArrayRef<char> inRawData,
MutableArrayRef<char> outRawData,
ShapedType type);
/// Convert endianess of input for big-endian(BE) machines. The number of
/// elements of `inRawData` is `numElements`, and each element has
/// `elementBitWidth` bits. If `inRawData` is little endian (LE), it is
/// converted to big endian (BE) and saved in `outRawData`. Conversely, if
/// `inRawData` is BE, converted to LE.
static void convertEndianOfCharForBEmachine(const char *inRawData,
char *outRawData,
size_t elementBitWidth,
size_t numElements);
protected:
friend DenseElementsAttr;
/// Constructs a dense elements attribute from an array of raw 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 getRaw(ShapedType type, size_t storageWidth,
ArrayRef<APFloat> values, bool isSplat);
/// 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, size_t storageWidth,
ArrayRef<APInt> values, bool isSplat);
/// 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
/// 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);
public:
}];
let genAccessors = 0;
let genStorageClass = 0;
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// DenseStringElementsAttr
//===----------------------------------------------------------------------===//
def Builtin_DenseStringElementsAttr
: Builtin_Attr<"DenseStringElements", "DenseElementsAttr"> {
let summary = "An Attribute containing a dense multi-dimensional array of "
"strings";
let description = [{
Syntax:
```
dense-string-elements-attribute ::= `dense` `<` attribute-value `>` `:`
( tensor-type | vector-type )
```
A dense string elements attribute is an elements attribute containing a
densely packed vector or tensor of string values. There are no restrictions
placed on the element type of this attribute, enabling the use of dialect
specific string types.
Examples:
```
// A splat tensor of strings.
dense<"example"> : tensor<2x!foo.string>
// A tensor of 2 string elements.
dense<["example1", "example2"]> : tensor<2x!foo.string>
```
}];
let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
"ArrayRef<StringRef>":$value);
let builders = [
AttrBuilderWithInferredContext<(ins "ShapedType":$type,
"ArrayRef<StringRef>":$values), [{
return $_get(type.getContext(), type, values,
/* isSplat */(values.size() == 1));
}]>,
];
let extraClassDeclaration = [{
protected:
friend DenseElementsAttr;
public:
}];
let genAccessors = 0;
let genStorageClass = 0;
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// DictionaryAttr
//===----------------------------------------------------------------------===//
@ -220,6 +366,147 @@ def Builtin_DictionaryAttr : Builtin_Attr<"Dictionary"> {
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// FloatAttr
//===----------------------------------------------------------------------===//
def Builtin_FloatAttr : Builtin_Attr<"Float"> {
let summary = "An Attribute containing a floating-point value";
let description = [{
Syntax:
```
float-attribute ::= (float-literal (`:` float-type)?)
| (hexadecimal-literal `:` float-type)
```
A float attribute is a literal attribute that represents a floating point
value of the specified [float type](#floating-point-types). It can be
represented in the hexadecimal form where the hexadecimal value is
interpreted as bits of the underlying binary representation. This form is
useful for representing infinity and NaN floating point values. To avoid
confusion with integer attributes, hexadecimal literals _must_ be followed
by a float type to define a float attribute.
Examples:
```
42.0 // float attribute defaults to f64 type
42.0 : f32 // float attribute of f32 type
0x7C00 : f16 // positive infinity
0x7CFF : f16 // NaN (one of possible values)
42 : f32 // Error: expected integer type
```
}];
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
APFloatParameter<"">:$value);
let builders = [
AttrBuilderWithInferredContext<(ins "Type":$type,
"const APFloat &":$value), [{
return $_get(type.getContext(), type, value);
}]>,
AttrBuilderWithInferredContext<(ins "Type":$type, "double":$value), [{
if (type.isF64())
return $_get(type.getContext(), type, APFloat(value));
// This handles, e.g., F16 because there is no APFloat constructor for it.
bool unused;
APFloat val(value);
val.convert(type.cast<FloatType>().getFloatSemantics(),
APFloat::rmNearestTiesToEven, &unused);
return $_get(type.getContext(), type, val);
}]>
];
let extraClassDeclaration = [{
using ValueType = APFloat;
/// This function is used to convert the value to a double, even if it loses
/// precision.
double getValueAsDouble() const;
static double getValueAsDouble(APFloat val);
}];
let genVerifyDecl = 1;
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// IntegerAttr
//===----------------------------------------------------------------------===//
def Builtin_IntegerAttr : Builtin_Attr<"Integer"> {
let summary = "An Attribute containing a integer value";
let description = [{
Syntax:
```
integer-attribute ::= (integer-literal ( `:` (index-type | integer-type) )?)
| `true` | `false`
```
An integer attribute is a literal attribute that represents an integral
value of the specified integer or index type. `i1` integer attributes are
treated as `boolean` attributes, and use a unique assembly format of either
`true` or `false` depending on the value. The default type for non-boolean
integer attributes, if a type is not specified, is signless 64-bit integer.
Examples:
```mlir
10 : i32
10 // : i64 is implied here.
true // A bool, i.e. i1, value.
false // A bool, i.e. i1, value.
```
}];
let parameters = (ins AttributeSelfTypeParameter<"">:$type, "APInt":$value);
let builders = [
AttrBuilderWithInferredContext<(ins "Type":$type,
"const APInt &":$value), [{
if (type.isSignlessInteger(1))
return BoolAttr::get(type.getContext(), value.getBoolValue());
return $_get(type.getContext(), type, value);
}]>,
AttrBuilderWithInferredContext<(ins "Type":$type, "int64_t":$value), [{
// `index` has a defined internal storage width.
if (type.isIndex()) {
APInt apValue(IndexType::kInternalStorageBitWidth, value);
return $_get(type.getContext(), type, apValue);
}
IntegerType intTy = type.cast<IntegerType>();
APInt apValue(intTy.getWidth(), value, intTy.isSignedInteger());
return $_get(type.getContext(), type, apValue);
}]>
];
let extraClassDeclaration = [{
using ValueType = APInt;
/// Return the integer value as a 64-bit int. The attribute must be a
/// signless integer.
// TODO: Change callers to use getValue instead.
int64_t getInt() const;
/// Return the integer value as a signed 64-bit int. The attribute must be
/// a signed integer.
int64_t getSInt() const;
/// Return the integer value as a unsigned 64-bit int. The attribute must be
/// an unsigned integer.
uint64_t getUInt() const;
private:
/// Return a boolean attribute. This is a special variant of the `get`
/// method that is used by the MLIRContext to cache the boolean IntegerAttr
/// instances.
static BoolAttr getBoolAttrUnchecked(IntegerType type, bool value);
/// Allow access to `getBoolAttrUnchecked`.
friend MLIRContext;
public:
}];
let genVerifyDecl = 1;
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// IntegerSetAttr
//===----------------------------------------------------------------------===//
@ -282,8 +569,212 @@ def Builtin_OpaqueAttr : Builtin_Attr<"Opaque"> {
return $_get(dialect.getContext(), dialect, attrData, type);
}]>
];
bit genVerifyDecl = 1;
// let skipDefaultBuilders = 1;
let genVerifyDecl = 1;
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// OpaqueElementsAttr
//===----------------------------------------------------------------------===//
def Builtin_OpaqueElementsAttr
: Builtin_Attr<"OpaqueElements", "ElementsAttr"> {
let summary = "An opaque representation of a multi-dimensional array";
let description = [{
Syntax:
```
opaque-elements-attribute ::= `opaque` `<` dialect-namespace `,`
hex-string-literal `>` `:`
( tensor-type | vector-type )
```
An opaque elements attribute is an elements attribute where the content of
the value is opaque. The representation of the constant stored by this
elements attribute is only understood, and thus decodable, by the dialect
that created it.
Note: The parsed string literal must be in hexadecimal form.
Examples:
```mlir
opaque<"foo_dialect", "0xDEADBEEF"> : tensor<10xi32>
```
}];
// TODO: Provide a way to avoid copying content of large opaque
// tensors This will likely require a new reference attribute kind.
let parameters = (ins "Identifier":$dialect,
StringRefParameter<"">:$value,
AttributeSelfTypeParameter<"", "ShapedType">:$type);
let builders = [
AttrBuilderWithInferredContext<(ins "Identifier":$dialect,
"ShapedType":$type,
"StringRef":$value), [{
return $_get(dialect.getContext(), dialect, value, type);
}]>,
AttrBuilderWithInferredContext<(ins "Dialect *":$dialect,
"ShapedType":$type,
"StringRef":$value), [{
MLIRContext *ctxt = dialect->getContext();
Identifier dialectName = Identifier::get(dialect->getNamespace(), ctxt);
return $_get(ctxt, dialectName, value, type);
}]>
];
let extraClassDeclaration = [{
using ValueType = StringRef;
/// 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);
}];
let genVerifyDecl = 1;
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//
// SparseElementsAttr
//===----------------------------------------------------------------------===//
def Builtin_SparseElementsAttr
: Builtin_Attr<"SparseElements", "ElementsAttr"> {
let summary = "An opaque representation of a multi-dimensional array";
let description = [{
Syntax:
```
sparse-elements-attribute ::= `sparse` `<` attribute-value `,`
attribute-value `>` `:`
( tensor-type | vector-type )
```
A sparse elements attribute is an elements attribute that represents a
sparse vector or tensor object. This is where very few of the elements are
non-zero.
The attribute uses COO (coordinate list) encoding to represent the sparse
elements of the elements attribute. The indices are stored via 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 non-zero values.
The element values are stored via a 1-D tensor with shape [N], that supplies
the corresponding values for the indices.
Example:
```mlir
sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>
// This represents the following tensor:
/// [[1, 0, 0, 0],
/// [0, 0, 5, 0],
/// [0, 0, 0, 0]]
```
}];
let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
"DenseIntElementsAttr":$indices,
"DenseElementsAttr":$values);
let builders = [
AttrBuilderWithInferredContext<(ins "ShapedType":$type,
"DenseElementsAttr":$indices,
"DenseElementsAttr":$values), [{
assert(indices.getType().getElementType().isInteger(64) &&
"expected sparse indices to be 64-bit integer values");
assert((type.isa<RankedTensorType, VectorType>()) &&
"type must be ranked tensor or vector");
assert(type.hasStaticShape() && "type must have static shape");
return $_get(type.getContext(), type,
indices.cast<DenseIntElementsAttr>(), values);
}]>,
];
let extraClassDeclaration = [{
template <typename T>
using iterator =
llvm::mapped_iterator<llvm::detail::value_sequence_iterator<ptrdiff_t>,
std::function<T(ptrdiff_t)>>;
/// Return the values of this attribute in the form of the given type 'T'.
/// 'T' may be any of Attribute, APInt, APFloat, c++ integer/float types,
/// etc.
template <typename T> llvm::iterator_range<iterator<T>> 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;
private:
/// Get a zero APFloat for the given sparse attribute.
APFloat getZeroAPFloat() const;
/// Get a zero APInt for the given sparse attribute.
APInt getZeroAPInt() const;
/// Get a zero attribute for the given sparse attribute.
Attribute getZeroAttr() const;
/// Utility methods to generate a zero value of some type 'T'. This is used
/// by the 'iterator' class.
/// Get a zero for a given attribute type.
template <typename T>
typename std::enable_if<std::is_base_of<Attribute, T>::value, T>::type
getZeroValue() const {
return getZeroAttr().template cast<T>();
}
/// Get a zero for an APInt.
template <typename T>
typename std::enable_if<std::is_same<APInt, T>::value, T>::type
getZeroValue() const {
return getZeroAPInt();
}
template <typename T>
typename std::enable_if<std::is_same<std::complex<APInt>, T>::value,
T>::type
getZeroValue() const {
APInt intZero = getZeroAPInt();
return {intZero, intZero};
}
/// Get a zero for an APFloat.
template <typename T>
typename std::enable_if<std::is_same<APFloat, T>::value, T>::type
getZeroValue() const {
return getZeroAPFloat();
}
template <typename T>
typename std::enable_if<std::is_same<std::complex<APFloat>, T>::value,
T>::type
getZeroValue() const {
APFloat floatZero = getZeroAPFloat();
return {floatZero, floatZero};
}
/// Get a zero for an C++ integer, float, StringRef, or complex type.
template <typename T>
typename std::enable_if<
std::numeric_limits<T>::is_integer ||
DenseElementsAttr::is_valid_cpp_fp_type<T>::value ||
std::is_same<T, StringRef>::value ||
(detail::is_complex_t<T>::value &&
!llvm::is_one_of<T, std::complex<APInt>,
std::complex<APFloat>>::value),
T>::type
getZeroValue() const {
return T();
}
/// Flatten, and return, all of the sparse indices in this attribute in
/// row-major order.
std::vector<ptrdiff_t> getFlattenedSparseIndices() const;
public:
}];
let skipDefaultBuilders = 1;
}
//===----------------------------------------------------------------------===//

View File

@ -2723,7 +2723,8 @@ class ArrayRefOfSelfAllocationParameter<string arrayOf, string desc> :
// This is a special parameter used for AttrDefs that represents a `mlir::Type`
// that is also used as the value `Type` of the attribute. Only one parameter
// of the attribute may be of this type.
class AttributeSelfTypeParameter<string desc> :
AttrOrTypeParameter<"::mlir::Type", desc> {}
class AttributeSelfTypeParameter<string desc,
string derivedType = "::mlir::Type"> :
AttrOrTypeParameter<derivedType, desc> {}
#endif // OP_BASE

View File

@ -1515,7 +1515,7 @@ static void printSymbolReference(StringRef symbolRef, raw_ostream &os) {
// accept the string "elided". The first string must be a registered dialect
// name and the latter must be a hex constant.
static void printElidedElementsAttr(raw_ostream &os) {
os << R"(opaque<"", "0xDEADBEEF">)";
os << R"(opaque<"_", "0xDEADBEEF">)";
}
void ModulePrinter::printAttribute(Attribute attr,
@ -1610,8 +1610,8 @@ void ModulePrinter::printAttribute(Attribute attr,
if (printerFlags.shouldElideElementsAttr(opaqueAttr)) {
printElidedElementsAttr(os);
} else {
os << "opaque<\"" << opaqueAttr.getDialect()->getNamespace() << "\", ";
os << '"' << "0x" << llvm::toHex(opaqueAttr.getValue()) << "\">";
os << "opaque<\"" << opaqueAttr.getDialect() << "\", \"0x"
<< llvm::toHex(opaqueAttr.getValue()) << "\">";
}
} else if (auto intOrFpEltAttr = attr.dyn_cast<DenseIntOrFPElementsAttr>()) {

View File

@ -27,113 +27,6 @@
namespace mlir {
namespace detail {
/// An attribute representing a floating point value.
struct FloatAttributeStorage final
: public AttributeStorage,
public llvm::TrailingObjects<FloatAttributeStorage, uint64_t> {
using KeyTy = std::pair<Type, APFloat>;
FloatAttributeStorage(const llvm::fltSemantics &semantics, Type type,
size_t numObjects)
: AttributeStorage(type), semantics(semantics), numObjects(numObjects) {}
/// Key equality and hash functions.
bool operator==(const KeyTy &key) const {
return key.first == getType() && key.second.bitwiseIsEqual(getValue());
}
static unsigned hashKey(const KeyTy &key) {
return llvm::hash_combine(key.first, llvm::hash_value(key.second));
}
/// Construct a key with a type and double.
static KeyTy getKey(Type type, double value) {
if (type.isF64())
return KeyTy(type, APFloat(value));
// This handles, e.g., F16 because there is no APFloat constructor for it.
bool unused;
APFloat val(value);
val.convert(type.cast<FloatType>().getFloatSemantics(),
APFloat::rmNearestTiesToEven, &unused);
return KeyTy(type, val);
}
/// Construct a new storage instance.
static FloatAttributeStorage *construct(AttributeStorageAllocator &allocator,
const KeyTy &key) {
const auto &apint = key.second.bitcastToAPInt();
// Here one word's bitwidth equals to that of uint64_t.
auto elements = ArrayRef<uint64_t>(apint.getRawData(), apint.getNumWords());
auto byteSize =
FloatAttributeStorage::totalSizeToAlloc<uint64_t>(elements.size());
auto rawMem = allocator.allocate(byteSize, alignof(FloatAttributeStorage));
auto result = ::new (rawMem) FloatAttributeStorage(
key.second.getSemantics(), key.first, elements.size());
std::uninitialized_copy(elements.begin(), elements.end(),
result->getTrailingObjects<uint64_t>());
return result;
}
/// Returns an APFloat representing the stored value.
APFloat getValue() const {
auto val = APInt(APFloat::getSizeInBits(semantics),
{getTrailingObjects<uint64_t>(), numObjects});
return APFloat(semantics, val);
}
const llvm::fltSemantics &semantics;
size_t numObjects;
};
/// An attribute representing an integral value.
struct IntegerAttributeStorage final
: public AttributeStorage,
public llvm::TrailingObjects<IntegerAttributeStorage, uint64_t> {
using KeyTy = std::pair<Type, APInt>;
IntegerAttributeStorage(Type type, size_t numObjects)
: AttributeStorage(type), numObjects(numObjects) {
assert((type.isIndex() || type.isa<IntegerType>()) && "invalid type");
}
/// Key equality and hash functions.
bool operator==(const KeyTy &key) const {
return key == KeyTy(getType(), getValue());
}
static unsigned hashKey(const KeyTy &key) {
return llvm::hash_combine(key.first, llvm::hash_value(key.second));
}
/// Construct a new storage instance.
static IntegerAttributeStorage *
construct(AttributeStorageAllocator &allocator, const KeyTy &key) {
Type type;
APInt value;
std::tie(type, value) = key;
auto elements = ArrayRef<uint64_t>(value.getRawData(), value.getNumWords());
auto size =
IntegerAttributeStorage::totalSizeToAlloc<uint64_t>(elements.size());
auto rawMem = allocator.allocate(size, alignof(IntegerAttributeStorage));
auto result = ::new (rawMem) IntegerAttributeStorage(type, elements.size());
std::uninitialized_copy(elements.begin(), elements.end(),
result->getTrailingObjects<uint64_t>());
return result;
}
/// Returns an APInt representing the stored value.
APInt getValue() const {
if (getType().isIndex())
return APInt(64, {getTrailingObjects<uint64_t>(), numObjects});
return APInt(getType().getIntOrFloatBitWidth(),
{getTrailingObjects<uint64_t>(), numObjects});
}
size_t numObjects;
};
//===----------------------------------------------------------------------===//
// Elements Attributes
//===----------------------------------------------------------------------===//
@ -158,10 +51,9 @@ public:
};
/// An attribute representing a reference to a dense vector or tensor object.
struct DenseIntOrFPElementsAttributeStorage
: public DenseElementsAttributeStorage {
DenseIntOrFPElementsAttributeStorage(ShapedType ty, ArrayRef<char> data,
bool isSplat = false)
struct DenseIntOrFPElementsAttrStorage : public DenseElementsAttributeStorage {
DenseIntOrFPElementsAttrStorage(ShapedType ty, ArrayRef<char> data,
bool isSplat = false)
: DenseElementsAttributeStorage(ty, isSplat), data(data) {}
struct KeyTy {
@ -287,7 +179,7 @@ struct DenseIntOrFPElementsAttributeStorage
}
/// Construct a new storage instance.
static DenseIntOrFPElementsAttributeStorage *
static DenseIntOrFPElementsAttrStorage *
construct(AttributeStorageAllocator &allocator, KeyTy key) {
// If the data buffer is non-empty, we copy it into the allocator with a
// 64-bit alignment.
@ -303,8 +195,8 @@ struct DenseIntOrFPElementsAttributeStorage
copy = ArrayRef<char>(rawData, data.size());
}
return new (allocator.allocate<DenseIntOrFPElementsAttributeStorage>())
DenseIntOrFPElementsAttributeStorage(key.type, copy, key.isSplat);
return new (allocator.allocate<DenseIntOrFPElementsAttrStorage>())
DenseIntOrFPElementsAttrStorage(key.type, copy, key.isSplat);
}
ArrayRef<char> data;
@ -312,10 +204,9 @@ struct DenseIntOrFPElementsAttributeStorage
/// An attribute representing a reference to a dense vector or tensor object
/// containing strings.
struct DenseStringElementsAttributeStorage
: public DenseElementsAttributeStorage {
DenseStringElementsAttributeStorage(ShapedType ty, ArrayRef<StringRef> data,
bool isSplat = false)
struct DenseStringElementsAttrStorage : public DenseElementsAttributeStorage {
DenseStringElementsAttrStorage(ShapedType ty, ArrayRef<StringRef> data,
bool isSplat = false)
: DenseElementsAttributeStorage(ty, isSplat), data(data) {}
struct KeyTy {
@ -385,14 +276,14 @@ struct DenseStringElementsAttributeStorage
}
/// Construct a new storage instance.
static DenseStringElementsAttributeStorage *
static DenseStringElementsAttrStorage *
construct(AttributeStorageAllocator &allocator, KeyTy key) {
// If the data buffer is non-empty, we copy it into the allocator with a
// 64-bit alignment.
ArrayRef<StringRef> copy, data = key.data;
if (data.empty()) {
return new (allocator.allocate<DenseStringElementsAttributeStorage>())
DenseStringElementsAttributeStorage(key.type, copy, key.isSplat);
return new (allocator.allocate<DenseStringElementsAttrStorage>())
DenseStringElementsAttrStorage(key.type, copy, key.isSplat);
}
int numEntries = key.isSplat ? 1 : data.size();
@ -421,72 +312,13 @@ struct DenseStringElementsAttributeStorage
copy =
ArrayRef<StringRef>(reinterpret_cast<StringRef *>(rawData), numEntries);
return new (allocator.allocate<DenseStringElementsAttributeStorage>())
DenseStringElementsAttributeStorage(key.type, copy, key.isSplat);
return new (allocator.allocate<DenseStringElementsAttrStorage>())
DenseStringElementsAttrStorage(key.type, copy, key.isSplat);
}
ArrayRef<StringRef> data;
};
/// An attribute representing a reference to a tensor constant with opaque
/// content.
struct OpaqueElementsAttributeStorage : public AttributeStorage {
using KeyTy = std::tuple<Type, Dialect *, StringRef>;
OpaqueElementsAttributeStorage(Type type, Dialect *dialect, StringRef bytes)
: AttributeStorage(type), dialect(dialect), bytes(bytes) {}
/// Key equality and hash functions.
bool operator==(const KeyTy &key) const {
return key == std::make_tuple(getType(), dialect, bytes);
}
static unsigned hashKey(const KeyTy &key) {
return llvm::hash_combine(std::get<0>(key), std::get<1>(key),
std::get<2>(key));
}
/// Construct a new storage instance.
static OpaqueElementsAttributeStorage *
construct(AttributeStorageAllocator &allocator, KeyTy key) {
// TODO: Provide a way to avoid copying content of large opaque
// tensors This will likely require a new reference attribute kind.
return new (allocator.allocate<OpaqueElementsAttributeStorage>())
OpaqueElementsAttributeStorage(std::get<0>(key), std::get<1>(key),
allocator.copyInto(std::get<2>(key)));
}
Dialect *dialect;
StringRef bytes;
};
/// An attribute representing a reference to a sparse vector or tensor object.
struct SparseElementsAttributeStorage : public AttributeStorage {
using KeyTy = std::tuple<Type, DenseIntElementsAttr, DenseElementsAttr>;
SparseElementsAttributeStorage(Type type, DenseIntElementsAttr indices,
DenseElementsAttr values)
: AttributeStorage(type), indices(indices), values(values) {}
/// Key equality and hash functions.
bool operator==(const KeyTy &key) const {
return key == std::make_tuple(getType(), indices, values);
}
static unsigned hashKey(const KeyTy &key) {
return llvm::hash_combine(std::get<0>(key), std::get<1>(key),
std::get<2>(key));
}
/// Construct a new storage instance.
static SparseElementsAttributeStorage *
construct(AttributeStorageAllocator &allocator, KeyTy key) {
return new (allocator.allocate<SparseElementsAttributeStorage>())
SparseElementsAttributeStorage(std::get<0>(key), std::get<1>(key),
std::get<2>(key));
}
DenseIntElementsAttr indices;
DenseElementsAttr values;
};
} // namespace detail
} // namespace mlir

View File

@ -202,26 +202,6 @@ DictionaryAttr DictionaryAttr::getEmptyUnchecked(MLIRContext *context) {
// FloatAttr
//===----------------------------------------------------------------------===//
FloatAttr FloatAttr::get(Type type, double value) {
return Base::get(type.getContext(), type, value);
}
FloatAttr FloatAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
Type type, double value) {
return Base::getChecked(emitError, type.getContext(), type, value);
}
FloatAttr FloatAttr::get(Type type, const APFloat &value) {
return Base::get(type.getContext(), type, value);
}
FloatAttr FloatAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
Type type, const APFloat &value) {
return Base::getChecked(emitError, type.getContext(), type, value);
}
APFloat FloatAttr::getValue() const { return getImpl()->getValue(); }
double FloatAttr::getValueAsDouble() const {
return getValueAsDouble(getValue());
}
@ -234,25 +214,11 @@ double FloatAttr::getValueAsDouble(APFloat value) {
return value.convertToDouble();
}
/// Verify construction invariants.
static LogicalResult
verifyFloatTypeInvariants(function_ref<InFlightDiagnostic()> emitError,
Type type) {
LogicalResult FloatAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Type type, APFloat value) {
// Verify that the type is correct.
if (!type.isa<FloatType>())
return emitError() << "expected floating point type";
return success();
}
LogicalResult FloatAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Type type, double value) {
return verifyFloatTypeInvariants(emitError, type);
}
LogicalResult FloatAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Type type, const APFloat &value) {
// Verify that the type is correct.
if (failed(verifyFloatTypeInvariants(emitError, type)))
return failure();
// Verify that the type semantics match that of the value.
if (&type.cast<FloatType>().getFloatSemantics() != &value.getSemantics()) {
@ -279,72 +245,47 @@ StringRef SymbolRefAttr::getLeafReference() const {
// IntegerAttr
//===----------------------------------------------------------------------===//
IntegerAttr IntegerAttr::get(Type type, const APInt &value) {
if (type.isSignlessInteger(1))
return BoolAttr::get(type.getContext(), value.getBoolValue());
return Base::get(type.getContext(), type, value);
}
IntegerAttr IntegerAttr::get(Type type, int64_t value) {
// This uses 64 bit APInts by default for index type.
if (type.isIndex())
return get(type, APInt(IndexType::kInternalStorageBitWidth, value));
auto intType = type.cast<IntegerType>();
return get(type, APInt(intType.getWidth(), value, intType.isSignedInteger()));
}
APInt IntegerAttr::getValue() const { return getImpl()->getValue(); }
int64_t IntegerAttr::getInt() const {
assert((getImpl()->getType().isIndex() ||
getImpl()->getType().isSignlessInteger()) &&
assert((getType().isIndex() || getType().isSignlessInteger()) &&
"must be signless integer");
return getValue().getSExtValue();
}
int64_t IntegerAttr::getSInt() const {
assert(getImpl()->getType().isSignedInteger() && "must be signed integer");
assert(getType().isSignedInteger() && "must be signed integer");
return getValue().getSExtValue();
}
uint64_t IntegerAttr::getUInt() const {
assert(getImpl()->getType().isUnsignedInteger() &&
"must be unsigned integer");
assert(getType().isUnsignedInteger() && "must be unsigned integer");
return getValue().getZExtValue();
}
static LogicalResult
verifyIntegerTypeInvariants(function_ref<InFlightDiagnostic()> emitError,
Type type) {
if (type.isa<IntegerType, IndexType>())
return success();
return emitError() << "expected integer or index type";
}
LogicalResult IntegerAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Type type, int64_t value) {
return verifyIntegerTypeInvariants(emitError, type);
}
LogicalResult IntegerAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Type type, const APInt &value) {
if (failed(verifyIntegerTypeInvariants(emitError, type)))
return failure();
if (auto integerType = type.dyn_cast<IntegerType>())
Type type, APInt value) {
if (IntegerType integerType = type.dyn_cast<IntegerType>()) {
if (integerType.getWidth() != value.getBitWidth())
return emitError() << "integer type bit width (" << integerType.getWidth()
<< ") doesn't match value bit width ("
<< value.getBitWidth() << ")";
return success();
return success();
}
if (type.isa<IndexType>())
return success();
return emitError() << "expected integer or index type";
}
BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type, bool value) {
auto attr = Base::get(type.getContext(), type, APInt(/*numBits=*/1, value));
return attr.cast<BoolAttr>();
}
//===----------------------------------------------------------------------===//
// BoolAttr
bool BoolAttr::getValue() const {
auto *storage = reinterpret_cast<IntegerAttributeStorage *>(impl);
return storage->getValue().getBoolValue();
auto *storage = reinterpret_cast<IntegerAttrStorage *>(impl);
return storage->value.getBoolValue();
}
bool BoolAttr::classof(Attribute attr) {
@ -987,11 +928,11 @@ auto DenseElementsAttr::getComplexFloatValues() const
/// Return the raw storage data held by this attribute.
ArrayRef<char> DenseElementsAttr::getRawData() const {
return static_cast<DenseIntOrFPElementsAttributeStorage *>(impl)->data;
return static_cast<DenseIntOrFPElementsAttrStorage *>(impl)->data;
}
ArrayRef<StringRef> DenseElementsAttr::getRawStringData() const {
return static_cast<DenseStringElementsAttributeStorage *>(impl)->data;
return static_cast<DenseStringElementsAttrStorage *>(impl)->data;
}
/// Return a new DenseElementsAttr that has the same data as the current
@ -1021,15 +962,6 @@ DenseElementsAttr DenseElementsAttr::mapValues(
return cast<DenseFPElementsAttr>().mapValues(newElementType, mapping);
}
//===----------------------------------------------------------------------===//
// DenseStringElementsAttr
//===----------------------------------------------------------------------===//
DenseStringElementsAttr
DenseStringElementsAttr::get(ShapedType type, ArrayRef<StringRef> values) {
return Base::get(type.getContext(), type, values, (values.size() == 1));
}
//===----------------------------------------------------------------------===//
// DenseIntOrFPElementsAttr
//===----------------------------------------------------------------------===//
@ -1254,15 +1186,6 @@ bool DenseIntElementsAttr::classof(Attribute attr) {
// OpaqueElementsAttr
//===----------------------------------------------------------------------===//
OpaqueElementsAttr OpaqueElementsAttr::get(Dialect *dialect, ShapedType type,
StringRef bytes) {
assert(TensorType::isValidElementType(type.getElementType()) &&
"Input element type should be a valid tensor element type");
return Base::get(type.getContext(), type, dialect, bytes);
}
StringRef OpaqueElementsAttr::getValue() const { return getImpl()->bytes; }
/// Return the value at the given index. If index does not refer to a valid
/// element, then a null attribute is returned.
Attribute OpaqueElementsAttr::getValue(ArrayRef<uint64_t> index) const {
@ -1270,43 +1193,30 @@ Attribute OpaqueElementsAttr::getValue(ArrayRef<uint64_t> index) const {
return Attribute();
}
Dialect *OpaqueElementsAttr::getDialect() const { return getImpl()->dialect; }
bool OpaqueElementsAttr::decode(ElementsAttr &result) {
auto *d = getDialect();
if (!d)
Dialect *dialect = getDialect().getDialect();
if (!dialect)
return true;
auto *interface =
d->getRegisteredInterface<DialectDecodeAttributesInterface>();
dialect->getRegisteredInterface<DialectDecodeAttributesInterface>();
if (!interface)
return true;
return failed(interface->decode(*this, result));
}
LogicalResult
OpaqueElementsAttr::verify(function_ref<InFlightDiagnostic()> emitError,
Identifier dialect, StringRef value,
ShapedType type) {
if (!Dialect::isValidNamespace(dialect.strref()))
return emitError() << "invalid dialect namespace '" << dialect << "'";
return success();
}
//===----------------------------------------------------------------------===//
// SparseElementsAttr
//===----------------------------------------------------------------------===//
SparseElementsAttr SparseElementsAttr::get(ShapedType type,
DenseElementsAttr indices,
DenseElementsAttr values) {
assert(indices.getType().getElementType().isInteger(64) &&
"expected sparse indices to be 64-bit integer values");
assert((type.isa<RankedTensorType, VectorType>()) &&
"type must be ranked tensor or vector");
assert(type.hasStaticShape() && "type must have static shape");
return Base::get(type.getContext(), type,
indices.cast<DenseIntElementsAttr>(), values);
}
DenseIntElementsAttr SparseElementsAttr::getIndices() const {
return getImpl()->indices;
}
DenseElementsAttr SparseElementsAttr::getValues() const {
return getImpl()->values;
}
/// Return the value of the element at the given index.
Attribute SparseElementsAttr::getValue(ArrayRef<uint64_t> index) const {
assert(isValidIndex(index) && "expected valid multi-dimensional index");

View File

@ -390,17 +390,13 @@ MLIRContext::MLIRContext(const DialectRegistry &registry)
//// Attributes.
//// Note: These must be registered after the types as they may generate one
//// of the above types internally.
/// Bool Attributes.
impl->falseAttr = AttributeUniquer::get<IntegerAttr>(
this, impl->int1Ty, APInt(/*numBits=*/1, false))
.cast<BoolAttr>();
impl->trueAttr = AttributeUniquer::get<IntegerAttr>(
this, impl->int1Ty, APInt(/*numBits=*/1, true))
.cast<BoolAttr>();
/// Unit Attribute.
impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
/// Unknown Location Attribute.
impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
/// Bool Attributes.
impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
/// Unit Attribute.
impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
/// The empty dictionary attribute.
impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);

View File

@ -862,16 +862,7 @@ Attribute Parser::parseOpaqueElementsAttr(Type attrType) {
if (getToken().isNot(Token::string))
return (emitError("expected dialect namespace"), nullptr);
auto name = getToken().getStringValue();
// Lazy load a dialect in the context if there is a possible namespace.
Dialect *dialect = builder.getContext()->getOrLoadDialect(name);
// TODO: Allow for having an unknown dialect on an opaque
// attribute. Otherwise, it can't be roundtripped without having the dialect
// registered.
if (!dialect)
return (emitError("no registered dialect with namespace '" + name + "'"),
nullptr);
std::string name = getToken().getStringValue();
consumeToken(Token::string);
if (parseToken(Token::comma, "expected ','"))
@ -888,7 +879,7 @@ Attribute Parser::parseOpaqueElementsAttr(Type attrType) {
std::string data;
if (parseElementAttrHexValues(*this, hexTok, data))
return nullptr;
return OpaqueElementsAttr::get(dialect, type, data);
return OpaqueElementsAttr::get(builder.getIdentifier(name), type, data);
}
/// Shaped type for elements attribute.

View File

@ -45,10 +45,6 @@ AttrOrTypeDef::AttrOrTypeDef(const llvm::Record *def) : def(def) {
}
builders.emplace_back(builder);
}
} else if (skipDefaultBuilders()) {
PrintFatalError(
def->getLoc(),
"default builders are skipped and no custom builders provided");
}
}

View File

@ -449,7 +449,7 @@ static void printFirstOfEach(MlirContext ctx, MlirOperation operation) {
mlirOperationPrintWithFlags(operation, flags, printToStderr, NULL);
fprintf(stderr, "\n");
// clang-format off
// CHECK: Op print with all flags: %{{.*}} = "std.constant"() {elts = opaque<"", "0xDEADBEEF"> : tensor<4xi32>, value = 0 : index} : () -> index loc(unknown)
// CHECK: Op print with all flags: %{{.*}} = "std.constant"() {elts = opaque<"_", "0xDEADBEEF"> : tensor<4xi32>, value = 0 : index} : () -> index loc(unknown)
// clang-format on
mlirOpPrintingFlagsDestroy(flags);

View File

@ -766,21 +766,14 @@ func @elementsattr_malformed_opaque() -> () {
func @elementsattr_malformed_opaque1() -> () {
^bb0:
"foo"(){bar = opaque<"", "0xQZz123"> : tensor<1xi8>} : () -> () // expected-error {{expected string containing hex digits starting with `0x`}}
"foo"(){bar = opaque<"_", "0xQZz123"> : tensor<1xi8>} : () -> () // expected-error {{expected string containing hex digits starting with `0x`}}
}
// -----
func @elementsattr_malformed_opaque2() -> () {
^bb0:
"foo"(){bar = opaque<"", "00abc"> : tensor<1xi8>} : () -> () // expected-error {{expected string containing hex digits starting with `0x`}}
}
// -----
func @elementsattr_malformed_opaque3() -> () {
^bb0:
"foo"(){bar = opaque<"t", "0xabc"> : tensor<1xi8>} : () -> () // expected-error {{no registered dialect with namespace 't'}}
"foo"(){bar = opaque<"_", "00abc"> : tensor<1xi8>} : () -> () // expected-error {{expected string containing hex digits starting with `0x`}}
}
// -----
@ -881,7 +874,7 @@ func @type_alias_unknown(!unknown_alias) -> () { // expected-error {{undefined s
func @complex_loops() {
affine.for %i1 = 1 to 100 {
// expected-error @+1 {{expected '"' in string literal}}
"opaqueIntTensor"(){bar = opaque<"", "0x686]> : tensor<2x1x4xi32>} : () -> ()
"opaqueIntTensor"(){bar = opaque<"_", "0x686]> : tensor<2x1x4xi32>} : () -> ()
// -----

View File

@ -5,17 +5,17 @@
// tensor which passes don't look at directly, this isn't an issue.
// RUN: mlir-opt %s -mlir-elide-elementsattrs-if-larger=2 | mlir-opt
// CHECK: opaque<"", "0xDEADBEEF"> : tensor<3xi32>
// CHECK: opaque<"_", "0xDEADBEEF"> : tensor<3xi32>
"test.dense_attr"() {foo.dense_attr = dense<[1, 2, 3]> : tensor<3xi32>} : () -> ()
// CHECK: dense<[1, 2]> : tensor<2xi32>
"test.non_elided_dense_attr"() {foo.dense_attr = dense<[1, 2]> : tensor<2xi32>} : () -> ()
// CHECK: opaque<"", "0xDEADBEEF"> : vector<1x1x1xf16>
// CHECK: opaque<"_", "0xDEADBEEF"> : vector<1x1x1xf16>
"test.sparse_attr"() {foo.sparse_attr = sparse<[[1, 2, 3]], -2.0> : vector<1x1x1xf16>} : () -> ()
// CHECK: opaque<"", "0xDEADBEEF"> : tensor<100xf32>
"test.opaque_attr"() {foo.opaque_attr = opaque<"", "0xEBFE"> : tensor<100xf32> } : () -> ()
// CHECK: opaque<"_", "0xDEADBEEF"> : tensor<100xf32>
"test.opaque_attr"() {foo.opaque_attr = opaque<"_", "0xEBFE"> : tensor<100xf32> } : () -> ()
// CHECK: dense<1> : tensor<3xi32>
"test.dense_splat"() {foo.dense_attr = dense<1> : tensor<3xi32>} : () -> ()

View File

@ -95,7 +95,7 @@ def B_CompoundAttrA : TestAttr<"CompoundA"> {
// DEF: return new (allocator.allocate<CompoundAAttrStorage>())
// DEF-NEXT: CompoundAAttrStorage(widthOfSomething, exampleTdType, apFloat, dims, inner);
// DEF: ::mlir::Type CompoundAAttr::getInner() const { return getImpl()->getType(); }
// DEF: ::mlir::Type CompoundAAttr::getInner() const { return getImpl()->getType().cast<::mlir::Type>(); }
}
def C_IndexAttr : TestAttr<"Index"> {

View File

@ -776,15 +776,19 @@ void DefGenerator::emitDefDef(const AttrOrTypeDef &def) {
// Generate accessor definitions only if we also generate the storage class.
// Otherwise, let the user define the exact accessor definition.
if (def.genAccessors() && def.genStorageClass()) {
for (const AttrOrTypeParameter &parameter : parameters) {
StringRef paramStorageName = isa<AttributeSelfTypeParameter>(parameter)
? "getType()"
: parameter.getName();
for (const AttrOrTypeParameter &param : parameters) {
SmallString<32> paramStorageName;
if (isa<AttributeSelfTypeParameter>(param)) {
Twine("getType().cast<" + param.getCppType() + ">()")
.toVector(paramStorageName);
} else {
paramStorageName = param.getName();
}
SmallString<16> name = parameter.getName();
SmallString<16> name = param.getName();
name[0] = llvm::toUpper(name[0]);
os << formatv("{0} {3}::get{1}() const {{ return getImpl()->{2}; }\n",
parameter.getCppType(), name, paramStorageName,
param.getCppType(), name, paramStorageName,
def.getCppClassName());
}
}