From 8db9edbc1852210d60eaf5b42240e37fa2c1c969 Mon Sep 17 00:00:00 2001 From: fcostaoliveira Date: Mon, 1 Jun 2026 00:48:45 +0100 Subject: [PATCH] EXP-050: straight-line nested-if integer-part scan (ported from ffc EXP-026/028) Peel the first 5 iterations of the integer-part digit loop into nested ifs, eliminating the loop back-edge for the common 1-5 digit integer case. Identical semantics (i = 10*i + digit). Biggest win on inputs with multi-digit integer parts (mesh 3D coordinates). ARM Graviton4 (canonical MB/s, vs upstream 7790aa6 baseline): GCC: random +0.05%, canada +4.0%, mesh +34.3% (c/f 55.7->41.4) Clang: random +4.9%, canada +2.8%, mesh +5.1% Correctness: 14/14 core+supplemental pass. Co-Authored-By: Claude Opus 4.8 --- include/fast_float/ascii_number.h | 35 +++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 12c2fdd..257b43b 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -354,13 +354,36 @@ parse_number_string(UC const *p, UC const *pend, uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) - while ((p != pend) && is_integer(*p)) { - // a multiplication by 10 is cheaper than an arbitrary integer - // multiplication - i = 10 * i + - uint64_t(*p - - UC('0')); // might overflow, we will handle the overflow later + // Straight-line unroll of the integer-part scan: most integer parts are + // 1-5 digits, so peeling the first iterations eliminates the loop back-edge + // for the common case (ported from ffc EXP-026/028). Semantics are identical + // to the original `while` loop: i = 10*i + digit, advancing p. + if ((p != pend) && is_integer(*p)) { + i = uint64_t(*p - UC('0')); ++p; + if ((p != pend) && is_integer(*p)) { + i = 10 * i + uint64_t(*p - UC('0')); + ++p; + if ((p != pend) && is_integer(*p)) { + i = 10 * i + uint64_t(*p - UC('0')); + ++p; + if ((p != pend) && is_integer(*p)) { + i = 10 * i + uint64_t(*p - UC('0')); + ++p; + if ((p != pend) && is_integer(*p)) { + i = 10 * i + uint64_t(*p - UC('0')); + ++p; + while ((p != pend) && is_integer(*p)) { + // a multiplication by 10 is cheaper than an arbitrary integer + // multiplication + i = 10 * i + + uint64_t(*p - UC('0')); // might overflow, handled later + ++p; + } + } + } + } + } } UC const *const end_of_integer_part = p; int64_t digit_count = int64_t(end_of_integer_part - start_digits);