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.

llvm-svn: 186539
This commit is contained in:
Eli Friedman 2013-07-17 22:17:29 +00:00
parent 00cf53520b
commit d2eb07acae
2 changed files with 26 additions and 31 deletions

View File

@ -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;
}
}

View File

@ -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) {