Teach APFloat how to create both QNaNs and SNaNs and with arbitrary-width

payloads.  APFloat's internal folding routines always make QNaNs now,
instead of sometimes making QNaNs and sometimes SNaNs depending on the
type.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@97364 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2010-02-28 02:51:25 +00:00
parent 6281cda673
commit e12b73816b
6 changed files with 107 additions and 17 deletions

View File

@ -173,11 +173,16 @@ namespace llvm {
fcZero
};
enum uninitializedTag {
uninitialized
};
// Constructors.
APFloat(const fltSemantics &); // Default construct to 0.0
APFloat(const fltSemantics &, const StringRef &);
APFloat(const fltSemantics &, integerPart);
APFloat(const fltSemantics &, fltCategory, bool negative, unsigned type=0);
APFloat(const fltSemantics &, fltCategory, bool negative);
APFloat(const fltSemantics &, uninitializedTag);
explicit APFloat(double d);
explicit APFloat(float f);
explicit APFloat(const APInt &, bool isIEEE = false);
@ -199,7 +204,26 @@ namespace llvm {
/// default. The value is truncated as necessary.
static APFloat getNaN(const fltSemantics &Sem, bool Negative = false,
unsigned type = 0) {
return APFloat(Sem, fcNaN, Negative, type);
if (type) {
APInt fill(64, type);
return getQNaN(Sem, Negative, &fill);
} else {
return getQNaN(Sem, Negative, 0);
}
}
/// getQNan - Factory for QNaN values.
static APFloat getQNaN(const fltSemantics &Sem,
bool Negative = false,
const APInt *payload = 0) {
return makeNaN(Sem, false, Negative, payload);
}
/// getSNan - Factory for SNaN values.
static APFloat getSNaN(const fltSemantics &Sem,
bool Negative = false,
const APInt *payload = 0) {
return makeNaN(Sem, true, Negative, payload);
}
/// getLargest - Returns the largest finite number in the given
@ -350,7 +374,9 @@ namespace llvm {
opStatus modSpecials(const APFloat &);
/* Miscellany. */
void makeNaN(unsigned = 0);
static APFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
const APInt *fill);
void makeNaN(bool SNaN = false, bool Neg = false, const APInt *fill = 0);
opStatus normalize(roundingMode, lostFraction);
opStatus addOrSubtract(const APFloat &, roundingMode, bool subtract);
cmpResult compareAbsoluteValue(const APFloat &) const;

View File

@ -1308,6 +1308,9 @@ public:
/// Set the given bit of a bignum. Zero-based.
static void tcSetBit(integerPart *, unsigned int bit);
/// Clear the given bit of a bignum. Zero-based.
static void tcClearBit(integerPart *, unsigned int bit);
/// Returns the bit number of the least or most significant set bit
/// of a number. If the input number has no bits set -1U is
/// returned.

View File

@ -626,17 +626,37 @@ APFloat::copySignificand(const APFloat &rhs)
/* Make this number a NaN, with an arbitrary but deterministic value
for the significand. If double or longer, this is a signalling NaN,
which may not be ideal. If float, this is QNaN(0). */
void
APFloat::makeNaN(unsigned type)
void APFloat::makeNaN(bool SNaN, bool Negative, const APInt *fill)
{
category = fcNaN;
// FIXME: Add double and long double support for QNaN(0).
if (semantics->precision == 24 && semantics->maxExponent == 127) {
type |= 0x7fc00000U;
type &= ~0x80000000U;
} else
type = ~0U;
APInt::tcSet(significandParts(), type, partCount());
sign = Negative;
// Set the significand bits to the fill.
if (!fill || fill->getNumWords() < partCount())
APInt::tcSet(significandParts(), 0, partCount());
if (fill)
APInt::tcAssign(significandParts(), fill->getRawData(), partCount());
if (SNaN) {
// We always have to clear the QNaN bit to make it an SNaN.
APInt::tcClearBit(significandParts(), semantics->precision - 2);
// If there are no bits set in the payload, we have to set
// *something* to make it a NaN instead of an infinity;
// conventionally, this is the next bit down from the QNaN bit.
if (APInt::tcIsZero(significandParts(), partCount()))
APInt::tcSetBit(significandParts(), semantics->precision - 3);
} else {
// We always have to set the QNaN bit to make it a QNaN.
APInt::tcSetBit(significandParts(), semantics->precision - 2);
}
}
APFloat APFloat::makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
const APInt *fill) {
APFloat value(Sem, uninitialized);
value.makeNaN(SNaN, Negative, fill);
return value;
}
APFloat &
@ -701,9 +721,14 @@ APFloat::APFloat(const fltSemantics &ourSemantics) {
sign = false;
}
APFloat::APFloat(const fltSemantics &ourSemantics, uninitializedTag tag) {
assertArithmeticOK(ourSemantics);
// Allocates storage if necessary but does not initialize it.
initialize(&ourSemantics);
}
APFloat::APFloat(const fltSemantics &ourSemantics,
fltCategory ourCategory, bool negative, unsigned type)
fltCategory ourCategory, bool negative)
{
assertArithmeticOK(ourSemantics);
initialize(&ourSemantics);
@ -712,7 +737,7 @@ APFloat::APFloat(const fltSemantics &ourSemantics,
if (category == fcNormal)
category = fcZero;
else if (ourCategory == fcNaN)
makeNaN(type);
makeNaN();
}
APFloat::APFloat(const fltSemantics &ourSemantics, const StringRef& text)

View File

@ -2344,13 +2344,21 @@ APInt::tcExtractBit(const integerPart *parts, unsigned int bit)
& ((integerPart) 1 << bit % integerPartWidth)) != 0;
}
/* Set the given bit of a bignum. */
/* Set the given bit of a bignum. */
void
APInt::tcSetBit(integerPart *parts, unsigned int bit)
{
parts[bit / integerPartWidth] |= (integerPart) 1 << (bit % integerPartWidth);
}
/* Clears the given bit of a bignum. */
void
APInt::tcClearBit(integerPart *parts, unsigned int bit)
{
parts[bit / integerPartWidth] &=
~((integerPart) 1 << (bit % integerPartWidth));
}
/* Returns the bit number of the least significant set bit of a
number. If the input number has no bits set -1U is returned. */
unsigned int

