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.
This commit is contained in:
parent
021b51814d
commit
d210653f39
1 changed files with 20 additions and 8 deletions
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue