mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-07-30 16:26:21 +08:00
EXP-052: 2x unroll of char loop_parse_if_eight_digits (ported from ffc EXP-044)
Clang/AArch64-gated 16-digit-per-iteration unroll of the fraction SWAR loop; eliminates the back-edge for typical 17-digit [0,1] mantissas. GCC keeps the auto-unrolled simple loop. ARM Graviton4 (canonical fast_float MB/s vs EXP-050): Clang: random +2.8% (1365.7 from 1328.8), mesh +1.7%, canada +0.5% GCC: unchanged (#else path) Correctness: 14/14 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8db9edbc18
commit
ee84946702
@ -259,6 +259,34 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
|||||||
loop_parse_if_eight_digits(char const *&p, char const *const pend,
|
loop_parse_if_eight_digits(char const *&p, char const *const pend,
|
||||||
uint64_t &i) {
|
uint64_t &i) {
|
||||||
// optimizes better than parse_if_eight_digits_unrolled() for UC = char.
|
// optimizes better than parse_if_eight_digits_unrolled() for UC = char.
|
||||||
|
#if defined(__aarch64__) && defined(__clang__)
|
||||||
|
// 2x unroll (ported from ffc EXP-044): on Clang/AArch64, consuming 16 digits
|
||||||
|
// per iteration eliminates the loop back-edge for typical fractions (e.g. the
|
||||||
|
// 17-digit mantissas of uniform [0,1] inputs) and keeps the SWAR constants
|
||||||
|
// resident. GCC auto-unrolls the simple loop well, so it keeps the original.
|
||||||
|
while ((pend - p) >= 16) {
|
||||||
|
uint64_t val1 = read8_to_u64(p);
|
||||||
|
if (!is_made_of_eight_digits_fast(val1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint64_t val2 = read8_to_u64(p + 8);
|
||||||
|
if (!is_made_of_eight_digits_fast(val2)) {
|
||||||
|
i = i * 100000000 + parse_eight_digits_unrolled(val1);
|
||||||
|
p += 8;
|
||||||
|
return; // val2 is not a full digit block; caller's byte loop handles rest
|
||||||
|
}
|
||||||
|
i = (i * 100000000 + parse_eight_digits_unrolled(val1)) * 100000000 +
|
||||||
|
parse_eight_digits_unrolled(val2); // in rare cases overflows, that's ok
|
||||||
|
p += 16;
|
||||||
|
}
|
||||||
|
if ((pend - p) >= 8) {
|
||||||
|
uint64_t val = read8_to_u64(p);
|
||||||
|
if (is_made_of_eight_digits_fast(val)) {
|
||||||
|
i = i * 100000000 + parse_eight_digits_unrolled(val);
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
while ((std::distance(p, pend) >= 8) &&
|
while ((std::distance(p, pend) >= 8) &&
|
||||||
is_made_of_eight_digits_fast(read8_to_u64(p))) {
|
is_made_of_eight_digits_fast(read8_to_u64(p))) {
|
||||||
i = i * 100000000 +
|
i = i * 100000000 +
|
||||||
@ -266,6 +294,7 @@ loop_parse_if_eight_digits(char const *&p, char const *const pend,
|
|||||||
p)); // in rare cases, this will overflow, but that's ok
|
p)); // in rare cases, this will overflow, but that's ok
|
||||||
p += 8;
|
p += 8;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class parse_error {
|
enum class parse_error {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user