Fix sorted gather_qmm NAX row overflow above 32K - #3922
Conversation
|
Independent final-patch review on the same M5 Max completed after the exact-source rebuild:
The reviewer also confirmed the declared scope boundary: untouched NVFP4 non-64 K tails still fail on current main/this branch and remain assigned to #3912. This PR does not claim otherwise. |
440075d to
d86fc87
Compare
|
I can confirm this works on M5 Max, thank you for the fix! LLM-generated report: Tested on M5 Max, macOS 26.5, MLX 0.32.0, a MoE model with 2-bit experts. I sent tokens through the model twice: once in a single forward pass, once in The model sends 10 rows to the gather kernel per token, so 4001 tokens make
A difference of about 2 is normal, because the two runs add numbers in a Prefill speed is 1903 tokens per second before and after the fix. |
|
Hey, please see #4009. Thanks! |
|
Thank you to the MLX maintainers and everyone who has taken the time to test and review these fixes. I really appreciate the opportunity to contribute. I’ll keep the remaining overlap and correctness questions in view so the patch is as straightforward as possible to evaluate. |
d86fc87 to
9cad37f
Compare
|
Recut onto current The PR is now intentionally limited to #3856's unique sorted-RHS NAX row-bound On M5 Max ( The current remote diff is exactly three files: the one-line kernel correction, |
9cad37f to
41aba66
Compare
|
Rebased onto the latest upstream main (8c28c38) after the recent merges. The current head is 41aba66. The diff remains intentionally limited to the three files already described, with no conflicts or whitespace errors; the focused M5 Max regression and full TestQuantized validation were completed on the unchanged patch before this rebase. Ready for CI approval and maintainer review. |
Keep the remaining M extent in int until after it is clamped to the SIMD-group tile size. This prevents ragged sorted-RHS workloads above the signed-short boundary from leaving output rows unwritten. Add a focused regression over the exact 32767/32768/32769 seam and an aligned control above it, using a dense fp32 oracle and allocator-poisoned outputs. Co-authored-by: OpenAI Codex <noreply@openai.com>
41aba66 to
bd8c825
Compare
|
Rebase and exact-head verification are complete at The frozen candidate was independently reviewed after the M5 Max rerun. Verdict: APPROVE, with no P0-P2 findings. The reviewer confirmed that the patch remains identical across the rebase, the Exact-head checks:
One non-blocking review note: the >32K regression selects BM=64 with |
Summary
Fixes #3856.
The sorted-RHS affine NAX kernel narrowed the remaining row count to
shortbefore clamping it to the SIMD-group tile size. For ragged workloads with
M > 32768, that intermediate conversion can wrap negative, causing earlytiles to leave output rows unwritten.
This keeps the remaining-row arithmetic in
intthrough the clamp and narrowsonly the final value. The regression test covers the exact signed-short seam,
an aligned control above it, a dense fp32 oracle, and two allocator-poison
values.
Scope
This recut intentionally contains only the failure class unique to #3856.
quantized.cpp, K/N-tail dispatch, and loader behavior are unchanged.sgp_snexpression is unchanged: its consumer is reached onlyon the final partial-N tile, where the remaining extent is already below 64.
Validation
Rebased onto upstream
mainat47a1bd613ebb67ed03da764c6ffedb8df9939997; candidate headbd8c825c2cad3d5ae3a6462f599c1a2320eeb9dd. The editable build reportsmlx 0.32.1.dev20260810+bd8c825c2andapplegpu_g17son Apple M5 Max.pre-clamp
shortconversion failed exactly atM=32769(31.2725maximumerror versus the
0.05limit), while controls remained clean;TestQuantized: 36/36 passed;applegpu_g16sfallback control: passed;git diff --check: passed;No performance claim is made; the change only corrects the row bound used by
the existing kernel.
Attribution
Philip John Basile is the primary author. Development and review used OpenAI
Codex assistance, disclosed in the commit trailer.