[llvm] 8b44945 - Revert "[APFloat] Properly implement DoubleAPFloat::convertToSignExtendedInteger"

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 10 00:36:35 PDT 2025


Author: Kazu Hirata
Date: 2025-08-10T00:36:29-07:00
New Revision: 8b44945a9231d4d7be0858a1c5d9c13d397bc512

URL: https://github.com/llvm/llvm-project/commit/8b44945a9231d4d7be0858a1c5d9c13d397bc512
DIFF: https://github.com/llvm/llvm-project/commit/8b44945a9231d4d7be0858a1c5d9c13d397bc512.diff

LOG: Revert "[APFloat] Properly implement DoubleAPFloat::convertToSignExtendedInteger"

This reverts commit 052c38be824d9dabb1e8fb64c1c7c3908d786e83.

I'm getting:

llvm/lib/Support/APFloat.cpp:5627:29: error:
use of undeclared identifier 'Parts'
 5627 |     assert(DstPartsCount <= Parts.size() && "Integer too big");
      |                             ^
1 error generated.

Added: 
    

Modified: 
    llvm/include/llvm/ADT/APFloat.h
    llvm/lib/Support/APFloat.cpp
    llvm/unittests/ADT/APFloatTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index a67c05ef2d626..e1589544787cf 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -609,10 +609,29 @@ class IEEEFloat final {
   /// return true.
   LLVM_ABI bool getExactInverse(APFloat *inv) const;
 
+  // If this is an exact power of two, return the exponent while ignoring the
+  // sign bit. If it's not an exact power of 2, return INT_MIN
   LLVM_ABI LLVM_READONLY int getExactLog2Abs() const;
 
+  // If this is an exact power of two, return the exponent. If it's not an exact
+  // power of 2, return INT_MIN
+  LLVM_READONLY
+  int getExactLog2() const {
+    return isNegative() ? INT_MIN : getExactLog2Abs();
+  }
+
+  /// Returns the exponent of the internal representation of the APFloat.
+  ///
+  /// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)).
+  /// For special APFloat values, this returns special error codes:
+  ///
+  ///   NaN -> \c IEK_NaN
+  ///   0   -> \c IEK_Zero
+  ///   Inf -> \c IEK_Inf
+  ///
   LLVM_ABI friend int ilogb(const IEEEFloat &Arg);
 
+  /// Returns: X * 2^Exp for integral exponents.
   LLVM_ABI friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode);
 
   LLVM_ABI friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode);
@@ -787,17 +806,7 @@ class IEEEFloat final {
 };
 
 LLVM_ABI hash_code hash_value(const IEEEFloat &Arg);
-/// Returns the exponent of the internal representation of the APFloat.
-///
-/// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)).
-/// For special APFloat values, this returns special error codes:
-///
-///   NaN -> \c IEK_NaN
-///   0   -> \c IEK_Zero
-///   Inf -> \c IEK_Inf
-///
 LLVM_ABI int ilogb(const IEEEFloat &Arg);
-/// Returns: X * 2^Exp for integral exponents.
 LLVM_ABI IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode);
 LLVM_ABI IEEEFloat frexp(const IEEEFloat &Val, int &Exp, roundingMode RM);
 
