[Mlir-commits] [mlir] [mlir][IR] Add builtin OCP INT8 element type (PR #230479)
Davide Grohmann
llvmlistbot at llvm.org
Mon Oct 12 04:43:31 PDT 2026
https://github.com/davidegrohmann updated https://github.com/llvm/llvm-project/pull/230479
>From 34c1681adc69567d1f059801c2e73d642e05006f Mon Sep 17 00:00:00 2001
From: Davide Grohmann <davide.grohmann at arm.com>
Date: Wed, 7 Oct 2026 16:08:05 +0200
Subject: [PATCH] [mlir][IR] Add builtin OCP INT8 element type
Add a builtin ocp_int8 type for the INT8 element of the OCP MXINT8
format. The type uses signed 8-bit storage with six fractional bits
and exposes the corresponding LLVM fixed-point semantics. The shared
E8M0 block scale is separate from this scalar type.
Add text and bytecode support, permit vector and tensor elements, and
encode dense elements through signless i8 attributes. Append the new
bytecode type code so existing codes retain their values.
Test text and bytecode round trips, raw storage endpoints, and the
fixed-point width, scale, and signedness.
See the Open Compute Project (OCP) MX specification:
https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf/
Change-Id: I5677b12fa372cbc1c5031373c9d32ddaf5c4efae
Signed-off-by: Davide Grohmann <davide.grohmann at arm.com>
---
.../include/mlir/IR/BuiltinDialectBytecode.td | 5 ++-
mlir/include/mlir/IR/BuiltinTypes.h | 2 ++
mlir/include/mlir/IR/BuiltinTypes.td | 25 +++++++++++++
mlir/include/mlir/IR/CommonTypeConstraints.td | 2 ++
mlir/lib/AsmParser/AttributeParser.cpp | 12 +++++++
mlir/lib/AsmParser/TokenKinds.def | 1 +
mlir/lib/AsmParser/TypeParser.cpp | 5 +++
mlir/lib/IR/AsmPrinter.cpp | 12 ++++++-
mlir/lib/IR/BuiltinAttributes.cpp | 4 +++
mlir/lib/IR/BuiltinTypes.cpp | 29 ++++++++++++++-
mlir/test/Dialect/Builtin/Bytecode/attrs.mlir | 6 +++-
mlir/test/Dialect/Builtin/Bytecode/types.mlir | 14 ++++++++
mlir/test/IR/attribute.mlir | 15 ++++++++
mlir/test/IR/invalid-builtin-attributes.mlir | 35 +++++++++++++++++++
mlir/test/IR/invalid-builtin-types.mlir | 4 +++
mlir/test/IR/parser.mlir | 10 ++++++
mlir/unittests/IR/AttributeTest.cpp | 19 ++++++++++
mlir/unittests/IR/TypeTest.cpp | 20 +++++++++++
18 files changed, 216 insertions(+), 4 deletions(-)
diff --git a/mlir/include/mlir/IR/BuiltinDialectBytecode.td b/mlir/include/mlir/IR/BuiltinDialectBytecode.td
index d098793989dc4..67677344dd960 100644
--- a/mlir/include/mlir/IR/BuiltinDialectBytecode.td
+++ b/mlir/include/mlir/IR/BuiltinDialectBytecode.td
@@ -318,6 +318,8 @@ def Float6E3M2FNType : EnableFloatPrintingJune2026<(type)>;
def Float8E8M0FNUType : EnableFloatPrintingJune2026<(type)>;
+def OCPInt8Type : EnableFloatPrintingJune2026<(type)>;
+
def ComplexType : DialectType<(type
Type:$elementType
)>;
@@ -469,7 +471,8 @@ def BuiltinDialectTypes : DialectTypes<"Builtin"> {
Float6E3M2FNType,
Float8E8M0FNUType,
TokenType,
- GraphType
+ GraphType,
+ OCPInt8Type
];
}
diff --git a/mlir/include/mlir/IR/BuiltinTypes.h b/mlir/include/mlir/IR/BuiltinTypes.h
index d30cba29c9814..e20b7a590ac37 100644
--- a/mlir/include/mlir/IR/BuiltinTypes.h
+++ b/mlir/include/mlir/IR/BuiltinTypes.h
@@ -15,6 +15,8 @@
namespace llvm {
class BitVector;
+// Used by the generated OCPInt8Type declaration in BuiltinTypes.h.inc.
+class FixedPointSemantics;
struct fltSemantics;
} // namespace llvm
diff --git a/mlir/include/mlir/IR/BuiltinTypes.td b/mlir/include/mlir/IR/BuiltinTypes.td
index ffb0e542153ee..23cb366581b48 100644
--- a/mlir/include/mlir/IR/BuiltinTypes.td
+++ b/mlir/include/mlir/IR/BuiltinTypes.td
@@ -453,6 +453,31 @@ def Builtin_Float8E5M3FNU : Builtin_FloatType<"Float8E5M3FNU", "f8E5M3FNU"> {
}];
}
+//===----------------------------------------------------------------------===//
+// OCPInt8Type
+//===----------------------------------------------------------------------===//
+
+def Builtin_OCPInt8 : Builtin_Type<"OCPInt8", "ocp_int8",
+ [VectorElementTypeInterface,
+ DeclareTypeInterfaceMethods<DenseElementTypeInterface, [
+ "getDenseElementBitSize", "convertToAttribute",
+ "convertFromAttribute"]>]> {
+ let summary = "OCP INT8 element type";
+ let description = [{
+ The INT8 element type of the OCP MXINT8 block format. It is an 8-bit signed
+ two's-complement type with six fractional bits. Its values are multiples of
+ 1/64 in the range [-2, 127/64]. The shared E8M0 scale is not part of this
+ type.
+
+ Open Compute Project (OCP) microscaling formats (MX) specification,
+ Section 5.3.4 (INT8):
+ https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
+ }];
+ let extraClassDeclaration = [{
+ static llvm::FixedPointSemantics getFixedPointSemantics();
+ }];
+}
+
//===----------------------------------------------------------------------===//
// BFloat16Type
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/IR/CommonTypeConstraints.td b/mlir/include/mlir/IR/CommonTypeConstraints.td
index 8dbd7ac4b9760..f65b010e90c8c 100644
--- a/mlir/include/mlir/IR/CommonTypeConstraints.td
+++ b/mlir/include/mlir/IR/CommonTypeConstraints.td
@@ -379,6 +379,8 @@ def F8E8M0FNU : Type<CPred<"::llvm::isa<::mlir::Float8E8M0FNUType>($_self)">, "f
BuildableType<"$_builder.getType<Float8E8M0FNUType>()">;
def F8E5M3FNU : Type<CPred<"::llvm::isa<::mlir::Float8E5M3FNUType>($_self)">, "f8E5M3FNU type">,
BuildableType<"$_builder.getType<Float8E5M3FNUType>()">;
+def OCPInt8 : Type<CPred<"::llvm::isa<::mlir::OCPInt8Type>($_self)">, "ocp_int8 type">,
+ BuildableType<"$_builder.getType<OCPInt8Type>()">;
def AnyComplex : Type<CPred<"::llvm::isa<::mlir::ComplexType>($_self)">,
"complex-type", "::mlir::ComplexType">;
diff --git a/mlir/lib/AsmParser/AttributeParser.cpp b/mlir/lib/AsmParser/AttributeParser.cpp
index 7459d8e0c3625..51f607a90a1e8 100644
--- a/mlir/lib/AsmParser/AttributeParser.cpp
+++ b/mlir/lib/AsmParser/AttributeParser.cpp
@@ -604,6 +604,18 @@ DenseElementsAttr TensorLiteralParser::getAttr(SMLoc loc, ShapedType type) {
}
return DenseElementsAttr::get(type, intValues);
}
+ // OCP INT8 stores encoded values as signless i8 attributes.
+ if (isa<OCPInt8Type>(eltType)) {
+ std::vector<APInt> intValues;
+ Type storageType = IntegerType::get(p.getContext(), 8);
+ if (failed(getIntAttrElements(loc, storageType, intValues)))
+ return nullptr;
+ SmallVector<Attribute> attrs;
+ attrs.reserve(intValues.size());
+ for (const APInt &value : intValues)
+ attrs.push_back(IntegerAttr::get(storageType, value));
+ return DenseElementsAttr::get(type, attrs);
+ }
// Handle floating point types.
if (FloatType floatTy = dyn_cast<FloatType>(eltType)) {
std::vector<APFloat> floatValues;
diff --git a/mlir/lib/AsmParser/TokenKinds.def b/mlir/lib/AsmParser/TokenKinds.def
index e9a883bdee92d..6a9191e3cd163 100644
--- a/mlir/lib/AsmParser/TokenKinds.def
+++ b/mlir/lib/AsmParser/TokenKinds.def
@@ -118,6 +118,7 @@ TOK_KEYWORD(max)
TOK_KEYWORD(memref)
TOK_KEYWORD(min)
TOK_KEYWORD(mod)
+TOK_KEYWORD(ocp_int8)
TOK_KEYWORD(none)
TOK_KEYWORD(offset)
TOK_KEYWORD(size)
diff --git a/mlir/lib/AsmParser/TypeParser.cpp b/mlir/lib/AsmParser/TypeParser.cpp
index 0617e73317184..c4775b69e842e 100644
--- a/mlir/lib/AsmParser/TypeParser.cpp
+++ b/mlir/lib/AsmParser/TypeParser.cpp
@@ -58,6 +58,7 @@ OptionalParseResult Parser::parseOptionalType(Type &type) {
case Token::kw_f80:
case Token::kw_f128:
case Token::kw_index:
+ case Token::kw_ocp_int8:
case Token::kw_none:
case Token::kw_token:
case Token::exclamation_identifier:
@@ -371,6 +372,10 @@ Type Parser::parseNonFunctionType() {
consumeToken(Token::kw_index);
return builder.getIndexType();
+ case Token::kw_ocp_int8:
+ consumeToken(Token::kw_ocp_int8);
+ return builder.getType<OCPInt8Type>();
+
// none-type
case Token::kw_none:
consumeToken(Token::kw_none);
diff --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index f78d33338904b..a20c4059a848d 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -2676,7 +2676,10 @@ void AsmPrinter::Impl::printDenseTypedElementsAttr(DenseTypedElementsAttr attr,
auto elementType = type.getElementType();
// Check to see if we should format this attribute as a hex string.
- if (allowHex && printerFlags.shouldPrintElementsAttrWithHex(attr)) {
+ if (allowHex &&
+ (elementType.isIntOrIndexOrFloat() ||
+ llvm::isa<ComplexType>(elementType)) &&
+ printerFlags.shouldPrintElementsAttrWithHex(attr)) {
ArrayRef<char> rawData = attr.getRawData();
if (llvm::endianness::native == llvm::endianness::big) {
// Convert endianess in big-endian(BE) machines. `rawData` is BE in BE
@@ -2724,6 +2727,12 @@ void AsmPrinter::Impl::printDenseTypedElementsAttr(DenseTypedElementsAttr attr,
printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
printDenseIntElement(*(valueIt + index), os, elementType);
});
+ } else if (llvm::isa<OCPInt8Type>(elementType)) {
+ auto valueIt = attr.value_begin<Attribute>();
+ printDenseElementsAttrImpl(attr.isSplat(), type, os, [&](unsigned index) {
+ auto value = llvm::cast<IntegerAttr>(*(valueIt + index));
+ printDenseIntElement(value.getValue(), os, value.getType());
+ });
} else {
assert(llvm::isa<FloatType>(elementType) && "unexpected element type");
auto valueIt = attr.value_begin<APFloat>();
@@ -2824,6 +2833,7 @@ void AsmPrinter::Impl::printTypeImpl(Type type) {
.Case<Float64Type>([&](Type) { os << "f64"; })
.Case<Float80Type>([&](Type) { os << "f80"; })
.Case<Float128Type>([&](Type) { os << "f128"; })
+ .Case<OCPInt8Type>([&](Type) { os << "ocp_int8"; })
.Case([&](IntegerType integerTy) {
if (integerTy.isSigned())
os << 's';
diff --git a/mlir/lib/IR/BuiltinAttributes.cpp b/mlir/lib/IR/BuiltinAttributes.cpp
index 876f5f878fdea..6cb849c98dadf 100644
--- a/mlir/lib/IR/BuiltinAttributes.cpp
+++ b/mlir/lib/IR/BuiltinAttributes.cpp
@@ -1561,6 +1561,10 @@ Attribute SparseElementsAttr::getZeroAttr() const {
if (llvm::isa<DenseStringElementsAttr>(getValues()))
return StringAttr::get("", eltType);
+ // OCP INT8 elements use signless i8 attributes for their encoded bits.
+ if (llvm::isa<OCPInt8Type>(eltType))
+ return IntegerAttr::get(IntegerType::get(eltType.getContext(), 8), 0);
+
// Otherwise, this is an integer.
return IntegerAttr::get(eltType, 0);
}
diff --git a/mlir/lib/IR/BuiltinTypes.cpp b/mlir/lib/IR/BuiltinTypes.cpp
index 845143f863d94..7903b4c7b05f8 100644
--- a/mlir/lib/IR/BuiltinTypes.cpp
+++ b/mlir/lib/IR/BuiltinTypes.cpp
@@ -18,6 +18,7 @@
#include "mlir/IR/Dialect.h"
#include "mlir/IR/TensorEncoding.h"
#include "mlir/IR/TypeUtilities.h"
+#include "llvm/ADT/APFixedPoint.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Sequence.h"
@@ -149,6 +150,32 @@ IntegerType::convertFromAttribute(Attribute attr,
return success();
}
+//===----------------------------------------------------------------------===//
+// OCPInt8 Type
+//===----------------------------------------------------------------------===//
+
+llvm::FixedPointSemantics OCPInt8Type::getFixedPointSemantics() {
+ // Saturation is selected by a conversion operation, not by the value type.
+ return {/*Width=*/8, /*Scale=*/6, /*IsSigned=*/true,
+ /*IsSaturated=*/false, /*HasUnsignedPadding=*/false};
+}
+
+size_t OCPInt8Type::getDenseElementBitSize() const { return 8; }
+
+Attribute OCPInt8Type::convertToAttribute(ArrayRef<char> rawData) const {
+ return IntegerType::get(getContext(), 8).convertToAttribute(rawData);
+}
+
+LogicalResult
+OCPInt8Type::convertFromAttribute(Attribute attr,
+ SmallVectorImpl<char> &result) const {
+ auto intAttr = dyn_cast<IntegerAttr>(attr);
+ if (!intAttr || !intAttr.getType().isSignlessInteger(8))
+ return failure();
+ return cast<IntegerType>(intAttr.getType())
+ .convertFromAttribute(attr, result);
+}
+
//===----------------------------------------------------------------------===//
// Index Type
//===----------------------------------------------------------------------===//
@@ -437,7 +464,7 @@ bool TensorType::isValidElementType(Type type) {
// types. Dialects are expected to verify that tensor types have a valid
// element type within that dialect.
return llvm::isa<ComplexType, FloatType, IntegerType, OpaqueType, VectorType,
- IndexType>(type) ||
+ IndexType, OCPInt8Type>(type) ||
!llvm::isa<BuiltinDialect>(type.getDialect());
}
diff --git a/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir b/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir
index ee59abc14f1cd..438f0b3c4fb50 100644
--- a/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir
+++ b/mlir/test/Dialect/Builtin/Bytecode/attrs.mlir
@@ -36,6 +36,7 @@ module @TestDenseArray attributes {
// CHECK-DAG: bytecode.i64 = dense<1000000> : tensor<4xi64>
// CHECK-DAG: bytecode.f16 = dense<[1.500000e+00, 2.500000e+00]> : tensor<2xf16>
// CHECK-DAG: bytecode.bf16 = dense<[-5.000000e-01, 5.000000e-01]> : tensor<2xbf16>
+// CHECK-DAG: bytecode.ocp_int8 = dense<tensor<4xocp_int8> : [-128 : i8, -1 : i8, 0 : i8, 127 : i8]>
// CHECK-DAG: bytecode.complex_val = dense<(1.000000e+00,2.000000e+00)> : tensor<1xcomplex<f32>>
module @TestDenseTypedElements attributes {
bytecode.test1 = dense<true> : tensor<256xi1>,
@@ -45,6 +46,7 @@ module @TestDenseTypedElements attributes {
bytecode.i64 = dense<1000000> : tensor<4xi64>,
bytecode.f16 = dense<[1.5, 2.5]> : tensor<2xf16>,
bytecode.bf16 = dense<[-0.5, 0.5]> : tensor<2xbf16>,
+ bytecode.ocp_int8 = dense<tensor<4xocp_int8> : [-128 : i8, -1 : i8, 0 : i8, 127 : i8]>,
bytecode.complex_val = dense<(1.0, 2.0)> : tensor<1xcomplex<f32>>
} {}
@@ -144,8 +146,10 @@ module @TestInt attributes {
module @TestSparseElements attributes {
// CHECK-LITERAL: bytecode.sparse = sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>
// CHECK-LITERAL: bytecode.sparse_1d = sparse<[1, 3], [10.0, 20.0]> : tensor<5xf32>
+ // CHECK-LITERAL: bytecode.sparse_ocp_int8 = sparse<[[0, 0], [1, 1]], [-128, 127]> : tensor<2x2xocp_int8>
bytecode.sparse = sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>,
- bytecode.sparse_1d = sparse<[1, 3], [10.0, 20.0]> : tensor<5xf32>
+ bytecode.sparse_1d = sparse<[1, 3], [10.0, 20.0]> : tensor<5xf32>,
+ bytecode.sparse_ocp_int8 = sparse<[[0, 0], [1, 1]], [-128, 127]> : tensor<2x2xocp_int8>
} {}
diff --git a/mlir/test/Dialect/Builtin/Bytecode/types.mlir b/mlir/test/Dialect/Builtin/Bytecode/types.mlir
index e1d4a18a33c73..adf1d3c767a7e 100644
--- a/mlir/test/Dialect/Builtin/Bytecode/types.mlir
+++ b/mlir/test/Dialect/Builtin/Bytecode/types.mlir
@@ -54,6 +54,20 @@ module @TestFloat attributes {
bytecode.test17 = tf32
} {}
+//===----------------------------------------------------------------------===//
+// OCPInt8Type
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @TestOCPInt8
+module @TestOCPInt8 attributes {
+ // CHECK: bytecode.scalar = ocp_int8,
+ // CHECK: bytecode.tensor = tensor<4xocp_int8>,
+ // CHECK: bytecode.vector = vector<2xocp_int8>
+ bytecode.scalar = ocp_int8,
+ bytecode.tensor = tensor<4xocp_int8>,
+ bytecode.vector = vector<2xocp_int8>
+} {}
+
//===----------------------------------------------------------------------===//
// IntegerType
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/IR/attribute.mlir b/mlir/test/IR/attribute.mlir
index ea378439c0f3b..c507032908ec1 100644
--- a/mlir/test/IR/attribute.mlir
+++ b/mlir/test/IR/attribute.mlir
@@ -596,6 +596,21 @@ func.func @tf32_elements_attr() {
// -----
+// Test OCP INT8 dense elements at both storage endpoints and around zero.
+
+// CHECK-LABEL: func @ocp_int8_elements_attr
+func.func @ocp_int8_elements_attr() {
+ // CHECK: "foo"() {attr = dense<tensor<4xocp_int8> : [-128 : i8, -1 : i8, 0 : i8, 127 : i8]>} : () -> ()
+ "foo"() {attr = dense<tensor<4xocp_int8> : [-128 : i8, -1 : i8, 0 : i8, 127 : i8]>} : () -> ()
+ // CHECK: "foo"() {attr = dense<tensor<3xocp_int8> : 64 : i8>} : () -> ()
+ "foo"() {attr = dense<tensor<3xocp_int8> : 64 : i8>} : () -> ()
+ // CHECK: "foo"() {attr = dense<vector<2xocp_int8> : [-128 : i8, 127 : i8]>} : () -> ()
+ "foo"() {attr = dense<vector<2xocp_int8> : [-128 : i8, 127 : i8]>} : () -> ()
+ return
+}
+
+// -----
+
//===----------------------------------------------------------------------===//
// Test StringElementsAttr
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/IR/invalid-builtin-attributes.mlir b/mlir/test/IR/invalid-builtin-attributes.mlir
index 1989ce663cbb2..d58a99bab5b91 100644
--- a/mlir/test/IR/invalid-builtin-attributes.mlir
+++ b/mlir/test/IR/invalid-builtin-attributes.mlir
@@ -1,5 +1,40 @@
// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -verify-diagnostics
+func.func @ocp_int8_dense_wrong_width() -> () {
+ // expected-error @+1 {{incompatible attribute for element type}}
+ "foo"(){bar = dense<tensor<1xocp_int8> : [1 : i16]>} : () -> ()
+}
+
+// -----
+
+func.func @ocp_int8_dense_signed_storage() -> () {
+ // expected-error @+1 {{incompatible attribute for element type}}
+ "foo"(){bar = dense<tensor<1xocp_int8> : [1 : si8]>} : () -> ()
+}
+
+// -----
+
+func.func @ocp_int8_dense_float_storage() -> () {
+ // expected-error @+1 {{incompatible attribute for element type}}
+ "foo"(){bar = dense<tensor<1xocp_int8> : [1.0 : f32]>} : () -> ()
+}
+
+// -----
+
+func.func @ocp_int8_sparse_out_of_range() -> () {
+ // expected-error @+1 {{integer constant out of range for type}}
+ "foo"(){bar = sparse<0, 256> : tensor<1xocp_int8>} : () -> ()
+}
+
+// -----
+
+func.func @ocp_int8_sparse_float_value() -> () {
+ // expected-error @+1 {{expected integer elements, but parsed floating-point}}
+ "foo"(){bar = sparse<0, 1.0> : tensor<1xocp_int8>} : () -> ()
+}
+
+// -----
+
func.func @elementsattr_non_tensor_type() -> () {
"foo"(){bar = dense<[4]> : i32} : () -> () // expected-error {{elements literal must be a shaped type}}
}
diff --git a/mlir/test/IR/invalid-builtin-types.mlir b/mlir/test/IR/invalid-builtin-types.mlir
index 8207b183e4a5d..abf4c517a3a1d 100644
--- a/mlir/test/IR/invalid-builtin-types.mlir
+++ b/mlir/test/IR/invalid-builtin-types.mlir
@@ -23,6 +23,10 @@ func.func @illegalmemrefelementtype(memref<?xtensor<i8>>) -> () // expected-erro
// -----
+func.func @ocp_int8_memref_element(memref<4xocp_int8>) -> () // expected-error {{invalid memref element type}}
+
+// -----
+
func.func @illegalunrankedmemrefelementtype(memref<*xtensor<i8>>) -> () // expected-error {{invalid memref element type}}
// -----
diff --git a/mlir/test/IR/parser.mlir b/mlir/test/IR/parser.mlir
index f3f63786199ec..12fdcb16bda41 100644
--- a/mlir/test/IR/parser.mlir
+++ b/mlir/test/IR/parser.mlir
@@ -2,6 +2,7 @@
// RUN: mlir-opt -allow-unregistered-dialect %s | mlir-opt -allow-unregistered-dialect | FileCheck %s
// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-op-generic %s | FileCheck %s -check-prefix GENERIC
// RUN: mlir-opt -allow-unregistered-dialect %s | mlir-opt -allow-unregistered-dialect -mlir-print-op-generic | FileCheck %s -check-prefix GENERIC
+// RUN: mlir-opt -allow-unregistered-dialect -mlir-print-elementsattrs-with-hex-if-larger=0 %s | mlir-opt -allow-unregistered-dialect | FileCheck %s -check-prefix OCP-HEX
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0, d1, d2, d3, d4)[s0] -> (d0, d1, d2, d4, d3)>
#map = affine_map<(d0, d1, d2, d3, d4)[s0] -> (d0, d1, d2, d4, d3)>
@@ -798,6 +799,13 @@ func.func @sparsetensorattr() -> () {
"fooi32"(){bar = sparse<> : tensor<1x1xi32>} : () -> ()
// CHECK: "fooi64"() {bar = sparse<0, -1> : tensor<1xi64>} : () -> ()
"fooi64"(){bar = sparse<[0], [-1]> : tensor<1xi64>} : () -> ()
+// CHECK: "fooocp_int"() {bar = sparse<{{\[\[}}0, 0], [1, 1]], {{\[}}-128, 127]> : tensor<2x2xocp_int8>} : () -> ()
+// OCP-HEX: "fooocp_int"() {bar = sparse<{{\[\[}}0, 0], [1, 1]], {{\[}}-128, 127]> : tensor<2x2xocp_int8>} : () -> ()
+ "fooocp_int"(){bar = sparse<[[0, 0], [1, 1]], [-128, 127]> : tensor<2x2xocp_int8>} : () -> ()
+// CHECK: "fooocp_int_splat"() {bar = sparse<0, -2> : tensor<1x1xocp_int8>} : () -> ()
+ "fooocp_int_splat"(){bar = sparse<0, -2> : tensor<1x1xocp_int8>} : () -> ()
+// CHECK: "fooocp_int_empty"() {bar = sparse<> : tensor<2x2xocp_int8>} : () -> ()
+ "fooocp_int_empty"(){bar = sparse<> : tensor<2x2xocp_int8>} : () -> ()
// CHECK: "foo2"() {bar = sparse<> : tensor<0xi32>} : () -> ()
"foo2"(){bar = sparse<> : tensor<0xi32>} : () -> ()
// CHECK: "foo3"() {bar = sparse<> : tensor<i32>} : () -> ()
@@ -835,6 +843,8 @@ func.func @sparsevectorattr() -> () {
"fooi32"(){bar = sparse<> : vector<1x1xi32>} : () -> ()
// CHECK: "fooi64"() {bar = sparse<0, -1> : vector<1xi64>} : () -> ()
"fooi64"(){bar = sparse<[[0]], [-1]> : vector<1xi64>} : () -> ()
+// CHECK: "fooocp_int"() {bar = sparse<0, 127> : vector<1xocp_int8>} : () -> ()
+ "fooocp_int"(){bar = sparse<0, 127> : vector<1xocp_int8>} : () -> ()
// CHECK: "foof16"() {bar = sparse<0, -2.000000e+00> : vector<1x1x1xf16>} : () -> ()
"foof16"(){bar = sparse<0, -2.0> : vector<1x1x1xf16>} : () -> ()
diff --git a/mlir/unittests/IR/AttributeTest.cpp b/mlir/unittests/IR/AttributeTest.cpp
index 5db6a0c636aa3..46092af37219d 100644
--- a/mlir/unittests/IR/AttributeTest.cpp
+++ b/mlir/unittests/IR/AttributeTest.cpp
@@ -407,10 +407,12 @@ TEST(SparseElementsAttrTest, GetZero) {
IntegerType intTy = IntegerType::get(&context, 32);
FloatType floatTy = Float32Type::get(&context);
+ Type ocpInt8Ty = OCPInt8Type::get(&context);
Type stringTy = OpaqueType::get(StringAttr::get(&context, "test"), "string");
ShapedType tensorI32 = RankedTensorType::get({2, 2}, intTy);
ShapedType tensorF32 = RankedTensorType::get({2, 2}, floatTy);
+ ShapedType tensorOCPInt8 = RankedTensorType::get({2, 2}, ocpInt8Ty);
ShapedType tensorString = RankedTensorType::get({2, 2}, stringTy);
auto indicesType =
@@ -424,11 +426,19 @@ TEST(SparseElementsAttrTest, GetZero) {
RankedTensorType floatValueTy = RankedTensorType::get({1}, floatTy);
auto floatValue = DenseFPElementsAttr::get(floatValueTy, {1.0f});
+ RankedTensorType ocpInt8ValueTy = RankedTensorType::get({1}, ocpInt8Ty);
+ Attribute ocpInt8EncodedValue =
+ IntegerAttr::get(IntegerType::get(&context, 8), 64);
+ auto ocpInt8Value = DenseElementsAttr::get(
+ ocpInt8ValueTy, ArrayRef<Attribute>(ocpInt8EncodedValue));
+
RankedTensorType stringValueTy = RankedTensorType::get({1}, stringTy);
auto stringValue = DenseElementsAttr::get(stringValueTy, {StringRef("foo")});
auto sparseInt = SparseElementsAttr::get(tensorI32, indices, intValue);
auto sparseFloat = SparseElementsAttr::get(tensorF32, indices, floatValue);
+ auto sparseOCPInt8 =
+ SparseElementsAttr::get(tensorOCPInt8, indices, ocpInt8Value);
auto sparseString =
SparseElementsAttr::get(tensorString, indices, stringValue);
@@ -444,6 +454,15 @@ TEST(SparseElementsAttrTest, GetZero) {
EXPECT_EQ(zeroFloatValue.getValueAsDouble(), 0.0f);
EXPECT_TRUE(zeroFloatValue.getType() == floatTy);
+ auto zeroOCPInt8Value =
+ cast<IntegerAttr>(sparseOCPInt8.getValues<Attribute>()[{1, 1}]);
+ EXPECT_EQ(zeroOCPInt8Value.getInt(), 0);
+ EXPECT_TRUE(zeroOCPInt8Value.getType().isSignlessInteger(8));
+ auto storedOCPInt8Value =
+ cast<IntegerAttr>(sparseOCPInt8.getValues<Attribute>()[{0, 0}]);
+ EXPECT_EQ(storedOCPInt8Value.getInt(), 64);
+ EXPECT_TRUE(storedOCPInt8Value.getType().isSignlessInteger(8));
+
auto zeroStringValue =
cast<StringAttr>(sparseString.getValues<Attribute>()[{1, 1}]);
EXPECT_TRUE(zeroStringValue.empty());
diff --git a/mlir/unittests/IR/TypeTest.cpp b/mlir/unittests/IR/TypeTest.cpp
index 30f6642a9ca71..77bb51600196a 100644
--- a/mlir/unittests/IR/TypeTest.cpp
+++ b/mlir/unittests/IR/TypeTest.cpp
@@ -10,6 +10,8 @@
#include "mlir/IR/Dialect.h"
#include "mlir/IR/Types.h"
#include "mlir/IR/Value.h"
+#include "llvm/ADT/APFixedPoint.h"
+#include "llvm/ADT/APFloat.h"
#include "gtest/gtest.h"
using namespace mlir;
@@ -69,3 +71,21 @@ TEST(Type, Casting) {
EXPECT_EQ(8u, cast<IntegerType>(intTy).getWidth());
}
+
+TEST(Type, OCPInt8FixedPointSemantics) {
+ llvm::FixedPointSemantics semantics = OCPInt8Type::getFixedPointSemantics();
+ EXPECT_EQ(8u, semantics.getWidth());
+ EXPECT_EQ(6u, semantics.getScale());
+ EXPECT_TRUE(semantics.isSigned());
+ EXPECT_FALSE(semantics.isSaturated());
+ EXPECT_FALSE(semantics.hasUnsignedPadding());
+
+ auto asDouble = [&](uint8_t bits) {
+ return llvm::APFixedPoint(llvm::APInt(8, bits), semantics)
+ .convertToFloat(llvm::APFloat::IEEEdouble())
+ .convertToDouble();
+ };
+ EXPECT_DOUBLE_EQ(-2.0, asDouble(0x80));
+ EXPECT_DOUBLE_EQ(1.0 / 64.0, asDouble(0x01));
+ EXPECT_DOUBLE_EQ(127.0 / 64.0, asDouble(0x7f));
+}
More information about the Mlir-commits
mailing list