aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/APFloat.cpp
diff options
context:
space:
mode:
authorDurgadoss R <durgadossr@nvidia.com>2024-06-11 13:16:51 +0530
committerGitHub <noreply@github.com>2024-06-11 13:16:51 +0530
commitb1fe03f0840a2c488b1f07a669bfea3cc986ce3b (patch)
tree94dc61f58ba757dffafbc48e2e6f5f4d13aa54ee /llvm/lib/Support/APFloat.cpp
parentbd9a525efdab2a83cb24773d95ce8c4a2e9cce68 (diff)
downloadllvm-b1fe03f0840a2c488b1f07a669bfea3cc986ce3b.zip
llvm-b1fe03f0840a2c488b1f07a669bfea3cc986ce3b.tar.gz
llvm-b1fe03f0840a2c488b1f07a669bfea3cc986ce3b.tar.bz2
[APFloat] Add APFloat support for FP6 data types (#94735)
This patch adds APFloat type support for two FP6 data types, E2M3 and E3M2. The definitions for the two formats are detailed in section 5.3.2 of the OCP specification, which can be accessed here: https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf Signed-off-by: Durgadoss R <durgadossr@nvidia.com>
Diffstat (limited to 'llvm/lib/Support/APFloat.cpp')
-rw-r--r--llvm/lib/Support/APFloat.cpp87
1 files changed, 74 insertions, 13 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 283fcc1..1209bf7 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -68,6 +68,10 @@ enum class fltNonfiniteBehavior {
// `fltNanEncoding` enum. We treat all NaNs as quiet, as the available
// encodings do not distinguish between signalling and quiet NaN.
NanOnly,
+
+ // This behavior is present in Float6E3M2FN and Float6E2M3FN types,
+ // which do not support Inf or NaN values.
+ FiniteOnly,
};
// How NaN values are represented. This is curently only used in combination
@@ -139,6 +143,10 @@ static constexpr fltSemantics semFloat8E4M3FNUZ = {
static constexpr fltSemantics semFloat8E4M3B11FNUZ = {
4, -10, 4, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero};
static constexpr fltSemantics semFloatTF32 = {127, -126, 11, 19};
+static constexpr fltSemantics semFloat6E3M2FN = {
+ 4, -2, 3, 6, fltNonfiniteBehavior::FiniteOnly};
+static constexpr fltSemantics semFloat6E2M3FN = {
+ 2, 0, 4, 6, fltNonfiniteBehavior::FiniteOnly};
static constexpr fltSemantics semX87DoubleExtended = {16383, -16382, 64, 80};
static constexpr fltSemantics semBogus = {0, 0, 0, 0};
@@ -206,6 +214,10 @@ const llvm::fltSemantics &APFloatBase::EnumToSemantics(Semantics S) {
return Float8E4M3B11FNUZ();
case S_FloatTF32:
return FloatTF32();
+ case S_Float6E3M2FN:
+ return Float6E3M2FN();
+ case S_Float6E2M3FN:
+ return Float6E2M3FN();
case S_x87DoubleExtended:
return x87DoubleExtended();
}
@@ -238,6 +250,10 @@ APFloatBase::SemanticsToEnum(const llvm::fltSemantics &Sem) {
return S_Float8E4M3B11FNUZ;
else if (&Sem == &llvm::APFloat::FloatTF32())
return S_FloatTF32;
+ else if (&Sem == &llvm::APFloat::Float6E3M2FN())
+ return S_Float6E3M2FN;
+ else if (&Sem == &llvm::APFloat::Float6E2M3FN())
+ return S_Float6E2M3FN;
else if (&Sem == &llvm::APFloat::x87DoubleExtended())
return S_x87DoubleExtended;
else
@@ -260,6 +276,8 @@ const fltSemantics &APFloatBase::Float8E4M3B11FNUZ() {
return semFloat8E4M3B11FNUZ;
}
const fltSemantics &APFloatBase::FloatTF32() { return semFloatTF32; }
+const fltSemantics &APFloatBase::Float6E3M2FN() { return semFloat6E3M2FN; }
+const fltSemantics &APFloatBase::Float6E2M3FN() { return semFloat6E2M3FN; }
const fltSemantics &APFloatBase::x87DoubleExtended() {
return semX87DoubleExtended;
}
@@ -878,6 +896,9 @@ void IEEEFloat::copySignificand(const IEEEFloat &rhs) {
for the significand. If double or longer, this is a signalling NaN,
which may not be ideal. If float, this is QNaN(0). */
void IEEEFloat::makeNaN(bool SNaN, bool Negative, const APInt *fill) {
+ if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
+ llvm_unreachable("This floating point format does not support NaN");
+
category = fcNaN;
sign = Negative;
exponent = exponentNaN();
@@ -1499,16 +1520,18 @@ static void tcSetLeastSignificantBits(APInt::WordType *dst, unsigned parts,
/* Handle overflow. Sign is preserved. We either become infinity or
the largest finite number. */
IEEEFloat::opStatus IEEEFloat::handleOverflow(roundingMode rounding_mode) {
- /* Infinity? */
- if (rounding_mode == rmNearestTiesToEven ||
- rounding_mode == rmNearestTiesToAway ||
- (rounding_mode == rmTowardPositive && !sign) ||
- (rounding_mode == rmTowardNegative && sign)) {
- if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly)
- makeNaN(false, sign);
- else
- category = fcInfinity;
- return (opStatus) (opOverflow | opInexact);
+ if (semantics->nonFiniteBehavior != fltNonfiniteBehavior::FiniteOnly) {
+ /* Infinity? */
+ if (rounding_mode == rmNearestTiesToEven ||
+ rounding_mode == rmNearestTiesToAway ||
+ (rounding_mode == rmTowardPositive && !sign) ||
+ (rounding_mode == rmTowardNegative && sign)) {
+ if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly)
+ makeNaN(false, sign);
+ else
+ category = fcInfinity;
+ return static_cast<opStatus>(opOverflow | opInexact);
+ }
}
/* Otherwise we become the largest finite number. */
@@ -3518,13 +3541,15 @@ APInt IEEEFloat::convertIEEEFloatToAPInt() const {
myexponent = ::exponentZero(S) + bias;
mysignificand.fill(0);
} else if (category == fcInfinity) {
- if (S.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly) {
+ if (S.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
+ S.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
llvm_unreachable("semantics don't support inf!");
- }
myexponent = ::exponentInf(S) + bias;
mysignificand.fill(0);
} else {
assert(category == fcNaN && "Unknown category!");
+ if (S.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
+ llvm_unreachable("semantics don't support NaN!");
myexponent = ::exponentNaN(S) + bias;
std::copy_n(significandParts(), mysignificand.size(),
mysignificand.begin());
@@ -3605,6 +3630,16 @@ APInt IEEEFloat::convertFloatTF32APFloatToAPInt() const {
return convertIEEEFloatToAPInt<semFloatTF32>();
}
+APInt IEEEFloat::convertFloat6E3M2FNAPFloatToAPInt() const {
+ assert(partCount() == 1);
+ return convertIEEEFloatToAPInt<semFloat6E3M2FN>();
+}
+
+APInt IEEEFloat::convertFloat6E2M3FNAPFloatToAPInt() const {
+ assert(partCount() == 1);
+ return convertIEEEFloatToAPInt<semFloat6E2M3FN>();
+}
+
// This function creates an APInt that is just a bit map of the floating
// point constant as it would appear in memory. It is not a conversion,
// and treating the result as a normal integer is unlikely to be useful.
@@ -3646,6 +3681,12 @@ APInt IEEEFloat::bitcastToAPInt() const {
if (semantics == (const llvm::fltSemantics *)&semFloatTF32)
return convertFloatTF32APFloatToAPInt();
+ if (semantics == (const llvm::fltSemantics *)&semFloat6E3M2FN)
+ return convertFloat6E3M2FNAPFloatToAPInt();
+
+ if (semantics == (const llvm::fltSemantics *)&semFloat6E2M3FN)
+ return convertFloat6E2M3FNAPFloatToAPInt();
+
assert(semantics == (const llvm::fltSemantics*)&semX87DoubleExtended &&
"unknown format!");
return convertF80LongDoubleAPFloatToAPInt();
@@ -3862,6 +3903,14 @@ void IEEEFloat::initFromFloatTF32APInt(const APInt &api) {
initFromIEEEAPInt<semFloatTF32>(api);
}
+void IEEEFloat::initFromFloat6E3M2FNAPInt(const APInt &api) {
+ initFromIEEEAPInt<semFloat6E3M2FN>(api);
+}
+
+void IEEEFloat::initFromFloat6E2M3FNAPInt(const APInt &api) {
+ initFromIEEEAPInt<semFloat6E2M3FN>(api);
+}
+
/// Treat api as containing the bits of a floating point number.
void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
assert(api.getBitWidth() == Sem->sizeInBits);
@@ -3891,6 +3940,10 @@ void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
return initFromFloat8E4M3B11FNUZAPInt(api);
if (Sem == &semFloatTF32)
return initFromFloatTF32APInt(api);
+ if (Sem == &semFloat6E3M2FN)
+ return initFromFloat6E3M2FNAPInt(api);
+ if (Sem == &semFloat6E2M3FN)
+ return initFromFloat6E2M3FNAPInt(api);
llvm_unreachable(nullptr);
}
@@ -4328,7 +4381,8 @@ int IEEEFloat::getExactLog2Abs() const {
bool IEEEFloat::isSignaling() const {
if (!isNaN())
return false;
- if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly)
+ if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
+ semantics->nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
return false;
// IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the
@@ -4387,6 +4441,10 @@ IEEEFloat::opStatus IEEEFloat::next(bool nextDown) {
// nextUp(getLargest()) == NAN
makeNaN();
break;
+ } else if (semantics->nonFiniteBehavior ==
+ fltNonfiniteBehavior::FiniteOnly) {
+ // nextUp(getLargest()) == getLargest()
+ break;
} else {
// nextUp(getLargest()) == INFINITY
APInt::tcSet(significandParts(), 0, partCount());
@@ -4477,6 +4535,9 @@ APFloatBase::ExponentType IEEEFloat::exponentZero() const {
}
void IEEEFloat::makeInf(bool Negative) {
+ if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
+ llvm_unreachable("This floating point format does not support Inf");
+
if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly) {
// There is no Inf, so make NaN instead.
makeNaN(false, Negative);