[MLAS] Reject Arm® KleidiAI™ Q4 prepack with dynamic scales - #32068
Hariharan Seshadri (hariharans29) merged 4 commits into
Conversation
|
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
Rejects KleidiAI Q4 prepacking when scales are runtime-provided, ensuring execution uses the unpacked fallback.
Changes:
- Detects non-initializer scales and declines incompatible prepacking/shared buffers.
- Adds dynamic-scale fallback and sharing tests.
- Includes the stacked KleidiAI QNBitGemm backend refactor from #31720.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
onnxruntime/contrib_ops/cpu/quantization/matmul_nbits.cc |
Adds dynamic-scale prepack fallback. |
onnxruntime/test/contrib_ops/matmul_4bits_test.cc |
Tests runtime scales and sharing. |
onnxruntime/test/mlas/unittest/test_sqnbitgemm.cpp |
Expands KleidiAI GEMM coverage. |
onnxruntime/core/mlas/lib/kleidiai/qnbitgemm_kleidiai.cpp |
Implements the dedicated backend. |
onnxruntime/core/mlas/lib/kleidiai/mlasi_kleidiai.h |
Declares QNBit overrides. |
onnxruntime/core/mlas/lib/kleidiai/kai_ukernel_interface.h |
Defines kernel wrappers. |
onnxruntime/core/mlas/lib/kleidiai/kai_ukernel_interface.cpp |
Updates relocated interface includes. |
onnxruntime/core/mlas/lib/qnbitgemm.cpp |
Routes operations through overrides. |
onnxruntime/core/mlas/lib/qnbitgemm.h |
Removes obsolete packed dispatch APIs. |
onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.cpp |
Removes embedded KleidiAI orchestration. |
onnxruntime/core/mlas/lib/qnbitgemm_kernel_neon.h |
Removes relocated declarations. |
onnxruntime/core/mlas/lib/sqnbitgemm_kernel_neon_int8.cpp |
Removes relocated packed kernels. |
onnxruntime/core/mlas/lib/platform.cpp |
Registers KleidiAI overrides. |
onnxruntime/core/mlas/lib/mlasi.h |
Adds override function pointers. |
onnxruntime/core/mlas/inc/mlas_qnbit.h |
Removes obsolete correction fields. |
cmake/onnxruntime_mlas.cmake |
Builds the dedicated backend. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… layer * Moved all KleidiAI-specific orchestration from qnbitgemm_kernel_neon into a new file `mlas/lib/kleidiai/qnbitgemm_kleidiai.cpp` * Changed the integration to go through an additional set of new overrides in platform.cpp, mirroring existing KleidiAI GEMM integrations * Removed obsolete zero-point correction in qnbitgemm_kleidiai Signed-off-by: Martin Klacer <martin.klacer@arm.com>
* Reject K == 0 from override selection in MlasQNBitGemmIsSupported * Treat zero M/N as no-op and return early in MlasQNBitGemmBatch * Add accompanying unit test coverage Signed-off-by: Martin Klacer <martin.klacer@arm.com>
Signed-off-by: Martin Klacer <martin.klacer@arm.com>
Signed-off-by: Martin Klacer <martin.klacer@arm.com>
76d6137 to
5587ec4
Compare
|
Review — PR #32068: Reject KleidiAI Q4 prepack with dynamic scales Scope clarification Per author note, this PR is stacked on #31720 (the KleidiAI QNBitGemm backend refactor). Three of the four commits ( The fix — bug and change The KleidiAI Q4 The change in matmul_nbits.cc generalizes the pre-existing "runtime-zero-points" prepack-decline into a runtime-quantization-parameter decline: const bool has_runtime_quantization_parameter =
!has_scales_initializer || (has_zp_arg && !has_zp_input);
return has_runtime_quantization_parameter && nbits == 4 && effective_compute_type == SQNBIT_CompInt8 &&
MlasQNBitGemmScalesPacked(K, nbits, block_size, effective_compute_type,
has_zp_arg, &backend_kernel_selector_config);Correctness by case (I walked all four combinations):
Behavior for the three unaffected rows is preserved; the two buggy rows now correctly fall back. ✓ The subtle-but-load-bearing The
The switch to Init and threading of Set in the constructor via Comment cleanup and error-message update
Test coverage New tests:
Both are properly The Missing coverage Asymmetric with runtime scales is a real case that the widened predicate handles ( Style nits
Non-issues I re-verified
Recommendation Approve — pending an asymmetric-with-runtime-scales test to close the coverage matrix. The core change is small, precisely targeted, and correctly extends an existing defensive pattern to prevent a real null-pointer UB in the KleidiAI pack path. The Merge order note: this PR must merge after #31720. Author already flagged. |
9cbf665
into
microsoft:main
Description
The Arm® KleidiAI™ Q4 path requires B and its scales to be packed together during session initialisation. Since runtime-provided scales are unavailable at that point, attempting to prepack B can pass a null scale pointer to the RHS packer causing undefined behavior.
This change declines B prepacking for nodes with dynamic scales and ensures that the existing unpacked fallback is used at execution. This matches the existing handling of dynamic zero points.
Motivation and Context
This fixes a pre-existing bug uncovered during the Q4 refactor in #31720.
The PR is a stacked follow-up based on the branch for #31720 and should be merged after it. The changes on this branch relevant to this PR are in the commit 76d6137 that builds on top of the previous commit (b1c03d8) under review in #31720.