Handle '.' correctly in hex float literal parsing.
authorEli Friedman <eli.friedman@gmail.com>
Wed, 17 Jul 2013 22:17:29 +0000 (22:17 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 17 Jul 2013 22:17:29 +0000 (22:17 +0000)
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

llvm/lib/Support/APFloat.cpp
llvm/unittests/ADT/APFloatTest.cpp

index 58f1623..ce57442 100644 (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;
     }
   }
 
index 46dfbd1..1d6d8ca 100644 (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) {