[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