[llvm] r182945 - Implement IEEE-754R 2008 nextUp/nextDown functions in the guise of the function APFloat::next(bool nextDown).
Michael Gottesman
mgottesman at apple.com
Thu May 30 11:07:13 PDT 2013
Author: mgottesman
Date: Thu May 30 13:07:13 2013
New Revision: 182945
URL: http://llvm.org/viewvc/llvm-project?rev=182945&view=rev
Log:
Implement IEEE-754R 2008 nextUp/nextDown functions in the guise of the function APFloat::next(bool nextDown).
rdar://13852078
Modified:
llvm/trunk/include/llvm/ADT/APFloat.h
llvm/trunk/lib/Support/APFloat.cpp
llvm/trunk/unittests/ADT/APFloatTest.cpp
Modified: llvm/trunk/include/llvm/ADT/APFloat.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/APFloat.h?rev=182945&r1=182944&r2=182945&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/APFloat.h (original)
+++ llvm/trunk/include/llvm/ADT/APFloat.h Thu May 30 13:07:13 2013
@@ -81,6 +81,11 @@
although not really meaningful, and preserved in non-conversion
operations. The exponent is implicitly all 1 bits.
+ APFloat does not provide any exception handling beyond default exception
+ handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause
+ by encoding Signaling NaNs with the first bit of its trailing significand as
+ 0.
+
TODO
====
@@ -273,6 +278,8 @@ public:
opStatus mod(const APFloat &, roundingMode);
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
opStatus roundToIntegral(roundingMode);
+ /// IEEE-754R 5.3.1: nextUp/nextDown.
+ opStatus next(bool nextDown);
/* Sign operations. */
void changeSign();
@@ -325,6 +332,8 @@ public:
bool isPosZero() const { return isZero() && !isNegative(); }
bool isNegZero() const { return isZero() && isNegative(); }
bool isDenormal() const;
+ /// IEEE-754R 5.7.2: isSignaling. Returns true if this is a signaling NaN.
+ bool isSignaling() const;
APFloat &operator=(const APFloat &);
@@ -386,6 +395,10 @@ private:
unsigned int significandLSB() const;
unsigned int significandMSB() const;
void zeroSignificand();
+ /// Return true if the significand excluding the integral bit is all ones.
+ bool isSignificandAllOnes() const;
+ /// Return true if the significand excluding the integral bit is all zeros.
+ bool isSignificandAllZeros() const;
/* Arithmetic on special values. */
opStatus addOrSubtractSpecials(const APFloat &, bool subtract);
@@ -393,10 +406,26 @@ private:
opStatus multiplySpecials(const APFloat &);
opStatus modSpecials(const APFloat &);
- /* Miscellany. */
+ /* Set to special values. */
+ void makeLargest(bool Neg = false);
+ void makeSmallest(bool Neg = false);
+ void makeNaN(bool SNaN = false, bool Neg = false, const APInt *fill = 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);
+
+ /// \name Special value queries only useful internally to APFloat
+ /// @{
+
+ /// Returns true if and only if the number has the smallest possible non-zero
+ /// magnitude in the current semantics.
+ bool isSmallest() const;
+ /// Returns true if and only if the number has the largest possible finite
+ /// magnitude in the current semantics.
+ bool isLargest() const;
+
+ /// @}
+
+ /* Miscellany. */
opStatus normalize(roundingMode, lostFraction);
opStatus addOrSubtract(const APFloat &, roundingMode, bool subtract);
cmpResult compareAbsoluteValue(const APFloat &) const;
Modified: llvm/trunk/lib/Support/APFloat.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/APFloat.cpp?rev=182945&r1=182944&r2=182945&view=diff
==============================================================================
--- llvm/trunk/lib/Support/APFloat.cpp (original)
+++ llvm/trunk/lib/Support/APFloat.cpp Thu May 30 13:07:13 2013
@@ -685,6 +685,67 @@ APFloat::isDenormal() const {
}
bool
+APFloat::isSmallest() const {
+ // The smallest number by magnitude in our format will be the smallest
+ // denormal, i.e. the floating point normal with exponent being minimum
+ // exponent and significand bitwise equal to 1 (i.e. with MSB equal to 0).
+ return isNormal() && exponent == semantics->minExponent &&
+ significandMSB() == 0;
+}
+
+bool APFloat::isSignificandAllOnes() const {
+ // Test if the significand excluding the integral bit is all ones. This allows
+ // us to test for binade boundaries.
+ const integerPart *Parts = significandParts();
+ const unsigned PartCount = partCount();
+ for (unsigned i = 0; i < PartCount - 1; i++)
+ if (~Parts[i])
+ return false;
+
+ // Set the unused high bits to all ones when we compare.
+ const unsigned NumHighBits =
+ PartCount*integerPartWidth - semantics->precision + 1;
+ assert(NumHighBits <= integerPartWidth && "Can not have more high bits to "
+ "fill than integerPartWidth");
+ const integerPart HighBitFill =
+ ~integerPart(0) << (integerPartWidth - NumHighBits);
+ if (~(Parts[PartCount - 1] | HighBitFill))
+ return false;
+
+ return true;
+}
+
+bool APFloat::isSignificandAllZeros() const {
+ // Test if the significand excluding the integral bit is all zeros. This
+ // allows us to test for binade boundaries.
+ const integerPart *Parts = significandParts();
+ const unsigned PartCount = partCount();
+
+ for (unsigned i = 0; i < PartCount - 1; i++)
+ if (Parts[i])
+ return false;
+
+ const unsigned NumHighBits =
+ PartCount*integerPartWidth - semantics->precision + 1;
+ assert(NumHighBits <= integerPartWidth && "Can not have more high bits to "
+ "clear than integerPartWidth");
+ const integerPart HighBitMask = ~integerPart(0) >> NumHighBits;
+
+ if (Parts[PartCount - 1] & HighBitMask)
+ return false;
+
+ return true;
+}
+
+bool
+APFloat::isLargest() const {
+ // The largest number by magnitude in our format will be the floating point
+ // number with maximum exponent and with significand that is all ones.
+ return isNormal() && exponent == semantics->maxExponent
+ && isSignificandAllOnes();
+}
+
+bool
APFloat::bitwiseIsEqual(const APFloat &rhs) const {
if (this == &rhs)
return true;
@@ -3236,42 +3297,60 @@ APFloat::getAllOnesValue(unsigned BitWid
}
}
-APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) {
- APFloat Val(Sem, fcNormal, Negative);
-
+/// Make this number the largest magnitude normal number in the given
+/// semantics.
+void APFloat::makeLargest(bool Negative) {
// We want (in interchange format):
// sign = {Negative}
// exponent = 1..10
// significand = 1..1
+ category = fcNormal;
+ sign = Negative;
+ exponent = semantics->maxExponent;
- Val.exponent = Sem.maxExponent; // unbiased
+ // Use memset to set all but the highest integerPart to all ones.
+ integerPart *significand = significandParts();
+ unsigned PartCount = partCount();
+ memset(significand, 0xFF, sizeof(integerPart)*(PartCount - 1));
+
+ // Set the high integerPart especially setting all unused top bits for
+ // internal consistency.
+ const unsigned NumUnusedHighBits =
+ PartCount*integerPartWidth - semantics->precision;
+ significand[PartCount - 1] = ~integerPart(0) >> NumUnusedHighBits;
+}
+
+/// Make this number the smallest magnitude denormal number in the given
+/// semantics.
+void APFloat::makeSmallest(bool Negative) {
+ // We want (in interchange format):
+ // sign = {Negative}
+ // exponent = 0..0
+ // significand = 0..01
+ category = fcNormal;
+ sign = Negative;
+ exponent = semantics->minExponent;
+ APInt::tcSet(significandParts(), 1, partCount());
+}
- // 1-initialize all bits....
- Val.zeroSignificand();
- integerPart *significand = Val.significandParts();
- unsigned N = partCountForBits(Sem.precision);
- for (unsigned i = 0; i != N; ++i)
- significand[i] = ~((integerPart) 0);
-
- // ...and then clear the top bits for internal consistency.
- if (Sem.precision % integerPartWidth != 0)
- significand[N-1] &=
- (((integerPart) 1) << (Sem.precision % integerPartWidth)) - 1;
+APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) {
+ // We want (in interchange format):
+ // sign = {Negative}
+ // exponent = 1..10
+ // significand = 1..1
+ APFloat Val(Sem, uninitialized);
+ Val.makeLargest(Negative);
return Val;
}
APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) {
- APFloat Val(Sem, fcNormal, Negative);
-
// We want (in interchange format):
// sign = {Negative}
// exponent = 0..0
// significand = 0..01
-
- Val.exponent = Sem.minExponent; // unbiased
- Val.zeroSignificand();
- Val.significandParts()[0] = 1;
+ APFloat Val(Sem, uninitialized);
+ Val.makeSmallest(Negative);
return Val;
}
@@ -3615,3 +3694,132 @@ bool APFloat::getExactInverse(APFloat *i
return true;
}
+
+bool APFloat::isSignaling() const {
+ if (!isNaN())
+ return false;
+
+ // IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the
+ // first bit of the trailing significand being 0.
+ return !APInt::tcExtractBit(significandParts(), semantics->precision - 2);
+}
+
+/// IEEE-754R 2008 5.3.1: nextUp/nextDown.
+///
+/// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with
+/// appropriate sign switching before/after the computation.
+APFloat::opStatus APFloat::next(bool nextDown) {
+ // If we are performing nextDown, swap sign so we have -x.
+ if (nextDown)
+ changeSign();
+
+ // Compute nextUp(x)
+ opStatus result = opOK;
+
+ // Handle each float category separately.
+ switch (category) {
+ case fcInfinity:
+ // nextUp(+inf) = +inf
+ if (!isNegative())
+ break;
+ // nextUp(-inf) = -getLargest()
+ makeLargest(true);
+ break;
+ case fcNaN:
+ // IEEE-754R 2008 6.2 Par 2: nextUp(sNaN) = qNaN. Set Invalid flag.
+ // IEEE-754R 2008 6.2: nextUp(qNaN) = qNaN. Must be identity so we do not
+ // change the payload.
+ if (isSignaling()) {
+ result = opInvalidOp;
+ // For consistency, propogate the sign of the sNaN to the qNaN.
+ makeNaN(false, isNegative(), 0);
+ }
+ break;
+ case fcZero:
+ // nextUp(pm 0) = +getSmallest()
+ makeSmallest(false);
+ break;
+ case fcNormal:
+ // nextUp(-getSmallest()) = -0
+ if (isSmallest() && isNegative()) {
+ APInt::tcSet(significandParts(), 0, partCount());
+ category = fcZero;
+ exponent = 0;
+ break;
+ }
+
+ // nextUp(getLargest()) == INFINITY
+ if (isLargest() && !isNegative()) {
+ APInt::tcSet(significandParts(), 0, partCount());
+ category = fcInfinity;
+ exponent = semantics->maxExponent + 1;
+ break;
+ }
+
+ // nextUp(normal) == normal + inc.
+ if (isNegative()) {
+ // If we are negative, we need to decrement the significand.
+
+ // We only cross a binade boundary that requires adjusting the exponent
+ // if:
+ // 1. exponent != semantics->minExponent. This implies we are not in the
+ // smallest binade or are dealing with denormals.
+ // 2. Our significand excluding the integral bit is all zeros.
+ bool WillCrossBinadeBoundary =
+ exponent != semantics->minExponent && isSignificandAllZeros();
+
+ // Decrement the significand.
+ //
+ // We always do this since:
+ // 1. If we are dealing with a non binade decrement, by definition we
+ // just decrement the significand.
+ // 2. If we are dealing with a normal -> normal binade decrement, since
+ // we have an explicit integral bit the fact that all bits but the
+ // integral bit are zero implies that subtracting one will yield a
+ // significand with 0 integral bit and 1 in all other spots. Thus we
+ // must just adjust the exponent and set the integral bit to 1.
+ // 3. If we are dealing with a normal -> denormal binade decrement,
+ // since we set the integral bit to 0 when we represent denormals, we
+ // just decrement the significand.
+ integerPart *Parts = significandParts();
+ APInt::tcDecrement(Parts, partCount());
+
+ if (WillCrossBinadeBoundary) {
+ // Our result is a normal number. Do the following:
+ // 1. Set the integral bit to 1.
+ // 2. Decrement the exponent.
+ APInt::tcSetBit(Parts, semantics->precision - 1);
+ exponent--;
+ }
+ } else {
+ // If we are positive, we need to increment the significand.
+
+ // We only cross a binade boundary that requires adjusting the exponent if
+ // the input is not a denormal and all of said input's significand bits
+ // are set. If all of said conditions are true: clear the significand, set
+ // the integral bit to 1, and increment the exponent. If we have a
+ // denormal always increment since moving denormals and the numbers in the
+ // smallest normal binade have the same exponent in our representation.
+ bool WillCrossBinadeBoundary = !isDenormal() && isSignificandAllOnes();
+
+ if (WillCrossBinadeBoundary) {
+ integerPart *Parts = significandParts();
+ APInt::tcSet(Parts, 0, partCount());
+ APInt::tcSetBit(Parts, semantics->precision - 1);
+ assert(exponent != semantics->maxExponent &&
+ "We can not increment an exponent beyond the maxExponent allowed"
+ " by the given floating point semantics.");
+ exponent++;
+ } else {
+ incrementSignificand();
+ }
+ }
+ break;
+ }
+
+ // If we are performing nextDown, swap sign so we have -nextUp(-x)
+ if (nextDown)
+ changeSign();
+
+ return result;
+}
Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=182945&r1=182944&r2=182945&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/APFloatTest.cpp (original)
+++ llvm/trunk/unittests/ADT/APFloatTest.cpp Thu May 30 13:07:13 2013
@@ -33,6 +33,426 @@ static std::string convertToString(doubl
namespace {
+TEST(APFloatTest, isSignaling) {
+ // We test qNaN, -qNaN, +sNaN, -sNaN with and without payloads. *NOTE* The
+ // positive/negative distinction is included only since the getQNaN/getSNaN
+ // API provides the option.
+ APInt payload = APInt::getOneBitSet(4, 2);
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, false, &payload).isSignaling());
+ EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle, true, &payload).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, false, &payload).isSignaling());
+ EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle, true, &payload).isSignaling());
+}
+
+TEST(APFloatTest, next) {
+
+ APFloat test(APFloat::IEEEquad, APFloat::uninitialized);
+ APFloat expected(APFloat::IEEEquad, APFloat::uninitialized);
+
+ // 1. Test Special Cases Values.
+ //
+ // Test all special values for nextUp and nextDown perscribed by IEEE-754R
+ // 2008. These are:
+ // 1. +inf
+ // 2. -inf
+ // 3. getLargest()
+ // 4. -getLargest()
+ // 5. getSmallest()
+ // 6. -getSmallest()
+ // 7. qNaN
+ // 8. sNaN
+ // 9. +0
+ // 10. -0
+
+ // nextUp(+inf) = +inf.
+ test = APFloat::getInf(APFloat::IEEEquad, false);
+ expected = APFloat::getInf(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isInfinity());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+inf) = -nextUp(-inf) = -(-getLargest()) = getLargest()
+ test = APFloat::getInf(APFloat::IEEEquad, false);
+ expected = APFloat::getLargest(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-inf) = -getLargest()
+ test = APFloat::getInf(APFloat::IEEEquad, true);
+ expected = APFloat::getLargest(APFloat::IEEEquad, true);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-inf) = -nextUp(+inf) = -(+inf) = -inf.
+ test = APFloat::getInf(APFloat::IEEEquad, true);
+ expected = APFloat::getInf(APFloat::IEEEquad, true);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isInfinity() && test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(getLargest()) = +inf
+ test = APFloat::getLargest(APFloat::IEEEquad, false);
+ expected = APFloat::getInf(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isInfinity() && !test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(getLargest()) = -nextUp(-getLargest())
+ // = -(-getLargest() + inc)
+ // = getLargest() - inc.
+ test = APFloat::getLargest(APFloat::IEEEquad, false);
+ expected = APFloat(APFloat::IEEEquad,
+ "0x1.fffffffffffffffffffffffffffep+16383");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(!test.isInfinity() && !test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-getLargest()) = -getLargest() + inc.
+ test = APFloat::getLargest(APFloat::IEEEquad, true);
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.fffffffffffffffffffffffffffep+16383");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-getLargest()) = -nextUp(getLargest()) = -(inf) = -inf.
+ test = APFloat::getLargest(APFloat::IEEEquad, true);
+ expected = APFloat::getInf(APFloat::IEEEquad, true);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isInfinity() && test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(getSmallest()) = getSmallest() + inc.
+ test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x0.0000000000000000000000000002p-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(getSmallest()) = -nextUp(-getSmallest()) = -(-0) = +0.
+ test = APFloat(APFloat::IEEEquad, "0x0.0000000000000000000000000001p-16382");
+ expected = APFloat::getZero(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isZero() && !test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-getSmallest()) = -0.
+ test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
+ expected = APFloat::getZero(APFloat::IEEEquad, true);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isZero() && test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-getSmallest()) = -nextUp(getSmallest()) = -getSmallest() - inc.
+ test = APFloat(APFloat::IEEEquad, "-0x0.0000000000000000000000000001p-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x0.0000000000000000000000000002p-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(qNaN) = qNaN
+ test = APFloat::getQNaN(APFloat::IEEEquad, false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(qNaN) = qNaN
+ test = APFloat::getQNaN(APFloat::IEEEquad, false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(sNaN) = qNaN
+ test = APFloat::getSNaN(APFloat::IEEEquad, false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(false), APFloat::opInvalidOp);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(sNaN) = qNaN
+ test = APFloat::getSNaN(APFloat::IEEEquad, false);
+ expected = APFloat::getQNaN(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(true), APFloat::opInvalidOp);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(+0) = +getSmallest()
+ test = APFloat::getZero(APFloat::IEEEquad, false);
+ expected = APFloat::getSmallest(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+0) = -nextUp(-0) = -getSmallest()
+ test = APFloat::getZero(APFloat::IEEEquad, false);
+ expected = APFloat::getSmallest(APFloat::IEEEquad, true);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-0) = +getSmallest()
+ test = APFloat::getZero(APFloat::IEEEquad, true);
+ expected = APFloat::getSmallest(APFloat::IEEEquad, false);
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-0) = -nextUp(0) = -getSmallest()
+ test = APFloat::getZero(APFloat::IEEEquad, true);
+ expected = APFloat::getSmallest(APFloat::IEEEquad, true);
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // 2. Binade Boundary Tests.
+
+ // 2a. Test denormal <-> normal binade boundaries.
+ // * nextUp(+Largest Denormal) -> +Smallest Normal.
+ // * nextDown(-Largest Denormal) -> -Smallest Normal.
+ // * nextUp(-Smallest Normal) -> -Largest Denormal.
+ // * nextDown(+Smallest Normal) -> +Largest Denormal.
+
+ // nextUp(+Largest Denormal) -> +Smallest Normal.
+ test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x1.0000000000000000000000000000p-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_FALSE(test.isDenormal());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-Largest Denormal) -> -Smallest Normal.
+ test = APFloat(APFloat::IEEEquad,
+ "-0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.0000000000000000000000000000p-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_FALSE(test.isDenormal());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-Smallest Normal) -> -LargestDenormal.
+ test = APFloat(APFloat::IEEEquad,
+ "-0x1.0000000000000000000000000000p-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x0.ffffffffffffffffffffffffffffp-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+Smallest Normal) -> +Largest Denormal.
+ test = APFloat(APFloat::IEEEquad,
+ "+0x1.0000000000000000000000000000p-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "+0x0.ffffffffffffffffffffffffffffp-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // 2b. Test normal <-> normal binade boundaries.
+ // * nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
+ // * nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
+ // * nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
+ // * nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
+
+ // nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
+ test = APFloat(APFloat::IEEEquad, "-0x1p+1");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.ffffffffffffffffffffffffffffp+0");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
+ test = APFloat(APFloat::IEEEquad, "0x1p+1");
+ expected = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
+ test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp+0");
+ expected = APFloat(APFloat::IEEEquad, "0x1p+1");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
+ test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp+0");
+ expected = APFloat(APFloat::IEEEquad, "-0x1p+1");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // 2c. Test using next at binade boundaries with a direction away from the
+ // binade boundary. Away from denormal <-> normal boundaries.
+ //
+ // This is to make sure that even though we are at a binade boundary, since
+ // we are rounding away, we do not trigger the binade boundary code. Thus we
+ // test:
+ // * nextUp(-Largest Denormal) -> -Largest Denormal + inc.
+ // * nextDown(+Largest Denormal) -> +Largest Denormal - inc.
+ // * nextUp(+Smallest Normal) -> +Smallest Normal + inc.
+ // * nextDown(-Smallest Normal) -> -Smallest Normal - inc.
+
+ // nextUp(-Largest Denormal) -> -Largest Denormal + inc.
+ test = APFloat(APFloat::IEEEquad, "-0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x0.fffffffffffffffffffffffffffep-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+Largest Denormal) -> +Largest Denormal - inc.
+ test = APFloat(APFloat::IEEEquad, "0x0.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x0.fffffffffffffffffffffffffffep-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(+Smallest Normal) -> +Smallest Normal + inc.
+ test = APFloat(APFloat::IEEEquad, "0x1.0000000000000000000000000000p-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x1.0000000000000000000000000001p-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(!test.isDenormal());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-Smallest Normal) -> -Smallest Normal - inc.
+ test = APFloat(APFloat::IEEEquad, "-0x1.0000000000000000000000000000p-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.0000000000000000000000000001p-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(!test.isDenormal());
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // 2d. Test values which cause our exponent to go to min exponent. This
+ // is to ensure that guards in the code to check for min exponent
+ // trigger properly.
+ // * nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
+ // * nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
+ // -0x1p-16381
+ // * nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16382
+ // * nextDown(0x1p-16382) -> 0x1.ffffffffffffffffffffffffffffp-16382
+
+ // nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
+ test = APFloat(APFloat::IEEEquad, "-0x1p-16381");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.ffffffffffffffffffffffffffffp-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
+ // -0x1p-16381
+ test = APFloat(APFloat::IEEEquad, "-0x1.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad, "-0x1p-16381");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16381
+ test = APFloat(APFloat::IEEEquad, "0x1.ffffffffffffffffffffffffffffp-16382");
+ expected = APFloat(APFloat::IEEEquad, "0x1p-16381");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(0x1p-16381) -> 0x1.ffffffffffffffffffffffffffffp-16382
+ test = APFloat(APFloat::IEEEquad, "0x1p-16381");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x1.ffffffffffffffffffffffffffffp-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // 3. Now we test both denormal/normal computation which will not cause us
+ // to go across binade boundaries. Specifically we test:
+ // * nextUp(+Denormal) -> +Denormal.
+ // * nextDown(+Denormal) -> +Denormal.
+ // * nextUp(-Denormal) -> -Denormal.
+ // * nextDown(-Denormal) -> -Denormal.
+ // * nextUp(+Normal) -> +Normal.
+ // * nextDown(+Normal) -> +Normal.
+ // * nextUp(-Normal) -> -Normal.
+ // * nextDown(-Normal) -> -Normal.
+
+ // nextUp(+Denormal) -> +Denormal.
+ test = APFloat(APFloat::IEEEquad,
+ "0x0.ffffffffffffffffffffffff000cp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x0.ffffffffffffffffffffffff000dp-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+Denormal) -> +Denormal.
+ test = APFloat(APFloat::IEEEquad,
+ "0x0.ffffffffffffffffffffffff000cp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x0.ffffffffffffffffffffffff000bp-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-Denormal) -> -Denormal.
+ test = APFloat(APFloat::IEEEquad,
+ "-0x0.ffffffffffffffffffffffff000cp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x0.ffffffffffffffffffffffff000bp-16382");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-Denormal) -> -Denormal
+ test = APFloat(APFloat::IEEEquad,
+ "-0x0.ffffffffffffffffffffffff000cp-16382");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x0.ffffffffffffffffffffffff000dp-16382");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(test.isDenormal());
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(+Normal) -> +Normal.
+ test = APFloat(APFloat::IEEEquad,
+ "0x1.ffffffffffffffffffffffff000cp-16000");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x1.ffffffffffffffffffffffff000dp-16000");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(!test.isDenormal());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(+Normal) -> +Normal.
+ test = APFloat(APFloat::IEEEquad,
+ "0x1.ffffffffffffffffffffffff000cp-16000");
+ expected = APFloat(APFloat::IEEEquad,
+ "0x1.ffffffffffffffffffffffff000bp-16000");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(!test.isDenormal());
+ EXPECT_TRUE(!test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextUp(-Normal) -> -Normal.
+ test = APFloat(APFloat::IEEEquad,
+ "-0x1.ffffffffffffffffffffffff000cp-16000");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.ffffffffffffffffffffffff000bp-16000");
+ EXPECT_EQ(test.next(false), APFloat::opOK);
+ EXPECT_TRUE(!test.isDenormal());
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+
+ // nextDown(-Normal) -> -Normal.
+ test = APFloat(APFloat::IEEEquad,
+ "-0x1.ffffffffffffffffffffffff000cp-16000");
+ expected = APFloat(APFloat::IEEEquad,
+ "-0x1.ffffffffffffffffffffffff000dp-16000");
+ EXPECT_EQ(test.next(true), APFloat::opOK);
+ EXPECT_TRUE(!test.isDenormal());
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+}
+
TEST(APFloatTest, FMA) {
APFloat::roundingMode rdmd = APFloat::rmNearestTiesToEven;
More information about the llvm-commits
mailing list