Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MLIR] Add f6E3M2FN type #105573

Merged
merged 2 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions llvm/unittests/ADT/APFloatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2084,16 +2084,17 @@ TEST(APFloatTest, getSmallestNormalized) {
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
EXPECT_TRUE(test.isSmallestNormalized());

test = APFloat::getSmallestNormalized(APFloat::Float6E3M2FN(), false);
expected = APFloat(APFloat::Float6E3M2FN(), "0x1p-2");

test = APFloat::getSmallestNormalized(APFloat::Float4E2M1FN(), false);
expected = APFloat(APFloat::Float4E2M1FN(), "0x1p0");
EXPECT_FALSE(test.isNegative());
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
EXPECT_TRUE(test.isSmallestNormalized());

test = APFloat::getSmallestNormalized(APFloat::Float4E2M1FN(), false);
expected = APFloat(APFloat::Float4E2M1FN(), "0x1p0");
EXPECT_FALSE(test.isNegative());
durga4github marked this conversation as resolved.
Show resolved Hide resolved
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
Expand Down
10 changes: 10 additions & 0 deletions mlir/include/mlir-c/BuiltinTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ MLIR_CAPI_EXPORTED bool mlirTypeIsAFloat(MlirType type);
/// Returns the bitwidth of a floating-point type.
MLIR_CAPI_EXPORTED unsigned mlirFloatTypeGetWidth(MlirType type);

/// Returns the typeID of an Float6E3M2FN type.
MLIR_CAPI_EXPORTED MlirTypeID mlirFloat6E3M2FNTypeGetTypeID(void);

/// Checks whether the given type is an f6E3M2FN type.
MLIR_CAPI_EXPORTED bool mlirTypeIsAFloat6E3M2FN(MlirType type);

/// Creates an f6E3M2FN type in the given context. The type is owned by the
/// context.
MLIR_CAPI_EXPORTED MlirType mlirFloat6E3M2FNTypeGet(MlirContext ctx);

/// Returns the typeID of an Float8E5M2 type.
MLIR_CAPI_EXPORTED MlirTypeID mlirFloat8E5M2TypeGetTypeID(void);

Expand Down
1 change: 1 addition & 0 deletions mlir/include/mlir/IR/Builders.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Builder {
Attribute metadata = Attribute());

// Types.
FloatType getFloat6E3M2FNType();
FloatType getFloat8E5M2Type();
FloatType getFloat8E4M3Type();
FloatType getFloat8E4M3FNType();
Expand Down
9 changes: 7 additions & 2 deletions mlir/include/mlir/IR/BuiltinTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class FloatType : public Type {
static FloatType getFloat8E4M3FNUZ(MLIRContext *ctx);
static FloatType getFloat8E4M3B11FNUZ(MLIRContext *ctx);
static FloatType getFloat8E3M4(MLIRContext *ctx);
static FloatType getFloat6E3M2FN(MLIRContext *ctx);

/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(Type type);
Expand Down Expand Up @@ -413,13 +414,17 @@ inline bool BaseMemRefType::isValidElementType(Type type) {
}

inline bool FloatType::classof(Type type) {
return llvm::isa<Float8E5M2Type, Float8E4M3Type, Float8E4M3FNType,
Float8E5M2FNUZType, Float8E4M3FNUZType,
return llvm::isa<Float6E3M2FNType, Float8E5M2Type, Float8E4M3Type,
Float8E4M3FNType, Float8E5M2FNUZType, Float8E4M3FNUZType,
Float8E4M3B11FNUZType, Float8E3M4Type, BFloat16Type,
Float16Type, FloatTF32Type, Float32Type, Float64Type,
Float80Type, Float128Type>(type);
}

inline FloatType FloatType::getFloat6E3M2FN(MLIRContext *ctx) {
return Float6E3M2FNType::get(ctx);
}

inline FloatType FloatType::getFloat8E5M2(MLIRContext *ctx) {
return Float8E5M2Type::get(ctx);
}
Expand Down
21 changes: 21 additions & 0 deletions mlir/include/mlir/IR/BuiltinTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,27 @@ def Builtin_Float8E3M4 : Builtin_FloatType<"Float8E3M4", "f8E3M4"> {
}];
}

