Pack mixed-width UTF-32 blocks from width/error masks instead of scalarizing them

perfloop/simdutf · DATA PARALLEL GAP

https://perfloop.ai/t/oss/case_nqbvgjwvc2

Verdict

VERIFIED · settled 2026-08-01 · pull request opened as simdutf/simdutf#1018

What happened: The paired measurements met the required improvement.

Hypothesis

The public entry in `src/implementation.cpp` forwards through the selected implementation, and the fallback hop in `src/fallback/implementation.cpp` immediately hands the entire buffer to `scalar::utf32_to_utf8::convert_with_errors`; that leaf has only a two-code-point ASCII check before its per-code-point width branches, error checks, and byte stores. This is broader than the published ASCII widening: mixed 1/2/3/4-byte input still takes the scalar shape, and the ISA sources expose the same structural bailout—`src/haswell/avx2_convert_utf32_to_utf8.cpp` falls into a scalar loop when a block contains a value above `0xFFFF`—despite the existing width-keyed packing tables in `src/tables/utf16_to_utf8_tables.h`. Carrying a compact width/error plan across the entry, dispatch, and leaf would remove that per-code-point branch-and-bailout class for valid mixed and non-BMP blocks; the remaining floor would be block loads, classification/validation, packed stores, and scalar work only for a tail or the first failing block. A later case should falsify this with an end-to-end, forced-fallback and per-ISA `convert_utf32_to_utf8_with_errors` benchmark using exact-size output buffers and ASCII, mixed-width, emoji-heavy, and every-lane error-position inputs, checking cycles per input scalar and latency alongside exact output and `result` semantics; reject the change if mixed/non-BMP cases do not improve without an ASCII regression.

Change to test: Introduce a shared internal block-transcode contract selected once by `convert_utf32_to_utf8_with_errors`: classify each 4- or 8-code-point block into a 2-bit UTF-8-width plan plus an invalid-lane mask, use a 1/2/3/4-byte packing table or backend vector-compress primitive to emit an all-valid mixed block, and scalarize only the prefix of the one block containing the first invalid lane. Route the public entry, implementation dispatch, fallback implementation, and ISA backends through that contract; retain the already-published widened ASCII route as an earlier fast path and preserve the exact error code and input index.

Where it lives

perfloop/simdutf · src/implementation.cpp

Evidence

Haswell AVX2, 32768-scalar all-width mixed UTF-32 to UTF-8 · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 4.817 1.117 −76.7% (−3.694) −3.726 to −3.671 < 0 PASSED
ns/call 157831 36597 −76.7% (−121056) −122098 to −120303 < 0 PASSED

Haswell AVX2, 32768-scalar mixed UTF-32 after a BMP prefix · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 4.793 1.119 −76.7% (−3.675) −3.706 to −3.65 < 0 PASSED
ns/call 157067 36680 −76.7% (−120419) −121454 to −119612 < 0 PASSED

Haswell AVX2, 32768-scalar emoji UTF-32 to UTF-8 · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 2.136 0.2724 −87.4% (−1.867) −1.885 to −1.836 < 0 PASSED
ns/call 69990 8926 −87.4% (−61168) −61776 to −60163 < 0 PASSED

Haswell AVX2, 32768-scalar ASCII UTF-32 to UTF-8 · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 0.1497 0.08457 −43.5% (−0.06509) −0.06598 to −0.06341 ≤ 0 PASSED
ns/call 4904 2771 −43.5% (−2133) −2162 to −2078 ≤ 0 PASSED

Forced fallback SSE4.1, 32768-scalar all-width mixed UTF-32 to UTF-8 · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 1.657 1.349 −18.3% (−0.303) −0.343 to −0.2962 < 0 PASSED
ns/call 54310 44207 −18.3% (−9929) −11239 to −9706 < 0 PASSED

Forced fallback SSE4.1, 32768-scalar mixed UTF-32 after a BMP prefix · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 1.663 1.36 −18.1% (−0.3017) −0.3199 to −0.2135 < 0 PASSED
ns/call 54485 44549 −18.1% (−9885) −10481 to −6997 < 0 PASSED

Forced fallback SSE4.1, 32768-scalar emoji UTF-32 to UTF-8 · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 2.398 1.348 −43.9% (−1.052) −1.086 to −1.016 < 0 PASSED
ns/call 78591 44158 −43.9% (−34476) −35596 to −33285 < 0 PASSED

Forced fallback SSE4.1, 32768-scalar ASCII UTF-32 to UTF-8 · 10 sample pairs

metric baseline candidate paired median change confidence range required result
ns/input_scalar 0.4209 0.3787 −9.7% (−0.04066) −0.0504 to −0.03853 ≤ 0 PASSED
ns/call 13793 12410 −9.7% (−1332) −1651 to −1262 ≤ 0 PASSED

Checks: 2 of 2 passed. Verification: no defect found.

Timeline