Skip to content

simd: saturating narrows down the 512-bit ladder (16x32 -> 32x16 -> 64x8) - #372

Merged
AdaWorldAPI merged 1 commit into
masterfrom
feat/simd-quant-primitives-20261024
Oct 24, 2026
Merged

AdaWorldAPI merged 1 commit into
masterfrom
feat/simd-quant-primitives-20261024

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

The codec8 SIMD path needs the saturating narrows from i32 to i16 and from i16 to i8/u8. This adds them as steps on the 512-bit ladder (16×32, 32×16, 64×8), on every backend:

  • I32x16::narrow_saturating_i16(hi) -> I16x32
  • I16x32::narrow_saturating_i8(hi) -> I8x64
  • I16x32::narrow_saturating_u8(hi) -> U8x64

Lanes 0..N come from self and N..2N from hi. Each lane is clamped to the narrow range.

The first version of this PR narrowed I32x16 -> I8x16/U8x16. That is a 128-bit result and is not on the ladder, so it is replaced here.

backend how
AVX-512 vpmovsdw / vpmovswb / vpmovuswb, then vinserti64x4 (u8 first raises negative lanes to 0)
AVX2 / AVX SSE2 packssdw / packsswb / packuswb over 16-byte quarters
NEON sqxtn / sqxtun + vcombine
wasm simd128 i16x8_narrow_i32x4, i8x16_narrow_i16x8, u8x16_narrow_i16x8
scalar clamp
nightly simd_clamp + cast

Two backend notes:

  • wasm: I16x32 / I8x64 / U8x64 come from the scalar backend on wasm. Their narrows are therefore implemented in simd_wasm.rs, and the scalar versions are cfg-gated off for that arm.
  • aarch64: the facade now re-exports the NEON I16x32 / I8x64 (+ i16x32 / i8x64). simd_neon.rs already had both types, but no arm re-exported them.

Nightly also keeps F32x16::cast_i32 and gains I32x16::cast_f32, which the other backends already had.

Verification

  • Parity group 0x10xx in simd-masking-parity:
    • inputs: an edge set plus 63 random rounds;
    • the chained i32→i16→i8/u8 result is compared with a single clamp;
    • the in-range f32↔i32 casts are compared with as;
    • anti-vacuity: some lanes must saturate and some must pass through unchanged.
  • All 8 arms pass, 17 groups bit-identical: native v4, native v3, avx-qemu, v2-qemu, neon-qemu, wasm, wasm-scalar, nightly.
  • Disable run: with the AVX-512 u8 "raise negatives to 0" step removed, the parity check fails with 0x1080, the u8 lane holding i32::MIN.
  • Lowered assembly (#[inline(never)] wrappers, release):
    • v4: two vshufi64x2 + one vpackssdw / vpacksswb / vpackuswb per narrow. LLVM folded the max + vpmovuswb into vpackuswb.
    • v3: four 128-bit packs per narrow.
    • No scalar code on either.
  • cargo clippy --lib -D warnings is clean on v4 and v3. The 6 new doctests pass (v4, release).

Not in this PR

The wasm F32x16::mul_add / F64x8::mul_add fix comes in its own PR. Today those are unfused (two roundings), or nondeterministic under relaxed-simd.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg

…ly casts

The codec8 encode composes from the polyfill: Div, round (ties-even),
floor, simd_clamp, abs, simd_ge, select and the F32x16/I32x16 casts
already exist on every stable arm. Two pieces did not:

- I32x16::narrow_saturate_i8 -> I8x16 and narrow_saturate_u8 -> U8x16,
  on all six I32x16 owners, each with its ISA's saturating pack:
  AVX-512 vpmovsdb / vpmovusdb (lanes raised to 0 first, the unsigned
  form reads them unsigned), AVX2 and AVX-only SSE2 packssdw +
  packsswb / packuswb, NEON sqxtn / sqxtun, wasm i16x8_narrow_i32x4 +
  i8x16_narrow_i16x8 / u8x16_narrow_i16x8, scalar clamp, nightly
  simd_clamp + cast.
- The nightly realization lacked F32x16::cast_i32 and
  I32x16::cast_f32, which every other arm has.

simd-masking-parity group 0x10xx checks both narrows against clamp
over 513 vectors (edges plus random, with an anti-vacuity floor on
saturated lanes in both directions), cast_f32 against 'as f32' bits
and cast_i32 against 'as i32' on in-range lanes. Passes on all eight
realizations: AVX-512, AVX2, AVX-only (qemu SandyBridge), v2/scalar
(qemu Nehalem), NEON (qemu), wasm simd128 and wasm scalar (node),
nightly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review October 24, 2026 14:55
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-24T14:56:25.094488Z e07be5b Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Add Carrot credits or activate Agent usage billing to use Autofix

@AdaWorldAPI
AdaWorldAPI merged commit 628386b into master Oct 24, 2026
29 checks passed
@AdaWorldAPI AdaWorldAPI changed the title feat(simd): I32x16 saturating narrow to I8x16/U8x16 on every backend; nightly casts simd: saturating narrows down the 512-bit ladder (16x32 -> 32x16 -> 64x8) Oct 24, 2026

Copy link
Copy Markdown
Owner Author

This PR merged at e07be5b, which has the off-ladder I32x16 -> I8x16/U8x16 narrow. The ladder rework (dc26129) reached this branch after the merge, so the description above does not match what landed. The ladder is now in #373.


Generated by Claude Code

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.

2 participants