Context
`BufferBackend::extend_and_fill` (used for RLE block expansion + 0-fill paths) currently routes to `slice::fill(byte)` (UserSliceBackend) / `Vec::resize(_, byte)` (FlatBuf). Both lower to `__memset_avx_unaligned_erms` (libc).
Visible on low-entropy fixtures (high RLE content) as supplementary cost to the match-copy hot path (#256). Not the primary bottleneck, but ~5-15% on RLE-heavy decode.
Donor zstd does NOT pay libc memset on short RLE fills — it uses an inline SSE2 broadcast (`_mm_set1_epi8` + `_mm_storeu_si128` loop with overshoot) for fills <= ~256 bytes, falls back to memset only for large ones.
Proposal
Add an inline 16-byte SIMD broadcast path to `extend_and_fill` for fill_length in 1..=256 (or similar threshold). Pattern mirrors `copy_bytes_overshooting`:
- 1..=16: single `_mm_set1_epi8` + overlapping 16-byte store at offset 0 and offset (len-16) where len > 8
- 17..=256: loop `_mm_set1_epi8` 16-byte store with overlapping-tail finish
Both UserSliceBackend and FlatBuf get the same path. Falls through to `slice::fill` for fill_length > threshold.
Acceptance criteria
Blocked by: nothing.
Synergy: #256 (same simd_copy module gets analogous treatment).
Part of #247.
Context
`BufferBackend::extend_and_fill` (used for RLE block expansion + 0-fill paths) currently routes to `slice::fill(byte)` (UserSliceBackend) / `Vec::resize(_, byte)` (FlatBuf). Both lower to `__memset_avx_unaligned_erms` (libc).
Visible on low-entropy fixtures (high RLE content) as supplementary cost to the match-copy hot path (#256). Not the primary bottleneck, but ~5-15% on RLE-heavy decode.
Donor zstd does NOT pay libc memset on short RLE fills — it uses an inline SSE2 broadcast (`_mm_set1_epi8` + `_mm_storeu_si128` loop with overshoot) for fills <= ~256 bytes, falls back to memset only for large ones.
Proposal
Add an inline 16-byte SIMD broadcast path to `extend_and_fill` for fill_length in 1..=256 (or similar threshold). Pattern mirrors `copy_bytes_overshooting`:
Both UserSliceBackend and FlatBuf get the same path. Falls through to `slice::fill` for fill_length > threshold.
Acceptance criteria
Blocked by: nothing.
Synergy: #256 (same simd_copy module gets analogous treatment).
Part of #247.