@@ -815,9 +824,6 @@ class DoubleAPFloat final {
 
   opStatus addWithSpecial(const DoubleAPFloat &LHS, const DoubleAPFloat &RHS,
                           DoubleAPFloat &Out, roundingMode RM);
-  opStatus convertToSignExtendedInteger(MutableArrayRef<integerPart> Input,
-                                        unsigned int Width, bool IsSigned,
-                                        roundingMode RM, bool *IsExact) const;
 
 public:
   LLVM_ABI DoubleAPFloat(const fltSemantics &S);
@@ -898,9 +904,9 @@ class DoubleAPFloat final {
 
   LLVM_ABI bool getExactInverse(APFloat *inv) const;
 
+  LLVM_ABI LLVM_READONLY int getExactLog2() const;
   LLVM_ABI LLVM_READONLY int getExactLog2Abs() const;
 
-  LLVM_ABI friend int ilogb(const DoubleAPFloat &X);
   LLVM_ABI friend DoubleAPFloat scalbn(const DoubleAPFloat &X, int Exp,
                                        roundingMode);
   LLVM_ABI friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp,
@@ -1339,23 +1345,12 @@ class APFloat : public APFloatBase {
 
   LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
                             bool *losesInfo);
-  // Convert a floating point number to an integer according to the
-  // rounding mode.  We provide deterministic values in case of an invalid
-  // operation exception, namely zero for NaNs and the minimal or maximal value
-  // respectively for underflow or overflow.
-  // The *IsExact output tells whether the result is exact, in the sense that
-  // converting it back to the original floating point type produces the
-  // original value.  This is almost equivalent to result==opOK, except for
-  // negative zeroes.
   opStatus convertToInteger(MutableArrayRef<integerPart> Input,
                             unsigned int Width, bool IsSigned, roundingMode RM,
                             bool *IsExact) const {
     APFLOAT_DISPATCH_ON_SEMANTICS(
         convertToInteger(Input, Width, IsSigned, RM, IsExact));
   }
-  // Same as convertToInteger(integerPart*, ...), except the result is returned
-  // in an APSInt, whose initial bit-width and signed-ness are used to determine
-  // the precision of the conversion.
   LLVM_ABI opStatus convertToInteger(APSInt &Result, roundingMode RM,
                                      bool *IsExact) const;
   opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
@@ -1514,28 +1509,18 @@ class APFloat : public APFloatBase {
     APFLOAT_DISPATCH_ON_SEMANTICS(getExactInverse(inv));
   }
 
-  // If this is an exact power of two, return the exponent while ignoring the
-  // sign bit. If it's not an exact power of 2, return INT_MIN
   LLVM_READONLY
   int getExactLog2Abs() const {
     APFLOAT_DISPATCH_ON_SEMANTICS(getExactLog2Abs());
   }
 
-  // If this is an exact power of two, return the exponent. If it's not an exact
-  // power of 2, return INT_MIN
   LLVM_READONLY
   int getExactLog2() const {
-    return isNegative() ? INT_MIN : getExactLog2Abs();
+    APFLOAT_DISPATCH_ON_SEMANTICS(getExactLog2());
   }
 
   LLVM_ABI friend hash_code hash_value(const APFloat &Arg);
-  friend int ilogb(const APFloat &Arg) {
-    if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics()))
-      return ilogb(Arg.getIEEE());
-    if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics()))
-      return ilogb(Arg.getIEEE());
-    llvm_unreachable("Unexpected semantics");
-  }
+  friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
   friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
   friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
   friend IEEEFloat;

diff  --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 6933e65cc1785..3d688a109cdee 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -5519,127 +5519,13 @@ APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
   return opOK;
 }
 
