aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2022-04-18 17:22:55 -0400
committerPatrick Palka <ppalka@redhat.com>2022-04-18 17:22:55 -0400
commitd210653f3907ac1829fd275d067b2855ea53da24 (patch)
tree6e394b80ee6b02b74647c5a1a7220d4a2477c6d6 /libstdc++-v3
parent021b51814d67bedd8f41ac07edfd05654140c6e5 (diff)
downloadgcc-d210653f3907ac1829fd275d067b2855ea53da24.zip
gcc-d210653f3907ac1829fd275d067b2855ea53da24.tar.gz
gcc-d210653f3907ac1829fd275d067b2855ea53da24.tar.bz2
libstdc++: Micro-optimize __from_chars_pow2_base
In the first iteration of __from_chars_pow2_base's main loop, we need to remember the value of the leading significant digit for sake of the overflow check at the end (for base > 2). This patch manually unrolls this first iteration so as to not encumber the entire loop with logic that only the first iteration needs. This seems to significantly improve performance: Base Before After (seconds, lower is better) 2 9.36 9.37 8 3.66 2.93 16 2.93 1.91 32 2.39 2.24 libstdc++-v3/ChangeLog: * include/std/charconv (__from_chars_pow2_base): Manually unroll the first iteration of the main loop and simplify accordingly.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/include/std/charconv28
1 files changed, 20 insertions, 8 deletions
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index dda4ec8..f1ace40 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -469,25 +469,37 @@ namespace __detail
while (__i < __len && __first[__i] == '0')
++__i;
const ptrdiff_t __leading_zeroes = __i;
+ if (__i >= __len) [[__unlikely__]]
+ {
+ __first += __i;
+ return true;
+ }
+ // Remember the leading significant digit value if necessary.
unsigned char __leading_c = 0;
+ if (__base != 2)
+ {
+ __leading_c = __from_chars_alnum_to_val<_DecOnly>(__first[__i]);
+ // __glibcxx_assert(__leading_c != 0);
+ if (__leading_c >= __base) [[__unlikely__]]
+ {
+ __first += __i;
+ return true;
+ }
+ __val = __leading_c;
+ ++__i;
+ }
+
for (; __i < __len; ++__i)
{
const unsigned char __c = __from_chars_alnum_to_val<_DecOnly>(__first[__i]);
if (__c >= __base)
break;
__val = (__val << __log2_base) | __c;
-
- if (__i == __leading_zeroes)
- {
- // At the first iteration, remember the leading significant digit.
- // __glibcxx_assert(__leading_c == 0 && __c != 0);
- __leading_c = __c;
- }
}
__first += __i;
auto __significant_bits = (__i - __leading_zeroes) * __log2_base;
- if (__base != 2 && __leading_c != 0)
+ if (__base != 2)
// Compensate for a leading significant digit that didn't use all
// of its available bits.
__significant_bits -= __log2_base - __bit_width(__leading_c);