[libc-commits] [libc] 499ca80 - [libc] Simplify decimalStringToFloat and hexadecimalStringToFloat and improve their performance.

Tue Ly via libc-commits libc-commits at lists.llvm.org
Thu Nov 11 15:35:19 PST 2021


Author: Tue Ly
Date: 2021-11-11T18:33:24-05:00
New Revision: 499ca806dcfb5f5c842fb240e150140fb15011ed

URL: https://github.com/llvm/llvm-project/commit/499ca806dcfb5f5c842fb240e150140fb15011ed
DIFF: https://github.com/llvm/llvm-project/commit/499ca806dcfb5f5c842fb240e150140fb15011ed.diff

LOG: [libc] Simplify decimalStringToFloat and hexadecimalStringToFloat and improve their performance.

Combine two loops in decimalStringToFloat and hexadecimalStringToFloat that extract the digits and re-arrange them a little bit.  This slightly improves the performance of strtof and strtod:
Running libc_str_to_float_comparison_test parse-number-fxx-test_data/data/* on my machine (Ryzen 1700)
- with glibc: ~1.92 seconds
- with current implementation: ~1.78 seconds
- with this change: ~1.67 seconds

Differential Revision: https://reviews.llvm.org/D113681

Added: 
    

Modified: 
    libc/src/__support/str_to_float.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h
index a768889f74f9..3f4a050fcb48 100644
--- a/libc/src/__support/str_to_float.h
+++ b/libc/src/__support/str_to_float.h
@@ -467,14 +467,15 @@ binaryExpToFloat(typename fputil::FPBits<T>::UIntType mantissa, int32_t exp2,
 
   // This is the number of leading zeroes a properly normalized float of type T
   // should have.
-  constexpr uint32_t NORMALIZED_LEADING_ZEROES =
+  constexpr int32_t NORMALIZED_LEADING_ZEROES =
       (sizeof(BitsType) * 8) - fputil::FloatProperties<T>::mantissaWidth - 1;
   constexpr BitsType OVERFLOWED_MANTISSA =
       BitsType(1) << (fputil::FloatProperties<T>::mantissaWidth + 1);
 
   // Normalization
   int32_t amountToShift =
-      NORMALIZED_LEADING_ZEROES - leadingZeroes<BitsType>(mantissa);
+      NORMALIZED_LEADING_ZEROES -
+      static_cast<int32_t>(leadingZeroes<BitsType>(mantissa));
   if (amountToShift < 0) {
     mantissa <<= -amountToShift;
   } else {
@@ -569,59 +570,45 @@ decimalStringToFloat(const char *__restrict src, const char DECIMAL_POINT,
   // The goal for the first step of parsing is to convert the number in src to
   // the format mantissa * (base ^ exponent)
 
-  // The first loop fills the mantissa with as many digits as it can hold
+  // The loop fills the mantissa with as many digits as it can hold
   const BitsType BITSTYPE_MAX_DIV_BY_BASE =
       __llvm_libc::cpp::NumericLimits<BitsType>::max() / BASE;
-  while ((isdigit(*src) || *src == DECIMAL_POINT) &&
-         mantissa < BITSTYPE_MAX_DIV_BY_BASE) {
-    if (*src == DECIMAL_POINT) {
-      if (afterDecimal) {
-        break; // this means that *src points to a second decimal point, ending
-               // the number.
+  while (true) {
+    if (isdigit(*src)) {
+      uint32_t digit = *src - '0';
+      seenDigit = true;
+
+      if (mantissa < BITSTYPE_MAX_DIV_BY_BASE) {
+        mantissa = (mantissa * BASE) + digit;
+        if (afterDecimal) {
+          --exponent;
+        }
       } else {
-        afterDecimal = true;
-        ++src;
-        continue;
+        if (digit > 0)
+          truncated = true;
+        if (!afterDecimal)
+          ++exponent;
       }
-    }
-    uint32_t digit = *src - '0';
 
-    mantissa = (mantissa * BASE) + digit;
-    seenDigit = true;
-    if (afterDecimal) {
-      --exponent;
+      ++src;
+      continue;
     }
-
-    ++src;
-  }
-
-  if (!seenDigit)
-    return false;
-
-  // The second loop is to run through the remaining digits after we've filled
-  // the mantissa.
-  while (isdigit(*src) || *src == DECIMAL_POINT) {
     if (*src == DECIMAL_POINT) {
       if (afterDecimal) {
         break; // this means that *src points to a second decimal point, ending
                // the number.
-      } else {
-        afterDecimal = true;
-        ++src;
-        continue;
       }
+      afterDecimal = true;
+      ++src;
+      continue;
     }
-    uint32_t digit = *src - '0';
-
-    if (digit > 0)
-      truncated = true;
-
-    if (!afterDecimal)
-      ++exponent;
-
-    ++src;
+    // The character is neither a digit nor a decimal point.
+    break;
   }
 
+  if (!seenDigit)
+    return false;
+
   if ((*src | 32) == EXPONENT_MARKER) {
     if (*(src + 1) == '+' || *(src + 1) == '-' || isdigit(*(src + 1))) {
       ++src;
@@ -673,62 +660,47 @@ hexadecimalStringToFloat(const char *__restrict src, const char DECIMAL_POINT,
   // The goal for the first step of parsing is to convert the number in src to
   // the format mantissa * (base ^ exponent)
 
-  // The first loop fills the mantissa with as many digits as it can hold
+  // The loop fills the mantissa with as many digits as it can hold
   const BitsType BITSTYPE_MAX_DIV_BY_BASE =
       __llvm_libc::cpp::NumericLimits<BitsType>::max() / BASE;
-  while ((isalnum(*src) || *src == DECIMAL_POINT) &&
-         mantissa < BITSTYPE_MAX_DIV_BY_BASE) {
-    if (*src == DECIMAL_POINT) {
-      if (afterDecimal) {
-        break; // this means that *src points to a second decimal point, ending
-               // the number.
+  while (true) {
+    if (isalnum(*src)) {
+      uint32_t digit = b36_char_to_int(*src);
+      if (digit >= BASE) {
+        seenDigit = false;
+        break;
+      }
+      seenDigit = true;
+
+      if (mantissa < BITSTYPE_MAX_DIV_BY_BASE) {
+        mantissa = (mantissa * BASE) + digit;
+        if (afterDecimal)
+          --exponent;
       } else {
-        afterDecimal = true;
-        ++src;
-        continue;
+        if (digit > 0)
+          truncated = true;
+        if (!afterDecimal)
+          ++exponent;
       }
+      ++src;
+      continue;
     }
-    uint32_t digit = b36_char_to_int(*src);
-    if (digit >= BASE)
-      break;
-
-    mantissa = (mantissa * BASE) + digit;
-    seenDigit = true;
-    if (afterDecimal)
-      --exponent;
-
-    ++src;
-  }
-
-  if (!seenDigit)
-    return false;
-
-  // The second loop is to run through the remaining digits after we've filled
-  // the mantissa.
-  while (isalnum(*src) || *src == DECIMAL_POINT) {
     if (*src == DECIMAL_POINT) {
       if (afterDecimal) {
         break; // this means that *src points to a second decimal point, ending
                // the number.
-      } else {
-        afterDecimal = true;
-        ++src;
-        continue;
       }
+      afterDecimal = true;
+      ++src;
+      continue;
     }
-    uint32_t digit = b36_char_to_int(*src);
-    if (digit >= BASE)
-      break;
-
-    if (digit > 0)
-      truncated = true;
-
-    if (!afterDecimal)
-      ++exponent;
-
-    ++src;
+    // The character is neither a hexadecimal digit nor a decimal point.
+    break;
   }
 
+  if (!seenDigit)
+    return false;
+
   // Convert the exponent from having a base of 16 to having a base of 2.
   exponent *= 4;
 


        


More information about the libc-commits mailing list