Fix #31573, prevent ARM64 SymmQgemm int16 overflow - #32057
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
@microsoft-github-policy-service agree |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR fixes a known overflow issue in the plain-NEON (non-dotprod) SymmQgemm S8 kernel on Arm64/AArch64, and removes the corresponding unit-test skip so the signed-input test runs on non-dotprod hosts again.
Changes:
- Reworked the NEON kernel inner loops to avoid int16 accumulation overflow by reducing into 32-bit accumulators between half-vector multiplies.
- Removed the Arm NEON dotprod capability guard (and related include) that previously skipped the signed-input SymmQgemm test on non-dotprod hosts.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| onnxruntime/test/mlas/unittest/test_symm_qgemm_fixture.h | Removes the runtime feature skip so the signed-input SymmQgemm test executes on plain-NEON hosts. |
| onnxruntime/core/mlas/lib/arm64/SymQgemmS8KernelNeon.asm | Updates the Arm64 NEON kernel to avoid int16 accumulator overflow by accumulating via 32-bit reductions. |
| onnxruntime/core/mlas/lib/aarch64/SymQgemmS8KernelNeon.S | Mirrors the Arm64 kernel fix in the AArch64 assembly source. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
03f2122 to
b93001b
Compare
b4e0fc9 to
1550204
Compare
|
Hariharan Seshadri (@hariharans29) Could you please authorize the CI runs and review this PR when convenient? The branch is now updated to current main and the diff is limited to the two NEON SymmQgemm kernels plus the regression-test guard. The overflow explanation requested by Copilot is now in both assembly files and references #31573. For the performance comment, the repository already has onnxruntime_mlas_benchmark with SYMMQGEMM/SignedActivation. I do not have representative non-dotprod Arm64 hardware for a trustworthy throughput comparison; forcing the NEON path on dotprod-capable hardware would not provide representative performance data. This PR also removes the guard added in #31606, as requested in #31573. |
|
Review — PR #32057: Fix ARM64 SymmQgemm int16 accumulator overflow (#31573) Summary of changes (3 files, 2 commits)
The diagnosis is correct — I verified it against the pre-PR file I looked at the current on-disk SymQgemmS8KernelNeon.S lines 143–150. The pattern is exactly: For the pathological case The reordering is bitwise-identical for correct inputs
Both expand to the same int32 sum of four products. Because the accumulation is now in int32 throughout, the overflow window at int16 is closed. For any input where the old code did not overflow, the new code produces identical bits. ✓ The perf trade-off Copilot flagged is real but bounded Old inner-block (four output cols, one A-row group): 4 smull + 4 smlal + 4 sadalp = 12 NEON ops. That's +33% NEON-pipe instructions on the fused-multiply-then-widen path. On A55 (in-order, dual-issue, one NEON pipe), that's close to a 1:1 wall-clock hit for the multiply-widen stage — probably 10–20% overall kernel slowdown after amortizing load/loop overhead. Copilot's suggested I think this trade is right for merge as-is:
Test guard removal is correct The removed guard from #31606 explicitly said "Skip on hosts that would fall back to it instead of failing; drop this guard once that kernel is fixed." That preconditioned drop is being honored here, and the CI ARM64 lanes will now actually exercise the fix on any non-dotprod code path they cover. Dropping the Minor comments
Recommendation Approve. Correctness fix for a shipping bug, mirror-edited in both |
|
Thanks Hariharan, appreciate the detailed review and validation, and for getting the CI running. The follow-up suggestions make sense, particularly broader M-loop regression coverage and keeping any performance optimization as a separate follow-up. |
Thanks for this fix. Should we consider adding in the M-loop regression test for this PR ? What are your thoughts on this matter ? |
I checked the existing signed-input regression coverage. It already registers M = {1, 2, 3, 4, 5, 7, 8, 9}, so it exercises the M1, M2 and M4 paths directly as well as mixed/tail combinations. Given that, I don't think a separate M-loop regression test would add meaningful coverage here. Happy to make that intent more explicit in the test if you prefer. |
Sounds good, we can leave it as such then, thanks. There are a couple of unstarted CI checks blocking merge. Can you please rebase with main to see if that is mitigated with that ? |
Widen each 8-lane int8 product group into the int32 accumulators before multiplying the second half of the packed K block. This avoids the signed int16 overflow that occurs when two -128 * -128 products share a halfword lane. Enable the existing signed-input regression coverage on non-dotprod ARM64 now that the plain NEON path is corrected.
Explain why each product group must be reduced into int32 before the next multiply so future kernel changes do not reintroduce microsoft#31573.
1550204 to
46cc6c1
Compare
Done, I’ve rebased the branch onto the latest Could you please authorize them again when convenient? Thanks! |
f73b9ef
into
microsoft:main
Widen each 8-lane int8 product group into the int32 accumulators before multiplying the second half of the packed K block. This avoids the signed int16 overflow that occurs when two
-128 * -128products share a halfword lane.Description
Motivation and Context
Fixes #31573.
The previous
smull+smlalsequence accumulated two int8 products in a signed int16 lane before widening. For the extreme case,(-128 * -128) + (-128 * -128) = 32768, which overflows int16. The revised sequence reduces each product group into the int32 accumulators before processing the second half of the packed K block.Validation
The existing signed-input regression test is re-enabled for non-dotprod ARM64. The repository also contains
onnxruntime_mlas_benchmarkwithSYMMQGEMM/SignedActivation; no representative non-dotprod Arm64 hardware was available for a trustworthy throughput comparison, so no performance numbers are claimed here.