[mlir][IR] Move the remaining builtin attributes to ODS.
authorRiver Riddle <riddleriver@gmail.com>
Tue, 16 Mar 2021 23:30:46 +0000 (16:30 -0700)
committerRiver Riddle <riddleriver@gmail.com>
Tue, 16 Mar 2021 23:31:53 +0000 (16:31 -0700)
With this revision, all builtin attributes and types will have been moved to the ODS generator.

Differential Revision: https://reviews.llvm.org/D98474

14 files changed:
mlir/include/mlir/IR/BuiltinAttributes.h
mlir/include/mlir/IR/BuiltinAttributes.td
mlir/include/mlir/IR/OpBase.td
mlir/lib/IR/AsmPrinter.cpp
mlir/lib/IR/AttributeDetail.h
mlir/lib/IR/BuiltinAttributes.cpp
mlir/lib/IR/MLIRContext.cpp
mlir/lib/Parser/AttributeParser.cpp
mlir/lib/TableGen/AttrOrTypeDef.cpp
mlir/test/CAPI/ir.c
mlir/test/IR/invalid.mlir
mlir/test/IR/pretty-attributes.mlir
mlir/test/mlir-tblgen/attrdefs.td
mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp

index 99bb2b6..ac98bfe 100644 (file)
 
 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;
-
-  /// 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);
+  using DenseElementsAttr::DenseElementsAttr;
 
-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;
-
-  /// 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);
+  using Attribute::Attribute;
+  using ValueType = bool;
 
-protected:
-  friend DenseElementsAttr;
+  static BoolAttr get(MLIRContext *context, bool value);
 
-  /// 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);
+  /// Enable conversion to IntegerAttr. This uses conversion vs. inheritance to
+  /// avoid bringing in all of IntegerAttrs methods.
+  operator IntegerAttr() const { return IntegerAttr(impl); }
 
-  /// 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);
+  /// Return the boolean value of this attribute.
+  bool getValue() const;
 
-  /// 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);
+  /// Methods for support type inquiry through isa, cast, and dyn_cast.
+  static bool classof(Attribute attr);
+};
 
-  /// 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);
+//===----------------------------------------------------------------------===//
+// FlatSymbolRefAttr
+//===----------------------------------------------------------------------===//
 
-  /// 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);
+/// 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;
-
-  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;
+//===----------------------------------------------------------------------===//
+// SparseElementsAttr
+//===----------------------------------------------------------------------===//
 
-  /// 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.
index 530ab0b..433c335 100644 (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 = ?;
 }
 
@@ -128,6 +129,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
 //===----------------------------------------------------------------------===//
 
@@ -221,6 +367,147 @@ def Builtin_DictionaryAttr : Builtin_Attr<"Dictionary"> {
 }
 
 //===----------------------------------------------------------------------===//
+// 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;
 }
 
 //===----------------------------------------------------------------------===//
index 819badc..844f768 100644 (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
index b6d327b..ad2c3c6 100644 (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>()) {
index 9499a0f..f62d886 100644 (file)
 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
 
index 5efb8f7..947ee14 100644 (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) {
-  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) {
+                                Type type, APFloat value) {
   // Verify that the type is correct.
-  if (failed(verifyFloatTypeInvariants(emitError, type)))
-    return failure();
+  if (!type.isa<FloatType>())
+    return emitError() << "expected floating point type";
 
   // 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
@@ -1022,15 +963,6 @@ DenseElementsAttr DenseElementsAttr::mapValues(
 }
 
 //===----------------------------------------------------------------------===//
-// 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");
index 464c1a7..ddc8804 100644 (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.
+  /// Unknown Location Attribute.
+  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
   /// 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>();
+  impl->falseAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, false);
+  impl->trueAttr = IntegerAttr::getBoolAttrUnchecked(impl->int1Ty, true);
   /// Unit Attribute.
   impl->unitAttr = AttributeUniquer::get<UnitAttr>(this);
-  /// Unknown Location Attribute.
-  impl->unknownLocAttr = AttributeUniquer::get<UnknownLoc>(this);
   /// The empty dictionary attribute.
   impl->emptyDictionaryAttr = DictionaryAttr::getEmptyUnchecked(this);
 
index 98f7417..f71f2a2 100644 (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.
index eea0301..1e4f5e4 100644 (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");
   }
 }
 
index b72a6e6..beb7310 100644 (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);
index 419c986..4c4df91 100644 (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>} : () -> ()
 
 // -----
 
index d4ac8e7..280e326 100644 (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>} : () -> ()
index 252b917..fc95fba 100644 (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"> {
index 636d4f8..a951df9 100644 (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();
-
-        SmallString<16> name = 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 = 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());
       }
     }