//===----------------------------------------------------------------------===//
// Float6E3M2FNType

def Builtin_Float6E3M2FN : Builtin_FloatType<"Float6E3M2FN", "f6E3M2FN"> {
let summary = "6-bit floating point with 3 bits exponent and 2 bit mantissa";
let description = [{
An 6-bit floating point type with 1 sign bit, 3 bits exponent and 2 bits
mantissa. This is not a standard type as defined by IEEE-754, but it
follows similar conventions with the following characteristics:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a reference to the OCP spec or at least mention it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a link.


* bit encoding: S1E3M2
* exponent bias: 3
* infinities: Not supported
* NaNs: Not supported
* denormals when exponent is 0

Open Compute Project (OCP) microscaling formats (MX) specification:
https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
}];
}

//===----------------------------------------------------------------------===//
// BFloat16Type

Expand Down
2 changes: 2 additions & 0 deletions mlir/include/mlir/IR/CommonTypeConstraints.td
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ def F8E5M2FNUZ : Type<CPred<"$_self.isFloat8E5M2FNUZ()">, "f8E5M2FNUZ type">,
BuildableType<"$_builder.getFloat8E5M2FNUZType()">;
def F8E3M4 : Type<CPred<"$_self.isFloat8E3M4()">, "f8E3M4 type">,
BuildableType<"$_builder.getFloat8E3M4Type()">;
def F6E3M2FN : Type<CPred<"$_self.isFloat6E3M2FN()">, "f6E3M2FN type">,
BuildableType<"$_builder.getFloat6E3M2FNType()">;

