Skip to content

Commit 2d0f63f

Browse files
committed
[APFloat] Fix IEEEFloat::addOrSubtractSignificand and IEEEFloat::normalize
1 parent 7d1b6b2 commit 2d0f63f

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

llvm/lib/Support/APFloat.cpp

+36-15
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,8 @@ IEEEFloat::opStatus IEEEFloat::normalize(roundingMode rounding_mode,
16071607
/* Before rounding normalize the exponent of fcNormal numbers. */
16081608
omsb = significandMSB() + 1;
16091609

1610-
if (omsb) {
1610+
// Only skip this `if` if the value is exactly zero.
1611+
if (omsb || lost_fraction != lfExactlyZero) {
16111612
/* OMSB is numbered from 1. We want to place it in the integer
16121613
bit numbered PRECISION if possible, with a compensating change in
16131614
the exponent. */
@@ -1782,7 +1783,7 @@ IEEEFloat::opStatus IEEEFloat::addOrSubtractSpecials(const IEEEFloat &rhs,
17821783
/* Add or subtract two normal numbers. */
17831784
lostFraction IEEEFloat::addOrSubtractSignificand(const IEEEFloat &rhs,
17841785
bool subtract) {
1785-
integerPart carry;
1786+
integerPart carry = 0;
17861787
lostFraction lost_fraction;
17871788
int bits;
17881789

@@ -1796,35 +1797,55 @@ lostFraction IEEEFloat::addOrSubtractSignificand(const IEEEFloat &rhs,
17961797
/* Subtraction is more subtle than one might naively expect. */
17971798
if (subtract) {
17981799
IEEEFloat temp_rhs(rhs);
1800+
bool lost_fraction_is_from_rhs = false;
17991801

18001802
if (bits == 0)
18011803
lost_fraction = lfExactlyZero;
18021804
else if (bits > 0) {
18031805
lost_fraction = temp_rhs.shiftSignificandRight(bits - 1);
1806+
lost_fraction_is_from_rhs = true;
18041807
shiftSignificandLeft(1);
18051808
} else {
18061809
lost_fraction = shiftSignificandRight(-bits - 1);
18071810
temp_rhs.shiftSignificandLeft(1);
18081811
}
18091812

18101813
// Should we reverse the subtraction.
1811-
if (compareAbsoluteValue(temp_rhs) == cmpLessThan) {
1812-
carry = temp_rhs.subtractSignificand
1813-
(*this, lost_fraction != lfExactlyZero);
1814+
cmpResult cmp_result = compareAbsoluteValue(temp_rhs);
1815+
if (cmp_result == cmpLessThan) {
1816+
bool borrow = false;
1817+
if (lost_fraction != lfExactlyZero && !lost_fraction_is_from_rhs) {
1818+
// The lost fraction is being subtracted, borrow from the significand
1819+
// and invert `lost_fraction`.
1820+
borrow = true;
1821+
if (lost_fraction == lfLessThanHalf)
1822+
lost_fraction = lfMoreThanHalf;
1823+
else if (lost_fraction == lfMoreThanHalf)
1824+
lost_fraction = lfLessThanHalf;
1825+
}
1826+
carry = temp_rhs.subtractSignificand(*this, borrow);
18141827
copySignificand(temp_rhs);
18151828
sign = !sign;
1816-
} else {
1817-
carry = subtractSignificand
1818-
(temp_rhs, lost_fraction != lfExactlyZero);
1829+
} else if (cmp_result == cmpGreaterThan) {
1830+
bool borrow = false;
1831+
if (lost_fraction != lfExactlyZero && lost_fraction_is_from_rhs) {
1832+
// The lost fraction is being subtracted, borrow from the significand
1833+
// and invert `lost_fraction`.
1834+
borrow = true;
1835+
if (lost_fraction == lfLessThanHalf)
1836+
lost_fraction = lfMoreThanHalf;
1837+
else if (lost_fraction == lfMoreThanHalf)
1838+
lost_fraction = lfLessThanHalf;
1839+
}
1840+
carry = subtractSignificand(temp_rhs, borrow);
1841+
} else { // cmpEqual
1842+
zeroSignificand();
1843+
if (lost_fraction != lfExactlyZero && lost_fraction_is_from_rhs) {
1844+
// rhs is slightly larger due to the lost fraction, flip the sign.
1845+
sign = !sign;
1846+
}
18191847
}
18201848

1821-
/* Invert the lost fraction - it was on the RHS and
1822-
subtracted. */
1823-
if (lost_fraction == lfLessThanHalf)
1824-
lost_fraction = lfMoreThanHalf;
1825-
else if (lost_fraction == lfMoreThanHalf)
1826-
lost_fraction = lfLessThanHalf;
1827-
18281849
/* The code above is intended to ensure that no borrow is
18291850
necessary. */
18301851
assert(!carry);

llvm/unittests/ADT/APFloatTest.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,17 @@ TEST(APFloatTest, FMA) {
560560
EXPECT_EQ(-8.85242279E-41f, f1.convertToFloat());
561561
}
562562

563+
// Regression test for failing the `assert(!carry)` in
564+
// `addOrSubtractSignificand` and normalizing the exponent even when the
565+
// significand is zero if there is a lost fraction.
566+
{
567+
APFloat f1(-1.4728589E-38f);
568+
APFloat f2(3.7105144E-6f);
569+
APFloat f3(5.5E-44f);
570+
f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven);
571+
EXPECT_EQ(-0.0f, f1.convertToFloat());
572+
}
573+
563574
// Test using only a single instance of APFloat.
564575
{
565576
APFloat F(1.5);

0 commit comments

Comments
 (0)