Skip to content

refactor: read decode words unaligned, dropping the align_to prefix - #39

Merged
bonega merged 1 commit into
masterfrom
unaligned-word-decode
Jul 4, 2026
Merged

refactor: read decode words unaligned, dropping the align_to prefix#39
bonega merged 1 commit into
masterfrom
unaligned-word-decode

Conversation

@bonega

@bonega bonega commented Jul 4, 2026

Copy link
Copy Markdown
Owner

What

Replace the align_to::<usize>() word-at-a-time structure in both bulk decoders with chunks_exact(USIZE_SIZE) + usize::from_ne_bytes, reading each word unaligned.

Why

The aligned-read design forced a byte-wise decode of the misaligned prefix. LLVM compiles that ≤7-byte prefix loop as a generic %4-remainder loop plus a 4×-unrolled loop, and its unroll cost model cannot be coaxed into the early-exit ladder it emits for the suffix (unreachable_unchecked, length masking, and a hand-unrolled source ladder were all tried — the last one gets re-rolled). Unaligned word loads are a single mov on x86-64/AArch64, and from_ne_bytes compiles to whatever load the target supports, so the prefix problem can simply be removed instead of fixed.

This also makes the len < USIZE_SIZE scalar fallback and the align_of guard unnecessary, and drops the prefix-offset term from the incomplete decoder's error positions.

Results

  • Assembly for a monomorphized decode: −41% (complete, 378 → 222 lines) / −34% (incomplete, 478 → 315 lines); the main-loop word read is a single unaligned mov, the tail keeps its early-exit ladder, and the safe try_into().unwrap() leaves no panic branch.
  • Benchmarks (decode_checked, decode_lossy, back-to-back vs master with setarch -R/taskset): neutral within noise.

Verification

  • cargo test (144 passed), cargo clippy --all-targets -- -D warnings, cargo fmt --check
  • Miri writer_stress under Stacked Borrows, Tree Borrows, and big-endian s390x; Miri lib tests --all-features
  • thumbv7em-none-eabi no-std builds (bare + alloc)

https://claude.ai/code/session_01D3JXrJnefe7pWs3kJRvTjz

@bonega
bonega force-pushed the unaligned-word-decode branch from 51a4cce to 556f19f Compare July 4, 2026 19:08
The bulk decoders read aligned usize chunks via align_to, which forced a
byte-wise decode of the misaligned prefix. LLVM compiles that <=7-byte
prefix loop as a generic remainder-plus-4x-unrolled structure and its
cost model can't be hinted into specializing it, so every monomorphized
decode carried the extra loop machinery.

Read each word with chunks_exact + usize::from_ne_bytes instead: the
unaligned load is a single mov on x86-64/AArch64 and stays correct on
strict-alignment targets. This removes the prefix entirely, along with
the len < USIZE_SIZE scalar fallback, the align_of guard, and the
prefix-offset term in the incomplete decoder's error positions.

Assembly for a monomorphized decode shrinks ~40% (complete) and ~34%
(incomplete); decode benchmarks are neutral. Verified with Miri
(Stacked/Tree Borrows, big-endian s390x) and thumbv7em no-std builds.

Claude-Session: https://claude.ai/code/session_01D3JXrJnefe7pWs3kJRvTjz
@bonega
bonega force-pushed the unaligned-word-decode branch from 556f19f to 48dd6c7 Compare July 4, 2026 19:10
@bonega
bonega enabled auto-merge (squash) July 4, 2026 19:15
@bonega
bonega merged commit 083f188 into master Jul 4, 2026
8 checks passed
@bonega bonega mentioned this pull request Jul 17, 2026
bonega added a commit that referenced this pull request Jul 17, 2026
Perf/code-size only, no API changes.

- Bulk decode of mostly-ASCII input ~12-15% faster (niche-packed
  NonZeroU32 table entries, #36).
- Monomorphized bulk decode ~40%/34% smaller from unaligned word
  reads, throughput unchanged (#39).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant