Skip to content

[llvm][NFC] APFloat: Add missing semantics to enum #117291

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

Merged
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
41 changes: 38 additions & 3 deletions llvm/include/llvm/ADT/APFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,41 @@ struct APFloatBase {
S_IEEEsingle,
S_IEEEdouble,
S_IEEEquad,
// The IBM double-double semantics. Such a number consists of a pair of
// IEEE 64-bit doubles (Hi, Lo), where |Hi| > |Lo|, and if normal,
// (double)(Hi + Lo) == Hi. The numeric value it's modeling is Hi + Lo.
// Therefore it has two 53-bit mantissa parts that aren't necessarily
// adjacent to each other, and two 11-bit exponents.
//
// Note: we need to make the value different from semBogus as otherwise
// an unsafe optimization may collapse both values to a single address,
// and we heavily rely on them having distinct addresses.
S_PPCDoubleDouble,
// These are legacy semantics for the fallback, inaccurate implementation
// of IBM double-double, if the accurate semPPCDoubleDouble doesn't handle
// the operation. It's equivalent to having an IEEE number with consecutive
// 106 bits of mantissa and 11 bits of exponent.
//
// It's not equivalent to IBM double-double. For example, a legit IBM
// double-double, 1 + epsilon:
//
// 1 + epsilon = 1 + (1 >> 1076)
//
// is not representable by a consecutive 106 bits of mantissa.
//
// Currently, these semantics are used in the following way:
//
// semPPCDoubleDouble -> (IEEEdouble, IEEEdouble) ->
// (64-bit APInt, 64-bit APInt) -> (128-bit APInt) ->
// semPPCDoubleDoubleLegacy -> IEEE operations
//
// We use bitcastToAPInt() to get the bit representation (in APInt) of the
// underlying IEEEdouble, then use the APInt constructor to construct the
// legacy IEEE float.
//
// TODO: Implement all operations in semPPCDoubleDouble, and delete these
// semantics.
S_PPCDoubleDoubleLegacy,
// 8-bit floating point number following IEEE-754 conventions with bit
// layout S1E5M2 as described in https://arxiv.org/abs/2209.05433.
S_Float8E5M2,
Expand Down Expand Up @@ -214,7 +248,7 @@ struct APFloatBase {
// 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_Float4E2M1FN,

// TODO: Documentation is missing.
S_x87DoubleExtended,
S_MaxSemantics = S_x87DoubleExtended,
};
Expand All @@ -228,6 +262,7 @@ struct APFloatBase {
static const fltSemantics &IEEEdouble() LLVM_READNONE;
static const fltSemantics &IEEEquad() LLVM_READNONE;
static const fltSemantics &PPCDoubleDouble() LLVM_READNONE;
static const fltSemantics &PPCDoubleDoubleLegacy() LLVM_READNONE;
static const fltSemantics &Float8E5M2() LLVM_READNONE;
static const fltSemantics &Float8E5M2FNUZ() LLVM_READNONE;
static const fltSemantics &Float8E4M3() LLVM_READNONE;
Expand Down Expand Up @@ -688,7 +723,7 @@ class IEEEFloat final {
APInt convertDoubleAPFloatToAPInt() const;
APInt convertQuadrupleAPFloatToAPInt() const;
APInt convertF80LongDoubleAPFloatToAPInt() const;
APInt convertPPCDoubleDoubleAPFloatToAPInt() const;
APInt convertPPCDoubleDoubleLegacyAPFloatToAPInt() const;
APInt convertFloat8E5M2APFloatToAPInt() const;
APInt convertFloat8E5M2FNUZAPFloatToAPInt() const;
APInt convertFloat8E4M3APFloatToAPInt() const;
Expand All @@ -709,7 +744,7 @@ class IEEEFloat final {
void initFromDoubleAPInt(const APInt &api);
void initFromQuadrupleAPInt(const APInt &api);
void initFromF80LongDoubleAPInt(const APInt &api);
void initFromPPCDoubleDoubleAPInt(const APInt &api);
void initFromPPCDoubleDoubleLegacyAPInt(const APInt &api);
void initFromFloat8E5M2APInt(const APInt &api);
void initFromFloat8E5M2FNUZAPInt(const APInt &api);
void initFromFloat8E4M3APInt(const APInt &api);
Expand Down
52 changes: 12 additions & 40 deletions llvm/lib/Support/APFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,42 +164,7 @@ static constexpr fltSemantics semFloat4E2M1FN = {
2, 0, 2, 4, fltNonfiniteBehavior::FiniteOnly};
static constexpr fltSemantics semX87DoubleExtended = {16383, -16382, 64, 80};
static constexpr fltSemantics semBogus = {0, 0, 0, 0};

/* The IBM double-double semantics. Such a number consists of a pair of IEEE
64-bit doubles (Hi, Lo), where |Hi| > |Lo|, and if normal,
(double)(Hi + Lo) == Hi. The numeric value it's modeling is Hi + Lo.
Therefore it has two 53-bit mantissa parts that aren't necessarily adjacent
to each other, and two 11-bit exponents.

Note: we need to make the value different from semBogus as otherwise
an unsafe optimization may collapse both values to a single address,
and we heavily rely on them having distinct addresses. */
static constexpr fltSemantics semPPCDoubleDouble = {-1, 0, 0, 128};

/* These are legacy semantics for the fallback, inaccrurate implementation of
IBM double-double, if the accurate semPPCDoubleDouble doesn't handle the
operation. It's equivalent to having an IEEE number with consecutive 106
bits of mantissa and 11 bits of exponent.

It's not equivalent to IBM double-double. For example, a legit IBM
double-double, 1 + epsilon:

1 + epsilon = 1 + (1 >> 1076)

is not representable by a consecutive 106 bits of mantissa.

Currently, these semantics are used in the following way:

semPPCDoubleDouble -> (IEEEdouble, IEEEdouble) ->
(64-bit APInt, 64-bit APInt) -> (128-bit APInt) ->
semPPCDoubleDoubleLegacy -> IEEE operations

We use bitcastToAPInt() to get the bit representation (in APInt) of the
underlying IEEEdouble, then use the APInt constructor to construct the
legacy IEEE float.

TODO: Implement all operations in semPPCDoubleDouble, and delete these
semantics. */
static constexpr fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53,
53 + 53, 128};

Expand All @@ -217,6 +182,8 @@ const llvm::fltSemantics &APFloatBase::EnumToSemantics(Semantics S) {
return IEEEquad();
case S_PPCDoubleDouble:
return PPCDoubleDouble();
case S_PPCDoubleDoubleLegacy:
return PPCDoubleDoubleLegacy();
case S_Float8E5M2:
return Float8E5M2();
case S_Float8E5M2FNUZ:
Expand Down Expand Up @@ -261,6 +228,8 @@ APFloatBase::SemanticsToEnum(const llvm::fltSemantics &Sem) {
return S_IEEEquad;
else if (&Sem == &llvm::APFloat::PPCDoubleDouble())
return S_PPCDoubleDouble;
else if (&Sem == &llvm::APFloat::PPCDoubleDoubleLegacy())
return S_PPCDoubleDoubleLegacy;
else if (&Sem == &llvm::APFloat::Float8E5M2())
return S_Float8E5M2;
else if (&Sem == &llvm::APFloat::Float8E5M2FNUZ())
Expand Down Expand Up @@ -299,6 +268,9 @@ const fltSemantics &APFloatBase::IEEEquad() { return semIEEEquad; }
const fltSemantics &APFloatBase::PPCDoubleDouble() {
return semPPCDoubleDouble;
}
const fltSemantics &APFloatBase::PPCDoubleDoubleLegacy() {
return semPPCDoubleDoubleLegacy;
}
const fltSemantics &APFloatBase::Float8E5M2() { return semFloat8E5M2; }
const fltSemantics &APFloatBase::Float8E5M2FNUZ() { return semFloat8E5M2FNUZ; }
const fltSemantics &APFloatBase::Float8E4M3() { return semFloat8E4M3; }
Expand Down Expand Up @@ -3574,7 +3546,7 @@ APInt IEEEFloat::convertF80LongDoubleAPFloatToAPInt() const {
return APInt(80, words);
}

APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const {
APInt IEEEFloat::convertPPCDoubleDoubleLegacyAPFloatToAPInt() const {
assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy);
assert(partCount()==2);

Expand Down Expand Up @@ -3796,7 +3768,7 @@ APInt IEEEFloat::bitcastToAPInt() const {
return convertQuadrupleAPFloatToAPInt();

if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy)
return convertPPCDoubleDoubleAPFloatToAPInt();
return convertPPCDoubleDoubleLegacyAPFloatToAPInt();

if (semantics == (const llvm::fltSemantics *)&semFloat8E5M2)
return convertFloat8E5M2APFloatToAPInt();
Expand Down Expand Up @@ -3900,7 +3872,7 @@ void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) {
}
}

void IEEEFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) {
void IEEEFloat::initFromPPCDoubleDoubleLegacyAPInt(const APInt &api) {
uint64_t i1 = api.getRawData()[0];
uint64_t i2 = api.getRawData()[1];
opStatus fs;
Expand Down Expand Up @@ -4119,7 +4091,7 @@ void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
if (Sem == &semIEEEquad)
return initFromQuadrupleAPInt(api);
if (Sem == &semPPCDoubleDoubleLegacy)
return initFromPPCDoubleDoubleAPInt(api);
return initFromPPCDoubleDoubleLegacyAPInt(api);
if (Sem == &semFloat8E5M2)
return initFromFloat8E5M2APInt(api);
if (Sem == &semFloat8E5M2FNUZ)
Expand All @@ -4145,7 +4117,7 @@ void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
if (Sem == &semFloat4E2M1FN)
return initFromFloat4E2M1FNAPInt(api);

llvm_unreachable(nullptr);
llvm_unreachable("unsupported semantics");
}

/// Make this number the largest magnitude normal number in the given
Expand Down
Loading