Implement arithmetic on APFloat with PPCDoubleDouble semantics by

treating it as if it were an IEEE floating-point type with 106-bit
mantissa.

This makes compile-time arithmetic on "long double" for PowerPC
in clang (in particular parsing of floating point constants)
work, and fixes all "long double" related failures in the test
suite.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166951 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ulrich Weigand 2012-10-29 18:09:01 +00:00
parent 2fbc239e4f
commit 69c9c8c4cf
2 changed files with 100 additions and 75 deletions

View File

@ -58,10 +58,19 @@ namespace llvm {
const fltSemantics APFloat::x87DoubleExtended = { 16383, -16382, 64, true }; const fltSemantics APFloat::x87DoubleExtended = { 16383, -16382, 64, true };
const fltSemantics APFloat::Bogus = { 0, 0, 0, true }; const fltSemantics APFloat::Bogus = { 0, 0, 0, true };
// The PowerPC format consists of two doubles. It does not map cleanly /* The PowerPC format consists of two doubles. It does not map cleanly
// onto the usual format above. For now only storage of constants of onto the usual format above. It is approximated using twice the
// this type is supported, no arithmetic. mantissa bits. Note that for exponents near the double minimum,
const fltSemantics APFloat::PPCDoubleDouble = { 1023, -1022, 106, false }; we no longer can represent the full 106 mantissa bits, so those
will be treated as denormal numbers.
FIXME: While this approximation is equivalent to what GCC uses for
compile-time arithmetic on PPC double-double numbers, it is not able
to represent all possible values held by a PPC double-double number,
for example: (long double) 1.0 + (long double) 0x1p-106
Should this be replaced by a full emulation of PPC double-double? */
const fltSemantics APFloat::PPCDoubleDouble =
{ 1023, -1022 + 53, 53 + 53, true };
/* A tight upper bound on number of parts required to hold the value /* A tight upper bound on number of parts required to hold the value
pow(5, power) is pow(5, power) is
@ -2790,42 +2799,46 @@ APFloat::convertPPCDoubleDoubleAPFloatToAPInt() const
assert(semantics == (const llvm::fltSemantics*)&PPCDoubleDouble); assert(semantics == (const llvm::fltSemantics*)&PPCDoubleDouble);
assert(partCount()==2); assert(partCount()==2);
uint64_t myexponent, mysignificand, myexponent2, mysignificand2; uint64_t words[2];
opStatus fs;
bool losesInfo;
if (category==fcNormal) { // Convert number to double. To avoid spurious underflows, we re-
myexponent = exponent + 1023; //bias // normalize against the "double" minExponent first, and only *then*
myexponent2 = exponent2 + 1023; // truncate the mantissa. The result of that second conversion
mysignificand = significandParts()[0]; // may be inexact, but should never underflow.
mysignificand2 = significandParts()[1]; APFloat extended(*this);
if (myexponent==1 && !(mysignificand & 0x10000000000000LL)) fltSemantics extendedSemantics = *semantics;
myexponent = 0; // denormal extendedSemantics.minExponent = IEEEdouble.minExponent;
if (myexponent2==1 && !(mysignificand2 & 0x10000000000000LL)) fs = extended.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo);
myexponent2 = 0; // denormal assert(fs == opOK && !losesInfo);
} else if (category==fcZero) { (void)fs;
myexponent = 0;
mysignificand = 0; APFloat u(extended);
myexponent2 = 0; fs = u.convert(IEEEdouble, rmNearestTiesToEven, &losesInfo);
mysignificand2 = 0; assert(fs == opOK || fs == opInexact);
} else if (category==fcInfinity) { (void)fs;
myexponent = 0x7ff; words[0] = *u.convertDoubleAPFloatToAPInt().getRawData();
myexponent2 = 0;
mysignificand = 0; // If conversion was exact or resulted in a special case, we're done;
mysignificand2 = 0; // just set the second double to zero. Otherwise, re-convert back to
// the extended format and compute the difference. This now should
// convert exactly to double.
if (u.category == fcNormal && losesInfo) {
fs = u.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
APFloat v(extended);
v.subtract(u, rmNearestTiesToEven);
fs = v.convert(IEEEdouble, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
words[1] = *v.convertDoubleAPFloatToAPInt().getRawData();
} else { } else {
assert(category == fcNaN && "Unknown category"); words[1] = 0;
myexponent = 0x7ff;
mysignificand = significandParts()[0];
myexponent2 = exponent2;
mysignificand2 = significandParts()[1];
} }
uint64_t words[2];
words[0] = ((uint64_t)(sign & 1) << 63) |
((myexponent & 0x7ff) << 52) |
(mysignificand & 0xfffffffffffffLL);
words[1] = ((uint64_t)(sign2 & 1) << 63) |
((myexponent2 & 0x7ff) << 52) |
(mysignificand2 & 0xfffffffffffffLL);
return APInt(128, words); return APInt(128, words);
} }
@ -3045,47 +3058,23 @@ APFloat::initFromPPCDoubleDoubleAPInt(const APInt &api)
assert(api.getBitWidth()==128); assert(api.getBitWidth()==128);
uint64_t i1 = api.getRawData()[0]; uint64_t i1 = api.getRawData()[0];
uint64_t i2 = api.getRawData()[1]; uint64_t i2 = api.getRawData()[1];
uint64_t myexponent = (i1 >> 52) & 0x7ff; opStatus fs;
uint64_t mysignificand = i1 & 0xfffffffffffffLL; bool losesInfo;
uint64_t myexponent2 = (i2 >> 52) & 0x7ff;
uint64_t mysignificand2 = i2 & 0xfffffffffffffLL;
initialize(&APFloat::PPCDoubleDouble); // Get the first double and convert to our format.
assert(partCount()==2); initFromDoubleAPInt(APInt(64, i1));
fs = convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
sign = static_cast<unsigned int>(i1>>63); // Unless we have a special case, add in second double.
sign2 = static_cast<unsigned int>(i2>>63); if (category == fcNormal) {
if (myexponent==0 && mysignificand==0) { APFloat v(APInt(64, i2));
// exponent, significand meaningless fs = v.convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo);
// exponent2 and significand2 are required to be 0; we don't check assert(fs == opOK && !losesInfo);
category = fcZero; (void)fs;
} else if (myexponent==0x7ff && mysignificand==0) {
// exponent, significand meaningless add(v, rmNearestTiesToEven);
// exponent2 and significand2 are required to be 0; we don't check
category = fcInfinity;
} else if (myexponent==0x7ff && mysignificand!=0) {
// exponent meaningless. So is the whole second word, but keep it
// for determinism.
category = fcNaN;
exponent2 = myexponent2;
significandParts()[0] = mysignificand;
significandParts()[1] = mysignificand2;
} else {
category = fcNormal;
// Note there is no category2; the second word is treated as if it is
// fcNormal, although it might be something else considered by itself.
exponent = myexponent - 1023;
exponent2 = myexponent2 - 1023;
significandParts()[0] = mysignificand;
significandParts()[1] = mysignificand2;
if (myexponent==0) // denormal
exponent = -1022;
else
significandParts()[0] |= 0x10000000000000LL; // integer bit
if (myexponent2==0)
exponent2 = -1022;
else
significandParts()[1] |= 0x10000000000000LL; // integer bit
} }
} }

View File

@ -737,4 +737,40 @@ TEST(APFloatTest, convert) {
EXPECT_EQ(4294967295.0, test.convertToDouble()); EXPECT_EQ(4294967295.0, test.convertToDouble());
EXPECT_FALSE(losesInfo); EXPECT_FALSE(losesInfo);
} }
TEST(APFloatTest, PPCDoubleDouble) {
APFloat test(APFloat::PPCDoubleDouble, "1.0");
EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]);
test.divide(APFloat(APFloat::PPCDoubleDouble, "3.0"), APFloat::rmNearestTiesToEven);
EXPECT_EQ(0x3fd5555555555555ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x3c75555555555556ull, test.bitcastToAPInt().getRawData()[1]);
// LDBL_MAX
test = APFloat(APFloat::PPCDoubleDouble, "1.79769313486231580793728971405301e+308");
EXPECT_EQ(0x7fefffffffffffffull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x7c8ffffffffffffeull, test.bitcastToAPInt().getRawData()[1]);
// LDBL_MIN
test = APFloat(APFloat::PPCDoubleDouble, "2.00416836000897277799610805135016e-292");
EXPECT_EQ(0x0360000000000000ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]);
test = APFloat(APFloat::PPCDoubleDouble, "1.0");
test.add(APFloat(APFloat::PPCDoubleDouble, "0x1p-105"), APFloat::rmNearestTiesToEven);
EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
EXPECT_EQ(0x3960000000000000ull, test.bitcastToAPInt().getRawData()[1]);
test = APFloat(APFloat::PPCDoubleDouble, "1.0");
test.add(APFloat(APFloat::PPCDoubleDouble, "0x1p-106"), APFloat::rmNearestTiesToEven);
EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]);
#if 0 // XFAIL
// This is what we would expect with a true double-double implementation
EXPECT_EQ(0x3950000000000000ull, test.bitcastToAPInt().getRawData()[1]);
#else
// This is what we get with our 106-bit mantissa approximation
EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]);
#endif
}
} }