Skip to content

Commit b1bcafd

Browse files
committed
APFloat/x87: Fix string conversion for "unnormal" values (pr35860)
Summary: Unnormal values are a feature of some very old x87 processors. We handle them correctly for the most part -- the only exception was an unnormal value whose significand happened to be zero. In this case the APFloat was still initialized as normal number (category = fcNormal), but a subsequent toString operation would assert because the math would produce nonsensical values for the zero significand. During review, it was decided that the correct way to fix this is to treat all unnormal values as NaNs (as that is what any >=386 processor will do). The issue was discovered because LLDB would crash when trying to print some "long double" values. Reviewers: skatkov, scanon, gottesmm Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D41868 llvm-svn: 331884
1 parent 8e7625e commit b1bcafd

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

llvm/lib/Support/APFloat.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3032,27 +3032,29 @@ double IEEEFloat::convertToDouble() const {
30323032
/// does not support these bit patterns:
30333033
/// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity")
30343034
/// exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN")
3035-
/// exponent = 0, integer bit 1 ("pseudodenormal")
30363035
/// exponent!=0 nor all 1's, integer bit 0 ("unnormal")
3037-
/// At the moment, the first two are treated as NaNs, the second two as Normal.
3036+
/// exponent = 0, integer bit 1 ("pseudodenormal")
3037+
/// At the moment, the first three are treated as NaNs, the last one as Normal.
30383038
void IEEEFloat::initFromF80LongDoubleAPInt(const APInt &api) {
30393039
assert(api.getBitWidth()==80);
30403040
uint64_t i1 = api.getRawData()[0];
30413041
uint64_t i2 = api.getRawData()[1];
30423042
uint64_t myexponent = (i2 & 0x7fff);
30433043
uint64_t mysignificand = i1;
3044+
uint8_t myintegerbit = mysignificand >> 63;
30443045

30453046
initialize(&semX87DoubleExtended);
30463047
assert(partCount()==2);
30473048

30483049
sign = static_cast<unsigned int>(i2>>15);
3049-
if (myexponent==0 && mysignificand==0) {
3050+
if (myexponent == 0 && mysignificand == 0) {
30503051
// exponent, significand meaningless
30513052
category = fcZero;
30523053
} else if (myexponent==0x7fff && mysignificand==0x8000000000000000ULL) {
30533054
// exponent, significand meaningless
30543055
category = fcInfinity;
3055-
} else if (myexponent==0x7fff && mysignificand!=0x8000000000000000ULL) {
3056+
} else if ((myexponent == 0x7fff && mysignificand != 0x8000000000000000ULL) ||
3057+
(myexponent != 0x7fff && myexponent != 0 && myintegerbit == 0)) {
30563058
// exponent meaningless
30573059
category = fcNaN;
30583060
significandParts()[0] = mysignificand;

llvm/unittests/ADT/APFloatTest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,13 @@ TEST(APFloatTest, toString) {
983983
ASSERT_EQ("8.73183400000000010e+02", convertToString(873.1834, 0, 0, false));
984984
ASSERT_EQ("1.79769313486231570e+308",
985985
convertToString(1.7976931348623157E+308, 0, 0, false));
986+
987+
{
988+
SmallString<64> Str;
989+
APFloat UnnormalZero(APFloat::x87DoubleExtended(), APInt(80, {0, 1}));
990+
UnnormalZero.toString(Str);
991+
ASSERT_EQ("NaN", Str);
992+
}
986993
}
987994

988995
TEST(APFloatTest, toInteger) {

0 commit comments

Comments
 (0)