From 763c066dca324ac4b86e7f014fe580ae5ba29fa0 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Wed, 17 Jul 2013 22:17:29 +0000 Subject: [PATCH] Handle '.' correctly in hex float literal parsing. There were a couple of different loops that were not handling '.' correctly in APFloat::convertFromHexadecimalString; these mistakes could lead to assertion failures and incorrect rounding for overlong hex float literals. Fixes PR16643. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186539 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Support/APFloat.cpp | 50 ++++++++++++++--------------------- unittests/ADT/APFloatTest.cpp | 7 ++++- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 58f16233ebf..ce57442219c 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -319,8 +319,8 @@ trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end, else if (digitValue < 8 && digitValue > 0) return lfLessThanHalf; - /* Otherwise we need to find the first non-zero digit. */ - while (*p == '0') + // Otherwise we need to find the first non-zero digit. + while (p != end && (*p == '0' || *p == '.')) p++; assert(p != end && "Invalid trailing hexadecimal fraction!"); @@ -2300,56 +2300,46 @@ APFloat::opStatus APFloat::convertFromHexadecimalString(StringRef s, roundingMode rounding_mode) { lostFraction lost_fraction = lfExactlyZero; - integerPart *significand; - unsigned int bitPos, partsCount; - StringRef::iterator dot, firstSignificantDigit; zeroSignificand(); exponent = 0; category = fcNormal; - significand = significandParts(); - partsCount = partCount(); - bitPos = partsCount * integerPartWidth; + integerPart *significand = significandParts(); + unsigned partsCount = partCount(); + unsigned bitPos = partsCount * integerPartWidth; + bool computedTrailingFraction = false; - /* Skip leading zeroes and any (hexa)decimal point. */ + // Skip leading zeroes and any (hexa)decimal point. StringRef::iterator begin = s.begin(); StringRef::iterator end = s.end(); + StringRef::iterator dot; StringRef::iterator p = skipLeadingZeroesAndAnyDot(begin, end, &dot); - firstSignificantDigit = p; + StringRef::iterator firstSignificantDigit = p; - for (; p != end;) { + while (p != end) { integerPart hex_value; if (*p == '.') { assert(dot == end && "String contains multiple dots"); dot = p++; - if (p == end) { - break; - } + continue; } hex_value = hexDigitValue(*p); - if (hex_value == -1U) { + if (hex_value == -1U) break; - } p++; - if (p == end) { - break; - } else { - /* Store the number whilst 4-bit nibbles remain. */ - if (bitPos) { - bitPos -= 4; - hex_value <<= bitPos % integerPartWidth; - significand[bitPos / integerPartWidth] |= hex_value; - } else { - lost_fraction = trailingHexadecimalFraction(p, end, hex_value); - while (p != end && hexDigitValue(*p) != -1U) - p++; - break; - } + // Store the number while we have space. + if (bitPos) { + bitPos -= 4; + hex_value <<= bitPos % integerPartWidth; + significand[bitPos / integerPartWidth] |= hex_value; + } else if (!computedTrailingFraction) { + lost_fraction = trailingHexadecimalFraction(p, end, hex_value); + computedTrailingFraction = true; } } diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 46dfbd1d13a..1d6d8caa321 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -766,6 +766,8 @@ TEST(APFloatTest, fromDecimalString) { EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-99e99999").isInfinity()); EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "1e-99999").isPosZero()); EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-1e-99999").isNegZero()); + + EXPECT_EQ(2.71828, convertToDoubleFromString("2.71828")); } TEST(APFloatTest, fromHexadecimalString) { @@ -849,7 +851,10 @@ TEST(APFloatTest, fromHexadecimalString) { EXPECT_EQ(1.0625, APFloat(APFloat::IEEEdouble, "0x1.1p0").convertToDouble()); EXPECT_EQ(1.0, APFloat(APFloat::IEEEdouble, "0x1p0").convertToDouble()); - EXPECT_EQ(2.71828, convertToDoubleFromString("2.71828")); + EXPECT_EQ(convertToDoubleFromString("0x1p-150"), + convertToDoubleFromString("+0x800000000000000001.p-221")); + EXPECT_EQ(2251799813685248.5, + convertToDoubleFromString("0x80000000000004000000.010p-28")); } TEST(APFloatTest, toString) {