View File

@ -1,5 +1,4 @@
; RUN: opt < %s -simplifycfg -instcombine -S | grep 0x7FF8000000000000 | count 7
; RUN: opt < %s -simplifycfg -instcombine -S | grep 0x7FF00000FFFFFFFF | count 5
; RUN: opt < %s -simplifycfg -instcombine -S | grep 0x7FF8000000000000 | count 12
; RUN: opt < %s -simplifycfg -instcombine -S | grep {0\\.0} | count 3
; RUN: opt < %s -simplifycfg -instcombine -S | grep {3\\.5} | count 1
;

View File

@ -344,6 +344,35 @@ TEST(APFloatTest, toString) {
ASSERT_EQ("8.731834E+2", convertToString(873.1834, 0, 0));
}
static APInt nanbits(const fltSemantics &Sem,
bool SNaN, bool Negative, uint64_t fill) {
APInt apfill(64, fill);
if (SNaN)
return APFloat::getSNaN(Sem, Negative, &apfill).bitcastToAPInt();
else
return APFloat::getQNaN(Sem, Negative, &apfill).bitcastToAPInt();
}
TEST(APFloatTest, makeNaN) {
ASSERT_EQ(0x7fc00000, nanbits(APFloat::IEEEsingle, false, false, 0));
ASSERT_EQ(0xffc00000, nanbits(APFloat::IEEEsingle, false, true, 0));
ASSERT_EQ(0x7fc0ae72, nanbits(APFloat::IEEEsingle, false, false, 0xae72));
ASSERT_EQ(0x7fffae72, nanbits(APFloat::IEEEsingle, false, false, 0xffffae72));
ASSERT_EQ(0x7fa00000, nanbits(APFloat::IEEEsingle, true, false, 0));
ASSERT_EQ(0xffa00000, nanbits(APFloat::IEEEsingle, true, true, 0));
ASSERT_EQ(0x7f80ae72, nanbits(APFloat::IEEEsingle, true, false, 0xae72));
ASSERT_EQ(0x7fbfae72, nanbits(APFloat::IEEEsingle, true, false, 0xffffae72));
ASSERT_EQ(0x7ff8000000000000ULL, nanbits(APFloat::IEEEdouble, false, false, 0));
ASSERT_EQ(0xfff8000000000000ULL, nanbits(APFloat::IEEEdouble, false, true, 0));
ASSERT_EQ(0x7ff800000000ae72ULL, nanbits(APFloat::IEEEdouble, false, false, 0xae72));
ASSERT_EQ(0x7fffffffffffae72ULL, nanbits(APFloat::IEEEdouble, false, false, 0xffffffffffffae72ULL));
ASSERT_EQ(0x7ff4000000000000ULL, nanbits(APFloat::IEEEdouble, true, false, 0));
ASSERT_EQ(0xfff4000000000000ULL, nanbits(APFloat::IEEEdouble, true, true, 0));
ASSERT_EQ(0x7ff000000000ae72ULL, nanbits(APFloat::IEEEdouble, true, false, 0xae72));
ASSERT_EQ(0x7ff7ffffffffae72ULL, nanbits(APFloat::IEEEdouble, true, false, 0xffffffffffffae72ULL));
}
#ifdef GTEST_HAS_DEATH_TEST
TEST(APFloatTest, SemanticsDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEsingle, 0.0f).convertToDouble(), "Float semantics are not IEEEdouble");