[Mlir-commits] [mlir] [mlir][IR] Generalize `DenseElementsAttr` to custom element types (PR #183920)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Feb 28 23:26:38 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-core
@llvm/pr-subscribers-mlir
Author: Matthias Springer (matthias-springer)
<details>
<summary>Changes</summary>
`DenseElementsAttr` supports only a hard-coded list of element types: `int`, `index`, `float`, `complex`. This commit generalizes the `DenseElementsAttr` infrastructure: it now supports arbitrary element types, as long as they implement the new `DenseElementTypeInterface`.
The `DenseElementTypeInterface` has the following helper functions:
- `getDenseElementBitSize`: Query the size of an element in bits. (When storing an element in memory, each element is padded to a full byte. This is an existing limitation of the `DenseElementsAttr`; with an exception for `i1`.)
- `convertToAttribute`: Attribute factory / deserializer. Converts bytes into an MLIR attribute. The attribute provides the assembly format / printer for a single element.
- `convertFromAttribute`: Serializer. Converts an MLIR attribute into bytes.
Note: `convertToAttribute` / `convertFromAttribute` are mainly for writing test cases. For performance reasons, `DenseElementsAttr` users should work with raw bytes / elements and avoid any API that materializes MLIR attributes. However, MLIR attributes typically have human-readable parsers/printers, making them suitable for lit tests and debugging.
This PR introduces an additional assembly format for `DenseElementsAttrs`. There are now two formats. (The existing one is kept for compatibility reasons.)
- Literal-first (existing): `dense<[1, 2, 3]> : tensor<3xi32>`
- Type-first (new): `dense<tensor<3xi32> : [1 : i32, 2 : i32, 3 : i32]>`
The new syntax is needed to disambiguate between "literal" (e.g., `1`) and attribute (e.g., `1 : i32`) when parsing the first token. In the literal-first syntax, we only parse literals. In the type-first syntax, we only parse attributes.
The existing `int`, `index`, `float`, `complex` types also implement the `DenseElementTypeInterface`. This allows us to implement `DenseElementsAttr::get` and `AttributeElementIterator::operator*` in a generic way.
RFC:
https://discourse.llvm.org/t/rfc-allow-custom-element-types-in-denseelementattr/89656
This is a re-upload of #<!-- -->179122.
---
Patch is 42.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/183920.diff
15 Files Affected:
- (modified) mlir/include/mlir/IR/BuiltinAttributes.td (+34-15)
- (modified) mlir/include/mlir/IR/BuiltinTypeInterfaces.h (+23)
- (modified) mlir/include/mlir/IR/BuiltinTypeInterfaces.td (+74-1)
- (modified) mlir/include/mlir/IR/BuiltinTypes.td (+11-3)
- (modified) mlir/include/mlir/Support/InterfaceSupport.h (+18-5)
- (modified) mlir/lib/AsmParser/AttributeParser.cpp (+124-1)
- (modified) mlir/lib/IR/AsmPrinter.cpp (+41-3)
- (modified) mlir/lib/IR/AttributeDetail.h (+4-6)
- (modified) mlir/lib/IR/BuiltinAttributes.cpp (+25-92)
- (modified) mlir/lib/IR/BuiltinTypeInterfaces.cpp (+34)
- (modified) mlir/lib/IR/BuiltinTypes.cpp (+87)
- (added) mlir/test/IR/dense-elements-type-interface.mlir (+83)
- (modified) mlir/test/lib/Dialect/Test/TestTypeDefs.td (+12)
- (modified) mlir/test/lib/Dialect/Test/TestTypes.cpp (+28)
- (modified) mlir/test/lib/Dialect/Test/TestTypes.h (+1)
``````````diff
diff --git a/mlir/include/mlir/IR/BuiltinAttributes.td b/mlir/include/mlir/IR/BuiltinAttributes.td
index 798d3c84f9618..dced379d1f979 100644
--- a/mlir/include/mlir/IR/BuiltinAttributes.td
+++ b/mlir/include/mlir/IR/BuiltinAttributes.td
@@ -239,29 +239,48 @@ def Builtin_DenseIntOrFPElementsAttr : Builtin_Attr<
"DenseElementsAttr"
> {
let summary = "An Attribute containing a dense multi-dimensional array of "
- "integer or floating-point values";
+ "values";
let description = [{
- Syntax:
-
- ```
- tensor-literal ::= integer-literal | float-literal | bool-literal | [] | [tensor-literal (, tensor-literal)* ]
- dense-intorfloat-elements-attribute ::= `dense` `<` tensor-literal `>` `:`
- ( 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`.
+ A dense elements attribute stores one or multiple elements of the same type.
+ The term "dense" refers to the fact that elements are not stored as
+ individual MLIR attributes, but in a raw buffer. The attribute provides a
+ covenience API to access elements in the form of MLIR attributes, but users
+ should avoid that API in performance-critical code and utilize APIs that
+ operate on raw bytes instead.
+
+ The number of elements is determined by the `type` shaped type. (Unranked
+ shaped types are not supported.) The element type of the shaped type must
+ implement the `DenseElementType` interface. This type interface defines the
+ bitwidth of an element and provides a serializer/deserializer to/from MLIR
+ attributes.
+
+ Storage format: Given an element bitwidth "w", element "i" starts at byte
+ offset "i * ceildiv(w, 8)". In other words, each element starts at a full
+ byte offset.
+
+ TODO: The name `DenseIntOrFPElements` is no longer accurate. The attribute
+ will be renamed in the future.
Examples:
```
- // A splat tensor of integer values.
+ // Literal-first syntax: A splat tensor of integer values.
dense<10> : tensor<2xi32>
- // A tensor of 2 float32 elements.
+
+ // Literal-first syntax: A tensor of 2 float32 elements.
dense<[10.0, 11.0]> : tensor<2xf32>
+
+ // Type-first syntax: A splat tensor of integer values.
+ dense<tensor<2xi32> : 10 : i32>
+
+ // Type-first syntax: A tensor of 2 float32 elements.
+ dense<tensor<2xf32> : [10.0, 11.0]>
```
+
+ Note: The literal-first syntax is supported only for complex, float, index,
+ int element types. The parser/print have special casing for these types.
+ Dense element attributes with other element types must use the type-first
+ syntax.
}];
let parameters = (ins AttributeSelfTypeParameter<"", "ShapedType">:$type,
"ArrayRef<char>":$rawData);
diff --git a/mlir/include/mlir/IR/BuiltinTypeInterfaces.h b/mlir/include/mlir/IR/BuiltinTypeInterfaces.h
index 5f14517d8dd71..9425d554b427c 100644
--- a/mlir/include/mlir/IR/BuiltinTypeInterfaces.h
+++ b/mlir/include/mlir/IR/BuiltinTypeInterfaces.h
@@ -19,6 +19,29 @@ struct fltSemantics;
namespace mlir {
class FloatType;
class MLIRContext;
+
+namespace detail {
+/// Float type implementation of
+/// DenseElementTypeInterface::getDenseElementBitSize.
+size_t getFloatTypeDenseElementBitSize(Type type);
+
+/// Float type implementation of DenseElementTypeInterface::convertToAttribute.
+Attribute convertFloatTypeToAttribute(Type type, llvm::ArrayRef<char> rawData);
+
+/// Float type implementation of
+/// DenseElementTypeInterface::convertFromAttribute.
+LogicalResult
+convertFloatTypeFromAttribute(Type type, Attribute attr,
+ llvm::SmallVectorImpl<char> &result);
+
+/// Read `bitWidth` bits from byte-aligned position in `rawData` and return as
+/// an APInt. Handles endianness correctly.
+llvm::APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth);
+
+/// Write `value` to byte-aligned position `bitPos` in `rawData`. Handles
+/// endianness correctly.
+void writeBits(char *rawData, size_t bitPos, llvm::APInt value);
+} // namespace detail
} // namespace mlir
#include "mlir/IR/BuiltinTypeInterfaces.h.inc"
diff --git a/mlir/include/mlir/IR/BuiltinTypeInterfaces.td b/mlir/include/mlir/IR/BuiltinTypeInterfaces.td
index 9ef08b7020b99..93c8c0694b467 100644
--- a/mlir/include/mlir/IR/BuiltinTypeInterfaces.td
+++ b/mlir/include/mlir/IR/BuiltinTypeInterfaces.td
@@ -41,12 +41,70 @@ def VectorElementTypeInterface : TypeInterface<"VectorElementTypeInterface"> {
}];
}
+//===----------------------------------------------------------------------===//
+// DenseElementTypeInterface
+//===----------------------------------------------------------------------===//
+
+def DenseElementTypeInterface : TypeInterface<"DenseElementType"> {
+ let cppNamespace = "::mlir";
+ let description = [{
+ This interface allows custom types to be used as element types in
+ DenseElementsAttr. Types implementing this interface define:
+
+ 1. The bit size for element storage.
+ 2. Helper methods for converting from/to Attribute. This assumes that there
+ is a corresponding attribute for each type that implements this
+ interface.
+
+ The helper methods for converting from/to Attribute are utilized when
+ parsing/printing IR or iterating over the elements via Attribute.
+ }];
+
+ let methods = [
+ InterfaceMethod<
+ /*desc=*/[{
+ Return the number of bits required to store one element in dense
+ storage.
+
+ Note: The DenseElementsAttr infrastructure will automatically align
+ every element to a full byte in storage. This limitation could be lifted
+ in the future to support dense packing of non-byte-sized elements.
+ }],
+ /*retTy=*/"size_t",
+ /*methodName=*/"getDenseElementBitSize",
+ /*args=*/(ins)
+ >,
+ InterfaceMethod<
+ /*desc=*/[{
+ Attribute deserialization / attribute factory: Convert raw storage bytes
+ into an MLIR attribute. The size of `rawData` is
+ "ceilDiv(getDenseElementBitSize(), 8)".
+ }],
+ /*retTy=*/"::mlir::Attribute",
+ /*methodName=*/"convertToAttribute",
+ /*args=*/(ins "::llvm::ArrayRef<char>":$rawData)
+ >,
+ InterfaceMethod<
+ /*desc=*/[{
+ Attribute serialization: Convert an MLIR attribute into raw bytes.
+ Implementations must append "getDenseElementBitSize() / 8" values to
+ `result`. Return "failure" if the attribute is incompatible with this
+ element type.
+ }],
+ /*retTy=*/"::llvm::LogicalResult",
+ /*methodName=*/"convertFromAttribute",
+ /*args=*/(ins "::mlir::Attribute":$attr,
+ "::llvm::SmallVectorImpl<char>&":$result)
+ >,
+ ];
+}
+
//===----------------------------------------------------------------------===//
// FloatTypeInterface
//===----------------------------------------------------------------------===//
def FloatTypeInterface : TypeInterface<"FloatType",
- [VectorElementTypeInterface]> {
+ [DenseElementTypeInterface, VectorElementTypeInterface]> {
let cppNamespace = "::mlir";
let description = [{
This type interface should be implemented by all floating-point types. It
@@ -83,6 +141,21 @@ def FloatTypeInterface : TypeInterface<"FloatType",
/// The width includes the integer bit.
unsigned getFPMantissaWidth();
}];
+
+ let extraTraitClassDeclaration = [{
+ /// DenseElementTypeInterface implementations for float types.
+ size_t getDenseElementBitSize() const {
+ return ::mlir::detail::getFloatTypeDenseElementBitSize($_type);
+ }
+ ::mlir::Attribute convertToAttribute(::llvm::ArrayRef<char> rawData) const {
+ return ::mlir::detail::convertFloatTypeToAttribute($_type, rawData);
+ }
+ ::llvm::LogicalResult
+ convertFromAttribute(::mlir::Attribute attr,
+ ::llvm::SmallVectorImpl<char> &result) const {
+ return ::mlir::detail::convertFloatTypeFromAttribute($_type, attr, result);
+ }
+ }];
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/IR/BuiltinTypes.td b/mlir/include/mlir/IR/BuiltinTypes.td
index 806064faeda00..e7d0a03a85e7d 100644
--- a/mlir/include/mlir/IR/BuiltinTypes.td
+++ b/mlir/include/mlir/IR/BuiltinTypes.td
@@ -45,7 +45,10 @@ def ValueSemantics : NativeTypeTrait<"ValueSemantics"> {
// ComplexType
//===----------------------------------------------------------------------===//
-def Builtin_Complex : Builtin_Type<"Complex", "complex"> {
+def Builtin_Complex : Builtin_Type<"Complex", "complex",
+ [DeclareTypeInterfaceMethods<DenseElementTypeInterface,
+ ["getDenseElementBitSize", "convertToAttribute", "convertFromAttribute"]>
+ ]> {
let summary = "Complex number with a parameterized element type";
let description = [{
Syntax:
@@ -560,7 +563,9 @@ def Builtin_Graph : Builtin_FunctionLike<"Graph", "graph">;
//===----------------------------------------------------------------------===//
def Builtin_Index : Builtin_Type<"Index", "index",
- [VectorElementTypeInterface]> {
+ [DeclareTypeInterfaceMethods<DenseElementTypeInterface,
+ ["getDenseElementBitSize", "convertToAttribute", "convertFromAttribute"]>,
+ VectorElementTypeInterface]> {
let summary = "Integer-like type with unknown platform-dependent bit width";
let description = [{
Syntax:
@@ -591,7 +596,10 @@ def Builtin_Index : Builtin_Type<"Index", "index",
//===----------------------------------------------------------------------===//
def Builtin_Integer : Builtin_Type<"Integer", "integer",
- [VectorElementTypeInterface, QuantStorageTypeInterface]> {
+ [VectorElementTypeInterface, QuantStorageTypeInterface,
+ DeclareTypeInterfaceMethods<DenseElementTypeInterface, [
+ "getDenseElementBitSize", "convertToAttribute",
+ "convertFromAttribute"]>]> {
let summary = "Integer type with arbitrary precision up to a fixed limit";
let description = [{
Syntax:
diff --git a/mlir/include/mlir/Support/InterfaceSupport.h b/mlir/include/mlir/Support/InterfaceSupport.h
index 20e2dfb453ef7..e24dd2676cfa3 100644
--- a/mlir/include/mlir/Support/InterfaceSupport.h
+++ b/mlir/include/mlir/Support/InterfaceSupport.h
@@ -192,12 +192,13 @@ class InterfaceMap {
template <typename... Types>
static InterfaceMap get() {
constexpr size_t numInterfaces = num_interface_types_t<Types...>::value;
- if constexpr (numInterfaces == 0)
+ if constexpr (numInterfaces == 0) {
return InterfaceMap();
-
- InterfaceMap map;
- (map.insertPotentialInterface<Types>(), ...);
- return map;
+ } else {
+ InterfaceMap map;
+ map.insertPotentialInterfaces<Types...>();
+ return map;
+ }
}
/// Returns an instance of the concept object for the given interface if it
@@ -217,6 +218,18 @@ class InterfaceMap {
}
private:
+ /// Insert the given interface types into the map (recursive expansion to
+ /// guarantee sequential, left-to-right evaluation across all compilers).
+ template <typename T>
+ void insertPotentialInterfaces() {
+ insertPotentialInterface<T>();
+ }
+ template <typename T, typename T2, typename... Rest>
+ void insertPotentialInterfaces() {
+ insertPotentialInterface<T>();
+ insertPotentialInterfaces<T2, Rest...>();
+ }
+
/// Insert the given interface type into the map, ignoring it if it doesn't
/// actually represent an interface.
template <typename T>
diff --git a/mlir/lib/AsmParser/AttributeParser.cpp b/mlir/lib/AsmParser/AttributeParser.cpp
index 5978a11d06bc9..dc9744a42b730 100644
--- a/mlir/lib/AsmParser/AttributeParser.cpp
+++ b/mlir/lib/AsmParser/AttributeParser.cpp
@@ -16,6 +16,7 @@
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinDialect.h"
+#include "mlir/IR/BuiltinTypeInterfaces.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/DialectResourceBlobManager.h"
#include "mlir/IR/IntegerSet.h"
@@ -953,6 +954,119 @@ Attribute Parser::parseDenseArrayAttr(Type attrType) {
return eltParser.getAttr();
}
+/// Try to parse a dense elements attribute with the type-first syntax.
+/// Syntax: dense<TYPE : [ATTR, ATTR, ...]>
+/// This syntax is used for types other than int, float, index and complex.
+///
+/// Returns:
+/// - "null" attribute if this is not the type-first syntax.
+/// - "failure" in case of a parse error.
+/// - A valid Attribute otherwise.
+static FailureOr<Attribute> parseDenseElementsAttrTyped(Parser &p, SMLoc loc) {
+ // Skip l_paren because "parseType" would try to parse it as a tuple/function
+ // type, but '(' starts a complex literal like in the literal-first syntax.
+ if (p.getToken().is(Token::l_paren))
+ return Attribute();
+
+ // Parse type and valdiate that it's a shaped type.
+ auto typeLoc = p.getToken().getLoc();
+ Type type;
+ OptionalParseResult typeResult = p.parseOptionalType(type);
+ if (!typeResult.has_value())
+ return Attribute(); // Not type-first syntax.
+ if (failed(*typeResult))
+ return failure(); // Type parse error.
+
+ auto shapedType = dyn_cast<ShapedType>(type);
+ if (!shapedType) {
+ p.emitError(typeLoc, "expected a shaped type for dense elements");
+ return failure();
+ }
+ if (!shapedType.hasStaticShape()) {
+ p.emitError(typeLoc, "dense elements type must have static shape");
+ return failure();
+ }
+
+ // Check that the element type implements DenseElementTypeInterface.
+ auto denseEltType = dyn_cast<DenseElementType>(shapedType.getElementType());
+ if (!denseEltType) {
+ p.emitError(typeLoc,
+ "element type must implement DenseElementTypeInterface "
+ "for type-first dense syntax");
+ return failure();
+ }
+
+ // Parse colon.
+ if (p.parseToken(Token::colon, "expected ':' after type in dense attribute"))
+ return failure();
+
+ // Parse the element attributes and convert to raw bytes.
+ SmallVector<char> rawData;
+
+ // Helper to parse a single element.
+ auto parseSingleElement = [&]() -> ParseResult {
+ Attribute elemAttr = p.parseAttribute();
+ if (!elemAttr)
+ return failure();
+ if (failed(denseEltType.convertFromAttribute(elemAttr, rawData))) {
+ p.emitError("incompatible attribute for element type");
+ return failure();
+ }
+ return success();
+ };
+
+ // Recursively parse elements matching the expected shape.
+ std::function<ParseResult(ArrayRef<int64_t>)> parseElements;
+ parseElements = [&](ArrayRef<int64_t> remainingShape) -> ParseResult {
+ // Leaf: parse a single element.
+ if (remainingShape.empty())
+ return parseSingleElement();
+
+ // Non-leaf: expect a list with the correct number of elements.
+ int64_t expectedCount = remainingShape.front();
+ ArrayRef<int64_t> innerShape = remainingShape.drop_front();
+ int64_t actualCount = 0;
+
+ auto parseOne = [&]() -> ParseResult {
+ if (parseElements(innerShape))
+ return failure();
+ ++actualCount;
+ return success();
+ };
+
+ if (p.parseCommaSeparatedList(Parser::Delimiter::Square, parseOne))
+ return failure();
+
+ if (actualCount != expectedCount) {
+ p.emitError() << "expected " << expectedCount
+ << " elements in dimension, got " << actualCount;
+ return failure();
+ }
+ return success();
+ };
+
+ // Parse elements.
+ if (!p.getToken().is(Token::l_square)) {
+ // Single element - parse as splat.
+ if (parseSingleElement())
+ return failure();
+ } else if (shapedType.getShape().empty()) {
+ // Scalar type shouldn't have a list.
+ p.emitError(loc, "expected single element for scalar type, got list");
+ return failure();
+ } else {
+ // Parse structured literal matching the shape.
+ if (parseElements(shapedType.getShape()))
+ return failure();
+ }
+
+ if (p.parseToken(Token::greater, "expected '>' to close dense attribute"))
+ return failure();
+
+ // Create the attribute from raw buffer.
+ return DenseElementsAttr::getFromRawBuffer(shapedType, rawData);
+}
+
/// Parse a dense elements attribute.
Attribute Parser::parseDenseElementsAttr(Type attrType) {
auto attribLoc = getToken().getLoc();
@@ -960,7 +1074,16 @@ Attribute Parser::parseDenseElementsAttr(Type attrType) {
if (parseToken(Token::less, "expected '<' after 'dense'"))
return nullptr;
- // Parse the literal data if necessary.
+ // Try to parse the type-first syntax: dense<TYPE : [ATTR, ...]>
+ FailureOr<Attribute> typedResult =
+ parseDenseElementsAttrTyped(*this, attribLoc);
+ if (failed(typedResult))
+ return nullptr;
+ if (*typedResult)
+ return *typedResult;
+
+ // Try to parse the literal-first syntax, which is the default format for
+ // int, float, index and complex element types.
TensorLiteralParser literalParser(*this);
if (!consumeIf(Token::greater)) {
if (literalParser.parse(/*allowHex=*/true) ||
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index 81455699421cc..b3242f838fc1d 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -507,11 +507,18 @@ class AsmPrinter::Impl {
/// Print a dense string elements attribute.
void printDenseStringElementsAttr(DenseStringElementsAttr attr);
- /// Print a dense elements attribute. If 'allowHex' is true, a hex string is
- /// used instead of individual elements when the elements attr is large.
+ /// Print a dense elements attribute in the literal-first syntax. If
+ /// 'allowHex' is true, a hex string is used instead of individual elements
+ /// when the elements attr is large.
void printDenseIntOrFPElementsAttr(DenseIntOrFPElementsAttr attr,
bool allowHex);
+ /// Print a dense elements attribute using the type-first syntax and the
+ /// DenseElementTypeInterface, which provides the attribute printer for each
+ /// element.
+ void printTypeFirstDenseElementsAttr(DenseElementsAttr attr,
+ DenseElementType denseEltType);
+
/// Print a dense array attribute.
void printDenseArrayAttr(DenseArrayAttr attr);
@@ -2507,7 +2514,17 @@ void AsmPrinter::Impl::printAttributeImpl(Attribute attr,
printElidedElementsAttr(os);
} else {
os << "dense<";
- printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
+ // Check if the element type implements DenseElementTypeInterface and is
+ // not a built-in type. Built-in types (int, float, index, complex) use
+ // the existing printing format for backwards compatibility.
+ Type eltType = intOrFpEltAttr.getElementType();
+ if (isa<FloatType, IntegerType, IndexType, ComplexType>(eltType)) {
+ printDenseIntOrFPElementsAttr(intOrFpEltAttr, /*allowHex=*/true);
+ } else {
+ printTypeFirstDenseElementsAttr(intOrFpEltAttr,
+ cast<DenseElementType>(eltType));
+ typeElision = AttrTypeElision::Must;
+ }
os << '>';
}
@@ -2705,6 +2722,27 @@ void AsmPrinter::Impl::printDenseStringElementsAttr(
printDenseElementsAttrImpl(attr.isSplat(), attr.getType(), os, printFn);
}
+void AsmPrinter::Impl::printTypeFirstDenseElementsAttr(
+ DenseElementsAttr attr, DenseElementType denseEltType) {
+ // Print the type first: dense<TYPE : [ELEMENTS]>
+ printType(attr.getType());
+ os << " : ";
+
+ ArrayRef<char> rawData = attr.getRawData();
+ // Storage is byte-aligned: align bit size up to next byte boundary.
+ size_t bitSize = denseEltType.getDenseElementBitSize();
+ size_t byteSize = llvm::divideCeil(bitSize, static_cast<size_t>(CHAR_BIT));
+
+ // Print elements: convert raw bytes to attribute, then print attribute.
+ printDenseElementsAttrImpl(
+ attr.isSplat(), attr.getType(), os, [&](unsigned index) {
+ size_t offset = attr.isSplat() ? 0 : index * byteSize;
+ ArrayRef<char> elemData = rawData.slice(offset, byteSize);
+ Attribute elemAttr = denseEltType.convertToAttribute(elemData);
+ printAttribut...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/183920
More information about the Mlir-commits
mailing list