From a30c1f3d3f42dde8c34478215edbe3ce3234b350 Mon Sep 17 00:00:00 2001 From: fcostaoliveira Date: Mon, 1 Jun 2026 01:04:30 +0100 Subject: [PATCH] EXP-053: 4-digit SWAR follow-up in loop_parse_if_eight_digits, GCC path (ffc EXP-001) After the 8-digit block loop, consume a remaining 4-7 digit run in one SWAR step (reusing fast_float's existing read4_to_u32 / is_made_of_four_digits_fast / parse_four_digits_unrolled) instead of byte-by-byte. GCC path only: on Clang the follow-up's presence bloated the 2x-unroll codegen and regressed random -6.2%. ARM Graviton4 (canonical fast_float MB/s vs EXP-052): GCC: canada +2.6% (948.1 from 924.0, i/f 248.7->229.7), random/mesh flat Clang: unchanged (EXP-052 path preserved) Correctness: 14/14 pass. Co-Authored-By: Claude Opus 4.8 --- include/fast_float/ascii_number.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 6c79509..371f3da 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -294,6 +294,17 @@ loop_parse_if_eight_digits(char const *&p, char const *const pend, p)); // in rare cases, this will overflow, but that's ok p += 8; } + // 4-digit SWAR follow-up (ported from ffc EXP-001): consume a remaining 4-7 + // digit run in one step rather than byte-by-byte. GCC path only — on Clang + // the follow-up's presence bloated the 2x-unroll codegen and regressed random. + if ((pend - p) >= 4) { + uint32_t const val4 = read4_to_u32(p); + if (is_made_of_four_digits_fast(val4)) { + i = i * 10000 + + parse_four_digits_unrolled(val4); // in rare cases overflows, that's ok + p += 4; + } + } #endif }