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
2026-07-31· Case opened2026-08-04· PR opened