Simplify atoi*/strto* for signed integers.

Make the cost of strto<signed> closer to the cost of strto<unsigned>
by removing an `if` from the inner loop. Previously a signed conversion
cost 10ns more than an unsigned one.

After:

  BM_inttypes_strtoimax         81 ns         81 ns    8603362
  BM_inttypes_strtoumax         78 ns         78 ns    8967174
  BM_stdlib_strtol              81 ns         81 ns    8685537
  BM_stdlib_strtoll             81 ns         81 ns    8685481
  BM_stdlib_strtoul             78 ns         78 ns    8962569
  BM_stdlib_strtoull            78 ns         78 ns    8972023

Bug: N/A
Test: ran tests, benchmarks
Change-Id: I72dd5499427b6a940bd94c4d6f727f7efe134d7e
diff --git a/libc/bionic/strtol.cpp b/libc/bionic/strtol.cpp
index f4c8c5f..f6005fa 100644
--- a/libc/bionic/strtol.cpp
+++ b/libc/bionic/strtol.cpp
@@ -66,31 +66,11 @@
   }
   if (base == 0) base = (c == '0') ? 8 : 10;
 
-  // Compute the cutoff value between legal numbers and illegal
-  // numbers.  That is the largest legal value, divided by the
-  // base.  An input number that is greater than this value, if
-  // followed by a legal input character, is too big.  One that
-  // is equal to this value may be valid or not; the limit
-  // between valid and invalid numbers is then based on the last
-  // digit.  For instance, if the range for intmax_t is
-  // [-9223372036854775808..9223372036854775807] and the input base
-  // is 10, cutoff will be set to 922337203685477580 and cutlim to
-  // either 7 (neg==0) or 8 (neg==1), meaning that if we have
-  // accumulated a value > 922337203685477580, or equal but the
-  // next digit is > 7 (or 8), the number is too big, and we will
-  // return a range error.
-  T cutoff = neg ? Min : Max;
-  int cutlim = cutoff % base;
-  cutoff /= base;
-  if (neg) {
-    if (cutlim > 0) {
-      cutlim -= base;
-      cutoff += 1;
-    }
-    cutlim = -cutlim;
-  }
-
-  // Set `any` if any digits consumed; make it negative to indicate overflow.
+  // We always work in the negative space because the most negative value has a
+  // larger magnitude than the most positive value.
+  T cutoff = Min / base;
+  int cutlim = -(Min % base);
+  // Non-zero if any digits consumed; negative to indicate overflow/underflow.
   int any = 0;
   T acc = 0;
   for (; ; c = *s++) {
@@ -103,29 +83,25 @@
     }
     if (c >= base) break;
     if (any < 0) continue;
-    if (neg) {
-      if (acc < cutoff || (acc == cutoff && c > cutlim)) {
-        any = -1;
-        acc = Min;
-        errno = ERANGE;
-      } else {
-        any = 1;
-        acc *= base;
-        acc -= c;
-      }
+    if (acc < cutoff || (acc == cutoff && c > cutlim)) {
+      any = -1;
+      acc = Min;
+      errno = ERANGE;
     } else {
-      if (acc > cutoff || (acc == cutoff && c > cutlim)) {
-        any = -1;
-        acc = Max;
-        errno = ERANGE;
-      } else {
-        any = 1;
-        acc *= base;
-        acc += c;
-      }
+      any = 1;
+      acc *= base;
+      acc -= c;
     }
   }
   if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
+  if (!neg) {
+    if (acc == Min) {
+      errno = ERANGE;
+      acc = Max;
+    } else {
+      acc = -acc;
+    }
+  }
   return acc;
 }
 
@@ -177,7 +153,7 @@
       errno = ERANGE;
     } else {
       any = 1;
-      acc *= static_cast<T>(base);
+      acc *= base;
       acc += c;
     }
   }
diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp
index 93877f3..caa7a85 100644
--- a/tests/stdlib_test.cpp
+++ b/tests/stdlib_test.cpp
@@ -679,22 +679,51 @@
   if (std::numeric_limits<T>::is_signed) {
     // Minimum (such as -128).
     std::string min{std::to_string(std::numeric_limits<T>::min())};
+    end_p = nullptr;
+    errno = 0;
     ASSERT_EQ(std::numeric_limits<T>::min(), fn(min.c_str(), &end_p, 0));
+    ASSERT_EQ(0, errno);
+    ASSERT_EQ('\0', *end_p);
     // Too negative (such as -129).
     min.back() = (min.back() + 1);
+    end_p = nullptr;
     errno = 0;
     ASSERT_EQ(std::numeric_limits<T>::min(), fn(min.c_str(), &end_p, 0));
     ASSERT_EQ(ERANGE, errno);
+    ASSERT_EQ('\0', *end_p);
   }
 
   // Maximum (such as 127).
   std::string max{std::to_string(std::numeric_limits<T>::max())};
+  end_p = nullptr;
+  errno = 0;
   ASSERT_EQ(std::numeric_limits<T>::max(), fn(max.c_str(), &end_p, 0));
+  ASSERT_EQ(0, errno);
+  ASSERT_EQ('\0', *end_p);
   // Too positive (such as 128).
   max.back() = (max.back() + 1);
+  end_p = nullptr;
   errno = 0;
   ASSERT_EQ(std::numeric_limits<T>::max(), fn(max.c_str(), &end_p, 0));
   ASSERT_EQ(ERANGE, errno);
+  ASSERT_EQ('\0', *end_p);
+
+  // In case of overflow, strto* leaves us pointing past the end of the number,
+  // not at the digit that overflowed.
+  end_p = nullptr;
+  errno = 0;
+  ASSERT_EQ(std::numeric_limits<T>::max(),
+            fn("99999999999999999999999999999999999999999999999999999abc", &end_p, 0));
+  ASSERT_EQ(ERANGE, errno);
+  ASSERT_STREQ("abc", end_p);
+  if (std::numeric_limits<T>::is_signed) {
+      end_p = nullptr;
+      errno = 0;
+      ASSERT_EQ(std::numeric_limits<T>::min(),
+                fn("-99999999999999999999999999999999999999999999999999999abc", &end_p, 0));
+      ASSERT_EQ(ERANGE, errno);
+      ASSERT_STREQ("abc", end_p);
+  }
 }
 
 TEST(stdlib, strtol_smoke) {