def AnyComplex : Type<CPred<"::llvm::isa<::mlir::ComplexType>($_self)">,
"complex-type", "::mlir::ComplexType">;
Expand Down
1 change: 1 addition & 0 deletions mlir/include/mlir/IR/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class Type {
// Convenience predicates. This is only for floating point types,
// derived types should use isa/dyn_cast.
bool isIndex() const;
bool isFloat6E3M2FN() const;
bool isFloat8E5M2() const;
bool isFloat8E4M3() const;
bool isFloat8E4M3FN() const;
Expand Down
1 change: 1 addition & 0 deletions mlir/lib/AsmParser/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ TOK_KEYWORD(f8E5M2FNUZ)
TOK_KEYWORD(f8E4M3FNUZ)
TOK_KEYWORD(f8E4M3B11FNUZ)
TOK_KEYWORD(f8E3M4)
TOK_KEYWORD(f6E3M2FN)
TOK_KEYWORD(f128)
TOK_KEYWORD(false)
TOK_KEYWORD(floordiv)
Expand Down
4 changes: 4 additions & 0 deletions mlir/lib/AsmParser/TypeParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ OptionalParseResult Parser::parseOptionalType(Type &type) {
case Token::kw_tuple:
case Token::kw_vector:
case Token::inttype:
case Token::kw_f6E3M2FN:
case Token::kw_f8E5M2:
case Token::kw_f8E4M3:
case Token::kw_f8E4M3FN:
Expand Down Expand Up @@ -303,6 +304,9 @@ Type Parser::parseNonFunctionType() {
}

// float-type
case Token::kw_f6E3M2FN:
consumeToken(Token::kw_f6E3M2FN);
return builder.getFloat6E3M2FNType();
case Token::kw_f8E5M2:
consumeToken(Token::kw_f8E5M2);
return builder.getFloat8E5M2Type();
Expand Down
22 changes: 22 additions & 0 deletions mlir/lib/Bindings/Python/IRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ class PyFloatType : public PyConcreteType<PyFloatType> {
}
};

/// Floating Point Type subclass - Float6E3M2FNType.
class PyFloat6E3M2FNType
: public PyConcreteType<PyFloat6E3M2FNType, PyFloatType> {
public:
static constexpr IsAFunctionTy isaFunction = mlirTypeIsAFloat6E3M2FN;
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
mlirFloat6E3M2FNTypeGetTypeID;
static constexpr const char *pyClassName = "Float6E3M2FNType";
using PyConcreteType::PyConcreteType;

static void bindDerived(ClassTy &c) {
c.def_static(
"get",
[](DefaultingPyMlirContext context) {
MlirType t = mlirFloat6E3M2FNTypeGet(context->get());
return PyFloat6E3M2FNType(context->getRef(), t);
},
py::arg("context") = py::none(), "Create a float6_e3m2fn type.");
}
};

/// Floating Point Type subclass - Float8E4M3FNType.
class PyFloat8E4M3FNType
: public PyConcreteType<PyFloat8E4M3FNType, PyFloatType> {
Expand Down Expand Up @@ -880,6 +901,7 @@ void mlir::python::populateIRTypes(py::module &m) {
PyIntegerType::bind(m);
PyFloatType::bind(m);
PyIndexType::bind(m);
PyFloat6E3M2FNType::bind(m);
PyFloat8E4M3FNType::bind(m);
PyFloat8E5M2Type::bind(m);
PyFloat8E4M3Type::bind(m);
Expand Down
12 changes: 12 additions & 0 deletions mlir/lib/CAPI/IR/BuiltinTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ unsigned mlirFloatTypeGetWidth(MlirType type) {
return llvm::cast<FloatType>(unwrap(type)).getWidth();
}

MlirTypeID mlirFloat6E3M2FNTypeGetTypeID() {
return wrap(Float6E3M2FNType::getTypeID());
}

bool mlirTypeIsAFloat6E3M2FN(MlirType type) {
return unwrap(type).isFloat6E3M2FN();
}

MlirType mlirFloat6E3M2FNTypeGet(MlirContext ctx) {
return wrap(FloatType::getFloat6E3M2FN(unwrap(ctx)));
}

MlirTypeID mlirFloat8E5M2TypeGetTypeID() {
return wrap(Float8E5M2Type::getTypeID());
}
Expand Down
3 changes: 2 additions & 1 deletion mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ Type LLVMTypeConverter::convertIntegerType(IntegerType type) const {
Type LLVMTypeConverter::convertFloatType(FloatType type) const {
if (type.isFloat8E5M2() || type.isFloat8E4M3() || type.isFloat8E4M3FN() ||
type.isFloat8E5M2FNUZ() || type.isFloat8E4M3FNUZ() ||
type.isFloat8E4M3B11FNUZ() || type.isFloat8E3M4())
type.isFloat8E4M3B11FNUZ() || type.isFloat8E3M4() ||
type.isFloat6E3M2FN())
return IntegerType::get(&getContext(), type.getWidth());
return type;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static std::optional<FloatType> parseFloatType(MLIRContext *ctx,
StringRef name) {
Builder b(ctx);
return llvm::StringSwitch<std::optional<FloatType>>(name)
.Case("f6E3M2FN", b.getFloat6E3M2FNType())
.Case("f8E5M2", b.getFloat8E5M2Type())
.Case("f8E4M3", b.getFloat8E4M3Type())
.Case("f8E4M3FN", b.getFloat8E4M3FNType())
Expand Down
1 change: 1 addition & 0 deletions mlir/lib/IR/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,7 @@ void AsmPrinter::Impl::printTypeImpl(Type type) {
opaqueTy.getTypeData());
})
.Case<IndexType>([&](Type) { os << "index"; })
.Case<Float6E3M2FNType>([&](Type) { os << "f6E3M2FN"; })
.Case<Float8E5M2Type>([&](Type) { os << "f8E5M2"; })
.Case<Float8E4M3Type>([&](Type) { os << "f8E4M3"; })
.Case<Float8E4M3FNType>([&](Type) { os << "f8E4M3FN"; })
Expand Down
4 changes: 4 additions & 0 deletions mlir/lib/IR/Builders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Location Builder::getFusedLoc(ArrayRef<Location> locs, Attribute metadata) {
// Types.
//===----------------------------------------------------------------------===//

FloatType Builder::getFloat6E3M2FNType() {
return FloatType::getFloat6E3M2FN(context);
}

FloatType Builder::getFloat8E5M2Type() {
return FloatType::getFloat8E5M2(context);
}
Expand Down
4 changes: 4 additions & 0 deletions mlir/lib/IR/BuiltinTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ IntegerType IntegerType::scaleElementBitwidth(unsigned scale) {
//===----------------------------------------------------------------------===//

unsigned FloatType::getWidth() {
if (llvm::isa<Float6E3M2FNType>(*this))
return 6;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we use APFloat here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this in a separate PR, if you don't mind.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #107372

if (llvm::isa<Float8E5M2Type, Float8E4M3Type, Float8E4M3FNType,
Float8E5M2FNUZType, Float8E4M3FNUZType, Float8E4M3B11FNUZType,
Float8E3M4Type>(*this))
Expand All @@ -110,6 +112,8 @@ unsigned FloatType::getWidth() {

/// Returns the floating semantics for the given type.
const llvm::fltSemantics &FloatType::getFloatSemantics() {
if (llvm::isa<Float6E3M2FNType>(*this))
return APFloat::Float6E3M2FN();
if (llvm::isa<Float8E5M2Type>(*this))
return APFloat::Float8E5M2();
if (llvm::isa<Float8E4M3Type>(*this))
Expand Down
5 changes: 5 additions & 0 deletions mlir/lib/IR/MLIRContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class MLIRContextImpl {
llvm::DenseMap<StringRef, AbstractType *> nameToType;

/// Cached Type Instances.
Float6E3M2FNType f6E3M2FNTy;
Float8E5M2Type f8E5M2Ty;
Float8E4M3Type f8E4M3Ty;
Float8E4M3FNType f8E4M3FNTy;
Expand Down Expand Up @@ -313,6 +314,7 @@ MLIRContext::MLIRContext(const DialectRegistry &registry, Threading setting)

//// Types.
/// Floating-point Types.
impl->f6E3M2FNTy = TypeUniquer::get<Float6E3M2FNType>(this);
impl->f8E5M2Ty = TypeUniquer::get<Float8E5M2Type>(this);
impl->f8E4M3Ty = TypeUniquer::get<Float8E4M3Type>(this);
impl->f8E4M3FNTy = TypeUniquer::get<Float8E4M3FNType>(this);
Expand Down Expand Up @@ -1013,6 +1015,9 @@ AbstractType::lookup(StringRef name, MLIRContext *context) {
/// This should not be used directly.
StorageUniquer &MLIRContext::getTypeUniquer() { return getImpl().typeUniquer; }

Float6E3M2FNType Float6E3M2FNType::get(MLIRContext *context) {
return context->getImpl().f6E3M2FNTy;
}
Float8E5M2Type Float8E5M2Type::get(MLIRContext *context) {
return context->getImpl().f8E5M2Ty;
}
Expand Down
1 change: 1 addition & 0 deletions mlir/lib/IR/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Type AbstractType::replaceImmediateSubElements(Type type,

MLIRContext *Type::getContext() const { return getDialect().getContext(); }

bool Type::isFloat6E3M2FN() const { return llvm::isa<Float6E3M2FNType>(*this); }
bool Type::isFloat8E5M2() const { return llvm::isa<Float8E5M2Type>(*this); }
bool Type::isFloat8E4M3() const { return llvm::isa<Float8E4M3Type>(*this); }
bool Type::isFloat8E4M3FN() const { return llvm::isa<Float8E4M3FNType>(*this); }
Expand Down
14 changes: 14 additions & 0 deletions mlir/python/mlir/_mlir_libs/_mlir/ir.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ __all__ = [
"F32Type",
"F64Type",
"FlatSymbolRefAttr",
"Float6E3M2FNType",
"Float8E3M4Type",
"Float8E4M3B11FNUZType",
"Float8E4M3FNType",
Expand Down Expand Up @@ -1539,6 +1540,19 @@ class FlatSymbolRefAttr(Attribute):
Returns the value of the FlatSymbolRef attribute as a string
"""

class Float6E3M2FNType(FloatType):
static_typeid: ClassVar[TypeID]
@staticmethod
def get(context: Optional[Context] = None) -> Float6E3M2FNType:
"""
Create a float6_e3m2fn type.
"""
@staticmethod
def isinstance(other: Type) -> bool: ...
def __init__(self, cast_from_type: Type) -> None: ...
@property
def typeid(self) -> TypeID: ...

class Float8E3M4Type(FloatType):
static_typeid: ClassVar[TypeID]
@staticmethod
Expand Down
2 changes: 2 additions & 0 deletions mlir/python/mlir/extras/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
F16Type,
F32Type,
F64Type,
Float6E3M2FNType,
Float8E3M4Type,
Float8E4M3B11FNUZType,
Float8E4M3FNType,
Expand Down Expand Up @@ -74,6 +75,7 @@ def ui(width):
f8E4M3FN = lambda: Float8E4M3FNType.get()
f8E4M3B11FNUZ = lambda: Float8E4M3B11FNUZType.get()
f8E3M4 = lambda: Float8E3M4Type.get()
f6E3M2FN = lambda: Float6E3M2FNType.get()

none = lambda: NoneType.get()

Expand Down
4 changes: 4 additions & 0 deletions mlir/test/IR/attribute.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func.func @any_attr_of_fail() {
//===----------------------------------------------------------------------===//

func.func @float_attrs_pass() {
"test.float_attrs"() {
// CHECK: float_attr = 2.000000e+00 : f6E3M2FN
float_attr = 2. : f6E3M2FN
} : () -> ()
"test.float_attrs"() {
// CHECK: float_attr = 2.000000e+00 : f8E5M2
float_attr = 2. : f8E5M2
Expand Down
3 changes: 3 additions & 0 deletions mlir/test/Target/LLVMIR/llvmir.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ llvm.mlir.global internal @int_global_undef() : i64
// CHECK: @externally_initialized_global = internal externally_initialized global i32 0
llvm.mlir.global internal @externally_initialized_global(0 : i32) {externally_initialized} : i32

// CHECK: @f6E3M2FN_global_as_i6 = internal global i6 14
llvm.mlir.global internal @f6E3M2FN_global_as_i6(1.5 : f6E3M2FN) : i6

// CHECK: @f8E3M4_global_as_i8 = internal global i8 56
llvm.mlir.global internal @f8E3M4_global_as_i8(1.5 : f8E3M4) : i8

Expand Down
9 changes: 9 additions & 0 deletions mlir/test/python/ir/builtin_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ def testTypeIsInstance():
def testFloatTypeSubclasses():
ctx = Context()
# CHECK: True
print(isinstance(Type.parse("f6E3M2FN", ctx), FloatType))
# CHECK: True
print(isinstance(Type.parse("f8E3M4", ctx), FloatType))
# CHECK: True
print(isinstance(Type.parse("f8E4M3", ctx), FloatType))
Expand Down Expand Up @@ -233,6 +235,8 @@ def testIndexType():
@run
def testFloatType():
with Context():
# CHECK: float: f6E3M2FN
print("float:", Float6E3M2FNType.get())
# CHECK: float: f8E3M4
print("float:", Float8E3M4Type.get())
# CHECK: float: f8E4M3
Expand Down Expand Up @@ -609,6 +613,7 @@ def testTypeIDs():
types = [
(IntegerType, IntegerType.get_signless(16)),
(IndexType, IndexType.get()),
(Float6E3M2FNType, Float6E3M2FNType.get()),
(Float8E3M4Type, Float8E3M4Type.get()),
(Float8E4M3Type, Float8E4M3Type.get()),
(Float8E4M3FNType, Float8E4M3FNType.get()),
Expand All @@ -634,6 +639,7 @@ def testTypeIDs():

# CHECK: IntegerType(i16)
# CHECK: IndexType(index)
# CHECK: Float6E3M2FNType(f6E3M2FN)
# CHECK: Float8E3M4Type(f8E3M4)
# CHECK: Float8E4M3Type(f8E4M3)
# CHECK: Float8E4M3FNType(f8E4M3FN)
Expand Down Expand Up @@ -713,6 +719,9 @@ def print_downcasted(typ):
# CHECK: F64Type
# CHECK: F64Type(f64)
print_downcasted(F64Type.get())
# CHECK: Float6E3M2FNType
# CHECK: Float6E3M2FNType(f6E3M2FN)
print_downcasted(Float6E3M2FNType.get())
# CHECK: Float8E3M4Type
# CHECK: Float8E3M4Type(f8E3M4)
print_downcasted(Float8E3M4Type.get())
Expand Down
Loading
Loading