-APFloat::opStatus DoubleAPFloat::convertToSignExtendedInteger(
-    MutableArrayRef<integerPart> Input, unsigned int Width, bool IsSigned,
-    roundingMode RM, bool *IsExact) const {
-  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
-
-  // If Hi is not finite, or Lo is zero, the value is entirely represented
-  // by Hi. Delegate to the simpler single-APFloat conversion.
-  if (!getFirst().isFiniteNonZero() || getSecond().isZero())
-    return getFirst().convertToInteger(Input, Width, IsSigned, RM, IsExact);
-
-  // First, round the full double-double value to an integral value. This
-  // simplifies the rest of the function, as we no longer need to consider
-  // fractional parts.
-  *IsExact = false;
-  DoubleAPFloat Integral = *this;
-  const opStatus RoundStatus = Integral.roundToIntegral(RM);
-  if (RoundStatus == opInvalidOp)
-    return RoundStatus;
-  const APFloat &IntegralHi = Integral.getFirst();
-  const APFloat &IntegralLo = Integral.getSecond();
-
-  // If rounding results in either component being zero, the sum is trivial.
-  // Delegate to the simpler single-APFloat conversion.
-  bool HiIsExact;
-  if (IntegralHi.isZero() || IntegralLo.isZero()) {
-    const opStatus HiStatus =
-        IntegralHi.convertToInteger(Input, Width, IsSigned, RM, &HiIsExact);
-    // The conversion from an integer-valued float to an APInt may fail if the
-    // result would be out of range.  Regardless, taking this path is only
-    // possible if rounding occured during the initial `roundToIntegral`.
-    return HiStatus == opOK ? opInexact : HiStatus;
-  }
-
-  // A negative number cannot be represented by an unsigned integer.
-  // Since a double-double is canonical, if Hi is negative, the sum is negative.
-  if (!IsSigned && IntegralHi.isNegative())
-    return opInvalidOp;
-
-  // Handle the special boundary case where |Hi| is exactly the power of two
-  // that marks the edge of the integer's range (e.g., 2^63 for int64_t). In
-  // this situation, Hi itself won't fit, but the sum Hi + Lo might.
-  // `PositiveOverflowWidth` is the bit number for this boundary (N-1 for
-  // signed, N for unsigned).
-  bool LoIsExact;
-  const int HiExactLog2 = IntegralHi.getExactLog2Abs();
-  const unsigned PositiveOverflowWidth = IsSigned ? Width - 1 : Width;
-  if (HiExactLog2 >= 0 &&
-      static_cast<unsigned>(HiExactLog2) == PositiveOverflowWidth) {
-    // If Hi and Lo have the same sign, |Hi + Lo| > |Hi|, so the sum is
-    // guaranteed to overflow. E.g., for uint128_t, (2^128, 1) overflows.
-    if (IntegralHi.isNegative() == IntegralLo.isNegative())
-      return opInvalidOp;
-
-    // If the signs 
diff er, the sum will fit. We can compute the result using
-    // properties of two's complement arithmetic without a wide intermediate
-    // integer. E.g., for uint128_t, (2^128, -1) should be 2^128 - 1.
-    [[maybe_unused]] opStatus LoStatus = IntegralLo.convertToInteger(
-        Input, Width, /*IsSigned=*/true, RM, &LoIsExact);
-    assert(LoStatus == opOK && "Unexpected failure");
-
-    // Adjust the bit pattern of Lo to account for Hi's value:
-    //  - For unsigned (Hi=2^Width): `2^Width + Lo` in `Width`-bit
-    //    arithmetic is equivalent to just `Lo`. The conversion of `Lo` above
-    //    already produced the correct final bit pattern.
-    //  - For signed (Hi=2^(Width-1)): The sum `2^(Width-1) + Lo` (where Lo<0)
-    //    can be computed by taking the two's complement pattern for `Lo` and
-    //    clearing the sign bit.
-    if (IsSigned && !IntegralHi.isNegative())
-      APInt::tcClearBit(Input.data(), PositiveOverflowWidth);
-    *IsExact = RoundStatus == opOK;
-    return RoundStatus;
-  }
-
-  // General case: Hi is not a power-of-two boundary, so we know it fits.
-  // Since we already rounded the full value, we now just need to convert the
-  // components to integers.  The rounding mode should not matter.
-  [[maybe_unused]] opStatus HiStatus = IntegralHi.convertToInteger(
-      Input, Width, IsSigned, rmTowardZero, &HiIsExact);
-  assert(HiStatus == opOK && "Unexpected failure");
-
-  // Convert Lo into a temporary integer of the same width.
-  APSInt LoResult{Width, /*isUnsigned=*/!IsSigned};
-  [[maybe_unused]] opStatus LoStatus =
-      IntegralLo.convertToInteger(LoResult, rmTowardZero, &LoIsExact);
-  assert(LoStatus == opOK && "Unexpected failure");
-
-  // Add Lo to Hi. This addition is guaranteed not to overflow because of the
-  // double-double canonicalization rule (`|Lo| <= ulp(Hi)/2`). The only case
-  // where the sum could cross the integer type's boundary is when Hi is a
-  // power of two, which is handled by the special case block above.
-  APInt::tcAdd(Input.data(), LoResult.getRawData(), /*carry=*/0, Input.size());
-
-  *IsExact = RoundStatus == opOK;
-  return RoundStatus;
-}
-
 APFloat::opStatus
 DoubleAPFloat::convertToInteger(MutableArrayRef<integerPart> Input,
                                 unsigned int Width, bool IsSigned,
                                 roundingMode RM, bool *IsExact) const {
-  opStatus FS =
-      convertToSignExtendedInteger(Input, Width, IsSigned, RM, IsExact);
-
-  if (FS == opInvalidOp) {
-    const unsigned DstPartsCount = partCountForBits(Width);
-    assert(DstPartsCount <= Parts.size() && "Integer too big");
-
-    unsigned Bits;
-    if (getCategory() == fcNaN)
-      Bits = 0;
-    else if (isNegative())
-      Bits = IsSigned;
-    else
-      Bits = Width - IsSigned;
-
-    tcSetLeastSignificantBits(Input.data(), DstPartsCount, Bits);
-    if (isNegative() && IsSigned)
-      APInt::tcShiftLeft(Input.data(), DstPartsCount, Width - 1);
-  }
-
-  return FS;
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+      .convertToInteger(Input, Width, IsSigned, RM, IsExact);
 }
 
 APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input,
@@ -5740,31 +5626,14 @@ bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
   return Ret;
 }
 
+int DoubleAPFloat::getExactLog2() const {
+  // TODO: Implement me
+  return INT_MIN;
+}
+
 int DoubleAPFloat::getExactLog2Abs() const {
-  // In order for Hi + Lo to be a power of two, the following must be true:
-  // 1. Hi must be a power of two.
-  // 2. Lo must be zero.
-  if (getSecond().isNonZero())
-    return INT_MIN;
-  return getFirst().getExactLog2Abs();
-}
-
-int ilogb(const DoubleAPFloat& Arg) {
-  const APFloat& Hi = Arg.getFirst();
-  const APFloat& Lo = Arg.getSecond();
-  int IlogbResult = ilogb(Hi);
-  // Zero and non-finite values can delegate to ilogb(Hi).
-  if (Arg.getCategory() != fcNormal)
-    return IlogbResult;
-  // If Lo can't change the binade, we can delegate to ilogb(Hi).
-  if (Lo.isZero() ||
-      Hi.isNegative() == Lo.isNegative())
-    return IlogbResult;
-  if (Hi.getExactLog2Abs() == INT_MIN)
-    return IlogbResult;
-  // Numbers of the form 2^a - 2^b or -2^a + 2^b are almost powers of two but
-  // get nudged out of the binade by the low component.
-  return IlogbResult - 1;
+  // TODO: Implement me
+  return INT_MIN;
 }
 
 DoubleAPFloat scalbn(const DoubleAPFloat &Arg, int Exp,
@@ -5880,6 +5749,10 @@ void APFloat::Profile(FoldingSetNodeID &NID) const {
   NID.Add(bitcastToAPInt());
 }
 
+/* Same as convertToInteger(integerPart*, ...), except the result is returned in
+   an APSInt, whose initial bit-width and signed-ness are used to determine the
+   precision of the conversion.
+ */
 APFloat::opStatus APFloat::convertToInteger(APSInt &result,
                                             roundingMode rounding_mode,
                                             bool *isExact) const {

diff  --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index 3fcd7ecc2eb2c..a35594d4afed4 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -5799,359 +5799,6 @@ TEST_P(PPCDoubleDoubleRoundToIntegralValueTest,
   }
 }
 
-namespace PPCDoubleDoubleConvertToIntegerTestDetails {
-// Define the rounding modes for easier readability.
-static constexpr auto RNE = APFloat::rmNearestTiesToEven;
-static constexpr auto RNA = APFloat::rmNearestTiesToAway;
-static constexpr auto RTZ = APFloat::rmTowardZero;
-static constexpr auto RTP = APFloat::rmTowardPositive;
-static constexpr auto RTN = APFloat::rmTowardNegative;
-
-struct TestCase {
-  // Structure to hold the expected result of a conversion
-  struct ExpectedConversion {
-    // The expected integer value represented as a string (decimal).
-    // We use a string to easily represent arbitrary precision values in
-    // constexpr. The test runner should parse this into an APSInt matching the
-    // test configuration.
-    const char *ExpectedIntStr;
-    APFloat::opStatus Status;
-  };
-
-  DD Input;
-  unsigned IntegerWidth;
-  bool IsSigned;
-  // Array indexed by the rounding mode enum value.
-  std::array<ExpectedConversion, 5> Rounded = {};
-
-  // Helper to define the expected results for a specific rounding mode.
-  constexpr TestCase &with(APFloat::roundingMode RM, const char *ExpectedStr,
-                           APFloat::opStatus Status) {
-    Rounded[static_cast<std::underlying_type_t<APFloat::roundingMode>>(RM)] = {
-        ExpectedStr,
-        Status,
-    };
-    return *this;
-  }
-
-  // Helper to define the same result for all rounding modes.
-  constexpr TestCase &withAll(const char *ExpectedStr,
-                              APFloat::opStatus Status) {
-    return with(RNE, ExpectedStr, Status)
-        .with(RNA, ExpectedStr, Status)
-        .with(RTZ, ExpectedStr, Status)
-        .with(RTP, ExpectedStr, Status)
-        .with(RTN, ExpectedStr, Status);
-  }
-};
-
-auto testCases() {
-  // Define the status codes.
-  constexpr auto OK = llvm::APFloat::opOK;
-  constexpr auto Inexact = llvm::APFloat::opInexact;
-  // The API specifies opInvalidOp for out-of-range (overflow/underflow) and
-  // NaN.
-  constexpr auto Invalid = llvm::APFloat::opInvalidOp;
-
-  // Helper constants for constructing specific DD values.
-  constexpr double Infinity = std::numeric_limits<double>::infinity();
-  constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
-  constexpr double DMAX = std::numeric_limits<double>::max();
-
-  // Powers of 2
-  constexpr double P53 = 0x1p53;
-  constexpr double P63 = 0x1p63;
-  constexpr double P64 = 0x1p64;
-  // 2^-100 (A very small delta demonstrating extended precision)
-  constexpr double PM100 = 0x1p-100;
-
-  static constexpr auto ConvertToIntegerTestCases = std::array{
-      // 1. Zeros, NaNs, and Infinities (Target: 64-bit Signed)
-      // INT64_MAX = 9223372036854775807
-      // INT64_MIN = -9223372036854775808
-
-      // Input: Positive Zero (0.0, 0.0)
-      TestCase{{0.0, 0.0}, 64, true}.withAll("0", OK),
-
-      // Input: Negative Zero (-0.0, 0.0)
-      TestCase{{-0.0, 0.0}, 64, true}.withAll("0", OK),
-
-      // Input: NaN. Expected behavior: Invalid, deterministic result of 0.
-      TestCase{{NaN, 0.0}, 64, true}.withAll("0", Invalid),
-
-      // Input: +Infinity. Expected behavior: Invalid, deterministic result of
-      // INT64_MAX.
-      TestCase{{Infinity, 0.0}, 64, true}.withAll("9223372036854775807",
-                                                  Invalid),
-
-      // Input: -Infinity. Expected behavior: Invalid, deterministic result of
-      // INT64_MIN.
-      TestCase{{-Infinity, 0.0}, 64, true}.withAll("-9223372036854775808",
-                                                   Invalid),
-
-      // 2. Basic Rounding and Tie-Breaking (Target: 32-bit Signed)
-
-      // Input: 2.5 (Tie, preceding integer is Even)
-      TestCase{{2.5, 0.0}, 32, true}
-          .with(RTZ, "2", Inexact)
-          .with(RTN, "2", Inexact)
-          .with(RTP, "3", Inexact)
-          .with(RNA, "3", Inexact)
-          .with(RNE, "2", Inexact),
-
-      // Input: 3.5 (Tie, preceding integer is Odd)
-      TestCase{{3.5, 0.0}, 32, true}
-          .with(RTZ, "3", Inexact)
-          .with(RTN, "3", Inexact)
-          .with(RTP, "4", Inexact)
-          .with(RNA, "4", Inexact)
-          .with(RNE, "4", Inexact),
-
-      // Input: -2.5 (Tie, preceding integer is Even)
-      TestCase{{-2.5, 0.0}, 32, true}
-          .with(RTZ, "-2", Inexact)
-          .with(RTN, "-3", Inexact)
-          .with(RTP, "-2", Inexact)
-          .with(RNA, "-3", Inexact)
-          .with(RNE, "-2", Inexact),
-
-      // 3. Double-Double Precision (The role of 'lo')
-      // Testing how extended precision affects rounding decisions.
-
-      // Input: 2.5 + Epsilon (Slightly above tie)
-      TestCase{{2.5, PM100}, 32, true}
-          .with(RTZ, "2", Inexact)
-          .with(RTN, "2", Inexact)
-          .with(RTP, "3", Inexact)
-          .with(RNA, "3", Inexact)
-          .with(RNE, "3", Inexact),
-
-      // Input: 2.5 - Epsilon (Slightly below tie)
-      TestCase{{2.5, -PM100}, 32, true}
-          .with(RTZ, "2", Inexact)
-          .with(RTN, "2", Inexact)
-          .with(RTP, "3", Inexact)
-          .with(RNA, "2", Inexact)
-          .with(RNE, "2", Inexact),
-
-      // Input: 1.0 + Epsilon (Just above 1.0, e.g., 1.00...1)
-      TestCase{{1.0, PM100}, 32, true}
-          .with(RTZ, "1", Inexact)
-          .with(RTN, "1", Inexact)
-          .with(RTP, "2", Inexact)
-          .with(RNA, "1", Inexact)
-          .with(RNE, "1", Inexact),
-
-      // Input: 1.0 - Epsilon (Just below 1.0, e.g. 0.999...)
-      TestCase{{1.0, -PM100}, 32, true}
-          .with(RTZ, "0", Inexact)
-          .with(RTN, "0", Inexact)
-          .with(RTP, "1", Inexact)
-          .with(RNA, "1", Inexact)
-          .with(RNE, "1", Inexact),
-
-      // Input: Large number tie-breaking (Crucial test for DD implementation)
-      // Input: 2^53 + 1.5.
-      // A standard double(2^53 + 1.5) rounds to 2^53 + 2.0.
-      // The DD representation must precisely hold 2^53 + 1.5.
-      // The canonical DD representation is {2^53 + 2.0, -0.5}.
-      // Value is 9007199254740993.5
-      TestCase{{P53 + 2.0, -0.5}, 64, true}
-          .with(RTZ, "9007199254740993", Inexact)
-          .with(RTN, "9007199254740993", Inexact)
-          .with(RTP, "9007199254740994", Inexact)
-          .with(RNA, "9007199254740994", Inexact)
-          .with(RNE, "9007199254740994", Inexact),
-
-      // 4. Overflow Boundaries (Signed)
-
-      // Input: Exactly INT64_MAX. (2^63 - 1)
-      // Represented precisely as (2^63, -1.0)
-      TestCase{{P63, -1.0}, 64, true}.withAll("9223372036854775807", OK),
-
-      // Input: INT64_MAX + 0.3.
-      // Represented as (2^63, -0.7)
-      TestCase{{P63, -0.7}, 64, true}
-          .with(RTZ, "9223372036854775807", Inexact)
-          .with(RTN, "9223372036854775807", Inexact)
-          .with(RNA, "9223372036854775807", Inexact)
-          .with(RNE, "9223372036854775807", Inexact)
-          .with(RTP, "9223372036854775807", Invalid),
-
-      // Input: INT64_MAX + 0.5 (Tie at the boundary)
-      // Represented as (2^63, -0.5). Target integers are MAX (odd) and 2^63
-      // (even).
-      TestCase{{P63, -0.5}, 64, true}
-          .with(RTZ, "9223372036854775807", Inexact)
-          .with(RTN, "9223372036854775807", Inexact)
-          .with(RTP, "9223372036854775807", Invalid)
-          .with(RNA, "9223372036854775807", Invalid)
-          .with(RNE, "9223372036854775807", Invalid),
-
-      // Input: 2^55 - 2^1 - 2^-52 to signed integer.
-      // Represented as (2^55 - 2^2, 2^1 - 2^-1).
-      TestCase{{0x1.fffffffffffffp+54, 0x1.8p0}, 56, true}
-          .with(RTZ, "36028797018963965", Inexact)
-          .with(RTN, "36028797018963965", Inexact)
-          .with(RTP, "36028797018963966", Inexact)
-          .with(RNA, "36028797018963966", Inexact)
-          .with(RNE, "36028797018963966", Inexact),
-
-      // Input: 2^55 - 2^1 - 2^-52 to signed integer.
-      // Represented as (2^55 - 2^2, 2^1 - 2^-52).
-      TestCase{{0x1.fffffffffffffp+54, 0x1.fffffffffffffp0}, 56, true}
-          .with(RTZ, "36028797018963965", Inexact)
-          .with(RTN, "36028797018963965", Inexact)
-          .with(RTP, "36028797018963966", Inexact)
-          .with(RNA, "36028797018963966", Inexact)
-          .with(RNE, "36028797018963966", Inexact),
-
-      // Input: Exactly 2^63 (One past INT64_MAX)
-      TestCase{{P63, 0.0}, 64, true}.withAll("9223372036854775807", Invalid),
-
-      // Input: Exactly INT64_MIN (-2^63)
-      TestCase{{-P63, 0.0}, 64, true}.withAll("-9223372036854775808", OK),
-
-      // Input: INT64_MIN - 0.5 (Tie at the lower boundary)
-      // Target integers are -2^63-1 (odd) and MIN (even).
-      TestCase{{-P63, -0.5}, 64, true}
-          .with(RTZ, "-9223372036854775808", Inexact)
-          .with(RTP, "-9223372036854775808", Inexact)
-          // RTN rounds down, causing overflow.
-          .with(RTN, "-9223372036854775808", Invalid)
-          // RNA rounds away (down), causing overflow.
-          .with(RNA, "-9223372036854775808", Invalid)
-          // RNE rounds to even (up to -2^63), which is OK.
-          .with(RNE, "-9223372036854775808", Inexact),
-
-      // 5. Overflow Boundaries (Unsigned)
-      // UINT64_MAX = 18446744073709551615 (2^64 - 1)
-
-      // Input: Exactly UINT64_MAX. (2^64 - 1)
-      // Represented precisely as (2^64, -1.0)
-      TestCase{{P64, -1.0}, 64, false}.withAll("18446744073709551615", OK),
-
-      // Input: UINT64_MAX + 0.5 (Tie at the boundary)
-      // Represented as (2^64, -0.5)
-      TestCase{{P64, -0.5}, 64, false}
-          .with(RTZ, "18446744073709551615", Inexact)
-          .with(RTN, "18446744073709551615", Inexact)
-          // RTP rounds up (2^64), causing overflow.
-          .with(RTP, "18446744073709551615", Invalid)
-          // RNA rounds away (up), causing overflow.
-          .with(RNA, "18446744073709551615", Invalid)
-          // RNE rounds to even (up to 2^64), causing overflow.
-          .with(RNE, "18446744073709551615", Invalid),
-
-      // Input: 2^55 - 2^1 - 2^-52 to unsigned integer.
-      // Represented as (2^55 - 2^2, 2^1 - 2^-1).
-      TestCase{{0x1.fffffffffffffp+54, 0x1.8p0}, 55, false}
-          .with(RTZ, "36028797018963965", Inexact)
-          .with(RTN, "36028797018963965", Inexact)
-          .with(RTP, "36028797018963966", Inexact)
-          .with(RNA, "36028797018963966", Inexact)
-          .with(RNE, "36028797018963966", Inexact),
-
-      // Input: 2^55 - 2^1 - 2^-52 to unsigned integer.
-      // Represented as (2^55 - 2^2, 2^1 - 2^-52).
-      TestCase{{0x1.fffffffffffffp+54, 0x1.fffffffffffffp0}, 55, false}
-          .with(RTZ, "36028797018963965", Inexact)
-          .with(RTN, "36028797018963965", Inexact)
-          .with(RTP, "36028797018963966", Inexact)
-          .with(RNA, "36028797018963966", Inexact)
-          .with(RNE, "36028797018963966", Inexact),
-
-      // Input: -0.3 (Slightly below zero)
-      TestCase{{-0.3, 0.0}, 64, false}
-          .with(RTZ, "0", Inexact)
-          .with(RTP, "0", Inexact)
-          .with(RNA, "0", Inexact)
-          .with(RNE, "0", Inexact)
-          .with(RTN, "0", Invalid),
-
-      // Input: -0.5 (Tie at zero)
-      TestCase{{-0.5, 0.0}, 64, false}
-          .with(RTZ, "0", Inexact)
-          .with(RTP, "0", Inexact)
-          // RNE rounds to even (0).
-          .with(RNE, "0", Inexact)
-          .with(RTN, "0", Invalid)
-          // RNA rounds away (-1), causing overflow.
-          .with(RNA, "0", Invalid),
-
-      // Input: -1.0 (Negative integer)
-      TestCase{{-1.0, 0.0}, 64, false}.withAll("0", Invalid),
-
-      // 6. High Precision Integers (Target: 128-bit Signed)
-      // INT128_MAX = 170141183460469231731687303715884105727
-
-      // Input: 2^100 (Exactly representable in DD)
-      // 2^100 = 1267650600228229401496703205376.0
-      TestCase{{1267650600228229401496703205376.0, 0.0}, 128, true}.withAll(
-          "1267650600228229401496703205376", OK),
-
-      // Input: DMAX. (Approx 1.8e308).
-      // This is vastly larger than INT128_MAX (Approx 1.7e38).
-      TestCase{{DMAX, 0.0}, 128, true}.withAll(
-          "170141183460469231731687303715884105727", Invalid),
-
-      // 7. Round to negative -0
-      TestCase{{-PM100, 0.0}, 32, true}
-          .with(RTZ, "0", Inexact)
-          .with(RTP, "0", Inexact)
-          .with(RNA, "0", Inexact)
-          .with(RNE, "0", Inexact)
-          .with(RTN, "-1", Inexact),
-  };
-  return ConvertToIntegerTestCases;
-}
-} // namespace PPCDoubleDoubleConvertToIntegerTestDetails
-
-class PPCDoubleDoubleConvertToIntegerValueTest
-    : public testing::Test,
-      public ::testing::WithParamInterface<
-          PPCDoubleDoubleConvertToIntegerTestDetails::TestCase> {};
-
-INSTANTIATE_TEST_SUITE_P(
-    PPCDoubleDoubleConvertToIntegerValueParamTests,
-    PPCDoubleDoubleConvertToIntegerValueTest,
-    ::testing::ValuesIn(
-        PPCDoubleDoubleConvertToIntegerTestDetails::testCases()));
-
-TEST_P(PPCDoubleDoubleConvertToIntegerValueTest,
-       PPCDoubleDoubleConvertToInteger) {
-  const PPCDoubleDoubleConvertToIntegerTestDetails::TestCase Params =
-      GetParam();
-  const APFloat Input = makeDoubleAPFloat(Params.Input);
-  EXPECT_FALSE(Input.isDenormal())
-      << Params.Input.Hi << " + " << Params.Input.Lo;
-
-  for (size_t I = 0, E = std::size(Params.Rounded); I != E; ++I) {
-    const auto RM = static_cast<APFloat::roundingMode>(I);
-    const auto &Expected = Params.Rounded[I];
-    APSInt ActualInteger(Params.IntegerWidth, /*isUnsigned=*/!Params.IsSigned);
-
-    APSInt ExpectedInteger{Expected.ExpectedIntStr};
-    EXPECT_LE(ExpectedInteger.getBitWidth(), Params.IntegerWidth);
-    ExpectedInteger = ExpectedInteger.extend(Params.IntegerWidth);
-    if (ExpectedInteger.isUnsigned() && Params.IsSigned) {
-      ExpectedInteger.setIsSigned(Params.IsSigned);
-      EXPECT_FALSE(ExpectedInteger.isNegative());
-    }
-
-    const bool NegativeUnderflow =
-        ExpectedInteger.isZero() && Input.isNegative();
-    const bool ExpectedIsExact =
-        Expected.Status == APFloat::opOK && !NegativeUnderflow;
-    bool ActualIsExact;
-    const auto ActualStatus =
-        Input.convertToInteger(ActualInteger, RM, &ActualIsExact);
-    EXPECT_EQ(ActualStatus, Expected.Status);
-    EXPECT_EQ(ActualIsExact, ExpectedIsExact);
-    EXPECT_EQ(ActualInteger, ExpectedInteger);
-  }
-}
-
 TEST(APFloatTest, PPCDoubleDoubleCompare) {
   using DataType =
       std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, APFloat::cmpResult>;
@@ -8612,8 +8259,13 @@ TEST(APFloatTest, getExactLog2) {
       continue;
 
     APFloat One(Semantics, "1.0");
-    APFloat Smallest = APFloat::getSmallest(Semantics);
-    APFloat Largest = APFloat::getLargest(Semantics);
+
+    if (I == APFloat::S_PPCDoubleDouble) {
+      // Not implemented
+      EXPECT_EQ(INT_MIN, One.getExactLog2());
+      EXPECT_EQ(INT_MIN, One.getExactLog2Abs());
+      continue;
+    }
 
     int MinExp = APFloat::semanticsMinExponent(Semantics);
     int MaxExp = APFloat::semanticsMaxExponent(Semantics);
@@ -8660,15 +8312,16 @@ TEST(APFloatTest, getExactLog2) {
       EXPECT_EQ(INT_MIN, APFloat::getNaN(Semantics, true).getExactLog2Abs());
     }
 
+    EXPECT_EQ(INT_MIN,
+              scalbn(One, MinExp - Precision - 1, APFloat::rmNearestTiesToEven)
+                  .getExactLog2());
+    EXPECT_EQ(INT_MIN,
+              scalbn(One, MinExp - Precision, APFloat::rmNearestTiesToEven)
+                  .getExactLog2());
+
     EXPECT_EQ(
         INT_MIN,
-        scalbn(Smallest, -2, APFloat::rmNearestTiesToEven).getExactLog2());
-    EXPECT_EQ(
-        INT_MIN,
-        scalbn(Smallest, -1, APFloat::rmNearestTiesToEven).getExactLog2());
-
-    EXPECT_EQ(INT_MIN,
-              scalbn(Largest, 1, APFloat::rmNearestTiesToEven).getExactLog2());
+        scalbn(One, MaxExp + 1, APFloat::rmNearestTiesToEven).getExactLog2());
 
     for (int i = MinExp - Precision + 1; i <= MaxExp; ++i) {
       EXPECT_EQ(i, scalbn(One, i, APFloat::rmNearestTiesToEven).getExactLog2());


        


More information about the llvm-commits mailing list