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

[APFloat] Add APFloat support for FP6 data types #94735

Merged
merged 1 commit into from
Jun 11, 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
2 changes: 2 additions & 0 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,8 @@ void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) {
case APFloat::S_Float8E4M3FNUZ:
case APFloat::S_Float8E4M3B11FNUZ:
case APFloat::S_FloatTF32:
case APFloat::S_Float6E3M2FN:
case APFloat::S_Float6E2M3FN:
llvm_unreachable("Tried to mangle unexpected APFloat semantics");
}

Expand Down
25 changes: 25 additions & 0 deletions llvm/include/llvm/ADT/APFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ struct APFloatBase {
// improved range compared to half (16-bit) formats, at (potentially)
// greater throughput than single precision (32-bit) formats.
S_FloatTF32,
// 6-bit floating point number with bit layout S1E3M2. Unlike IEEE-754
// types, there are no infinity or NaN values. The format is detailed in
// https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
S_Float6E3M2FN,
// 6-bit floating point number with bit layout S1E2M3. Unlike IEEE-754
// types, there are no infinity or NaN values. The format is detailed in
// https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
S_Float6E2M3FN,

S_x87DoubleExtended,
S_MaxSemantics = S_x87DoubleExtended,
Expand All @@ -209,6 +217,8 @@ struct APFloatBase {
static const fltSemantics &Float8E4M3FNUZ() LLVM_READNONE;
static const fltSemantics &Float8E4M3B11FNUZ() LLVM_READNONE;
static const fltSemantics &FloatTF32() LLVM_READNONE;
static const fltSemantics &Float6E3M2FN() LLVM_READNONE;
static const fltSemantics &Float6E2M3FN() LLVM_READNONE;
static const fltSemantics &x87DoubleExtended() LLVM_READNONE;

/// A Pseudo fltsemantic used to construct APFloats that cannot conflict with
Expand Down Expand Up @@ -627,6 +637,8 @@ class IEEEFloat final : public APFloatBase {
APInt convertFloat8E4M3FNUZAPFloatToAPInt() const;
APInt convertFloat8E4M3B11FNUZAPFloatToAPInt() const;
APInt convertFloatTF32APFloatToAPInt() const;
APInt convertFloat6E3M2FNAPFloatToAPInt() const;
APInt convertFloat6E2M3FNAPFloatToAPInt() const;
void initFromAPInt(const fltSemantics *Sem, const APInt &api);
template <const fltSemantics &S> void initFromIEEEAPInt(const APInt &api);
void initFromHalfAPInt(const APInt &api);
Expand All @@ -642,6 +654,8 @@ class IEEEFloat final : public APFloatBase {
void initFromFloat8E4M3FNUZAPInt(const APInt &api);
void initFromFloat8E4M3B11FNUZAPInt(const APInt &api);
void initFromFloatTF32APInt(const APInt &api);
void initFromFloat6E3M2FNAPInt(const APInt &api);
void initFromFloat6E2M3FNAPInt(const APInt &api);

void assign(const IEEEFloat &);
void copySignificand(const IEEEFloat &);
Expand Down Expand Up @@ -1039,6 +1053,17 @@ class APFloat : public APFloatBase {
/// \param Semantics - type float semantics
static APFloat getAllOnesValue(const fltSemantics &Semantics);

static bool hasNanOrInf(const fltSemantics &Sem) {
switch (SemanticsToEnum(Sem)) {
default:
return true;
// Below Semantics do not support {NaN or Inf}
case APFloat::S_Float6E3M2FN:
case APFloat::S_Float6E2M3FN:
return false;
}
}

/// Used to insert APFloat objects, or objects that contain APFloat objects,
/// into FoldingSets.
void Profile(FoldingSetNodeID &NID) const;
Expand Down
87 changes: 74 additions & 13 deletions llvm/lib/Support/APFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 = {
durga4github marked this conversation as resolved.
Show resolved Hide resolved
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};

Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading