@@ -5519,13 +5519,127 @@ APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
55195519 return opOK;
55205520}
55215521
5522+ APFloat::opStatus DoubleAPFloat::convertToSignExtendedInteger (
5523+ MutableArrayRef<integerPart> Input, unsigned int Width, bool IsSigned,
5524+ roundingMode RM, bool *IsExact) const {
5525+ assert (Semantics == &semPPCDoubleDouble && " Unexpected Semantics" );
5526+
5527+ // If Hi is not finite, or Lo is zero, the value is entirely represented
5528+ // by Hi. Delegate to the simpler single-APFloat conversion.
5529+ if (!getFirst ().isFiniteNonZero () || getSecond ().isZero ())
5530+ return getFirst ().convertToInteger (Input, Width, IsSigned, RM, IsExact);
5531+
5532+ // First, round the full double-double value to an integral value. This
5533+ // simplifies the rest of the function, as we no longer need to consider
5534+ // fractional parts.
5535+ *IsExact = false ;
5536+ DoubleAPFloat Integral = *this ;
5537+ const opStatus RoundStatus = Integral.roundToIntegral (RM);
5538+ if (RoundStatus == opInvalidOp)
5539+ return RoundStatus;
5540+ const APFloat &IntegralHi = Integral.getFirst ();
5541+ const APFloat &IntegralLo = Integral.getSecond ();
5542+
5543+ // If rounding results in either component being zero, the sum is trivial.
5544+ // Delegate to the simpler single-APFloat conversion.
5545+ bool HiIsExact;
5546+ if (IntegralHi.isZero () || IntegralLo.isZero ()) {
5547+ const opStatus HiStatus =
5548+ IntegralHi.convertToInteger (Input, Width, IsSigned, RM, &HiIsExact);
5549+ // The conversion from an integer-valued float to an APInt may fail if the
5550+ // result would be out of range. Regardless, taking this path is only
5551+ // possible if rounding occured during the initial `roundToIntegral`.
5552+ return HiStatus == opOK ? opInexact : HiStatus;
5553+ }
5554+
5555+ // A negative number cannot be represented by an unsigned integer.
5556+ // Since a double-double is canonical, if Hi is negative, the sum is negative.
5557+ if (!IsSigned && IntegralHi.isNegative ())
5558+ return opInvalidOp;
5559+
5560+ // Handle the special boundary case where |Hi| is exactly the power of two
5561+ // that marks the edge of the integer's range (e.g., 2^63 for int64_t). In
5562+ // this situation, Hi itself won't fit, but the sum Hi + Lo might.
5563+ // `PositiveOverflowWidth` is the bit number for this boundary (N-1 for
5564+ // signed, N for unsigned).
5565+ bool LoIsExact;
5566+ const int HiExactLog2 = IntegralHi.getExactLog2Abs ();
5567+ const unsigned PositiveOverflowWidth = IsSigned ? Width - 1 : Width;
5568+ if (HiExactLog2 >= 0 &&
5569+ static_cast <unsigned >(HiExactLog2) == PositiveOverflowWidth) {
5570+ // If Hi and Lo have the same sign, |Hi + Lo| > |Hi|, so the sum is
5571+ // guaranteed to overflow. E.g., for uint128_t, (2^128, 1) overflows.
5572+ if (IntegralHi.isNegative () == IntegralLo.isNegative ())
5573+ return opInvalidOp;
5574+
5575+ // If the signs differ, the sum will fit. We can compute the result using
5576+ // properties of two's complement arithmetic without a wide intermediate
5577+ // integer. E.g., for uint128_t, (2^128, -1) should be 2^128 - 1.
5578+ [[maybe_unused]] opStatus LoStatus = IntegralLo.convertToInteger (
5579+ Input, Width, /* IsSigned=*/ true , RM, &LoIsExact);
5580+ assert (LoStatus == opOK && " Unexpected failure" );
5581+
5582+ // Adjust the bit pattern of Lo to account for Hi's value:
5583+ // - For unsigned (Hi=2^Width): `2^Width + Lo` in `Width`-bit
5584+ // arithmetic is equivalent to just `Lo`. The conversion of `Lo` above
5585+ // already produced the correct final bit pattern.
5586+ // - For signed (Hi=2^(Width-1)): The sum `2^(Width-1) + Lo` (where Lo<0)
5587+ // can be computed by taking the two's complement pattern for `Lo` and
5588+ // clearing the sign bit.
5589+ if (IsSigned && !IntegralHi.isNegative ())
5590+ APInt::tcClearBit (Input.data (), PositiveOverflowWidth);
5591+ *IsExact = RoundStatus == opOK;
5592+ return RoundStatus;
5593+ }
5594+
5595+ // General case: Hi is not a power-of-two boundary, so we know it fits.
5596+ // Since we already rounded the full value, we now just need to convert the
5597+ // components to integers. The rounding mode should not matter.
5598+ [[maybe_unused]] opStatus HiStatus = IntegralHi.convertToInteger (
5599+ Input, Width, IsSigned, rmTowardZero, &HiIsExact);
5600+ assert (HiStatus == opOK && " Unexpected failure" );
5601+
5602+ // Convert Lo into a temporary integer of the same width.
5603+ APSInt LoResult{Width, /* isUnsigned=*/ !IsSigned};
5604+ [[maybe_unused]] opStatus LoStatus =
5605+ IntegralLo.convertToInteger (LoResult, rmTowardZero, &LoIsExact);
5606+ assert (LoStatus == opOK && " Unexpected failure" );
5607+
5608+ // Add Lo to Hi. This addition is guaranteed not to overflow because of the
5609+ // double-double canonicalization rule (`|Lo| <= ulp(Hi)/2`). The only case
5610+ // where the sum could cross the integer type's boundary is when Hi is a
5611+ // power of two, which is handled by the special case block above.
5612+ APInt::tcAdd (Input.data (), LoResult.getRawData (), /* carry=*/ 0 , Input.size ());
5613+
5614+ *IsExact = RoundStatus == opOK;
5615+ return RoundStatus;
5616+ }
5617+
55225618APFloat::opStatus
55235619DoubleAPFloat::convertToInteger (MutableArrayRef<integerPart> Input,
55245620 unsigned int Width, bool IsSigned,
55255621 roundingMode RM, bool *IsExact) const {
5526- assert (Semantics == &semPPCDoubleDouble && " Unexpected Semantics" );
5527- return APFloat (semPPCDoubleDoubleLegacy, bitcastToAPInt ())
5528- .convertToInteger (Input, Width, IsSigned, RM, IsExact);
5622+ opStatus FS =
5623+ convertToSignExtendedInteger (Input, Width, IsSigned, RM, IsExact);
5624+
5625+ if (FS == opInvalidOp) {
5626+ const unsigned DstPartsCount = partCountForBits (Width);
5627+ assert (DstPartsCount <= Input.size () && " Integer too big" );
5628+
5629+ unsigned Bits;
5630+ if (getCategory () == fcNaN)
5631+ Bits = 0 ;
5632+ else if (isNegative ())
5633+ Bits = IsSigned;
5634+ else
5635+ Bits = Width - IsSigned;
5636+
5637+ tcSetLeastSignificantBits (Input.data (), DstPartsCount, Bits);
5638+ if (isNegative () && IsSigned)
5639+ APInt::tcShiftLeft (Input.data (), DstPartsCount, Width - 1 );
5640+ }
5641+
5642+ return FS;
55295643}
55305644
55315645APFloat::opStatus DoubleAPFloat::convertFromAPInt (const APInt &Input,
@@ -5626,14 +5740,31 @@ bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
56265740 return Ret;
56275741}
56285742
5629- int DoubleAPFloat::getExactLog2 () const {
5630- // TODO: Implement me
5631- return INT_MIN;
5632- }
5633-
56345743int DoubleAPFloat::getExactLog2Abs () const {
5635- // TODO: Implement me
5636- return INT_MIN;
5744+ // In order for Hi + Lo to be a power of two, the following must be true:
5745+ // 1. Hi must be a power of two.
5746+ // 2. Lo must be zero.
5747+ if (getSecond ().isNonZero ())
5748+ return INT_MIN;
5749+ return getFirst ().getExactLog2Abs ();
5750+ }
5751+
5752+ int ilogb (const DoubleAPFloat& Arg) {
5753+ const APFloat& Hi = Arg.getFirst ();
5754+ const APFloat& Lo = Arg.getSecond ();
5755+ int IlogbResult = ilogb (Hi);
5756+ // Zero and non-finite values can delegate to ilogb(Hi).
5757+ if (Arg.getCategory () != fcNormal)
5758+ return IlogbResult;
5759+ // If Lo can't change the binade, we can delegate to ilogb(Hi).
5760+ if (Lo.isZero () ||
5761+ Hi.isNegative () == Lo.isNegative ())
5762+ return IlogbResult;
5763+ if (Hi.getExactLog2Abs () == INT_MIN)
5764+ return IlogbResult;
5765+ // Numbers of the form 2^a - 2^b or -2^a + 2^b are almost powers of two but
5766+ // get nudged out of the binade by the low component.
5767+ return IlogbResult - 1 ;
56375768}
56385769
56395770DoubleAPFloat scalbn (const DoubleAPFloat &Arg, int Exp,
@@ -5749,10 +5880,6 @@ void APFloat::Profile(FoldingSetNodeID &NID) const {
57495880 NID.Add (bitcastToAPInt ());
57505881}
57515882
5752- /* Same as convertToInteger(integerPart*, ...), except the result is returned in
5753- an APSInt, whose initial bit-width and signed-ness are used to determine the
5754- precision of the conversion.
5755- */
57565883APFloat::opStatus APFloat::convertToInteger (APSInt &result,
57575884 roundingMode rounding_mode,
57585885 bool *isExact) const {
0 commit comments