[MLAS] Add ARM64 2-bit weight CPU kernels (#29466)
## Summary
Adds a new ARM64 NEON implementation of the 2-bit `MatMulNBits`
(`SQNBIT_CompInt8`, `BlkBitWidth=2`) path built on `SDOT` + in-kernel
2-bit unpack. Replaces the previous ARM64 W2 fallback, which dequantized
the 2-bit weights to fp32 and dispatched them through the standard fp32
GEMM — correct but far below the achievable throughput for a native
int8-dot kernel. Also fixes a correctness bug in `MatMulNBits` that
mis-handled the MLFloat16 A-input variant on the `accuracy_level=4`
(CompInt8) code path on ARM64.
This is the ARM64 equivalent of the PR
https://github.com/microsoft/onnxruntime/pull/29064
## What's in the PR
### New ARM64 W2 DotProd kernel family
`onnxruntime/core/mlas/lib/sqnbitgemm_kernel_neon_int8_2bit.cpp` (new
TU)
- Native `SDOT`-based kernels for `BlkLen ∈ {32, 64, 128}`.
- Templated `R{1,2} × C{1,4,8}` DotProd tile grid — one implementation
covers the full `M × N` register-tile matrix instead of six copy-pasted
variants.
- In-kernel 2-bit → int8 unpack via `vsubq_s8(B, 2)`; B zero-point
folded into the unpack so no post-kernel `BlkSum` SGEMM is needed. Same
shape as the ARM64 W4 DotProd path.
- Dispatch plumbing in `qnbitgemm.{cpp,h}` and
`qnbitgemm_kernel_neon.{cpp,h}` routes `BlkBitWidth==2` through the new
TU on ARM64 hosts with DotProd (Neoverse, Cortex-A76+, Snapdragon X,
Apple M-series).
### `MatMulNBits` fp16 A-input CompInt8 fix
`onnxruntime/contrib_ops/cpu/quantization/matmul_nbits.cc`
- The MLFloat16 specialization of `PrePack` did not follow the same
eager-fold path as the fp32 specialization, so the ARM64 CompInt8 W2
dispatch could mis-select a kernel or use un-recomputed `QuantBBlkSum`
values when the A-input is fp16 and `accuracy_level=4`.
- Fixed by routing the MLFloat16 `PrePack` through a mirror of the fp32
CompInt8 pipeline, and by having the W2 zero-points callback recompute
`QuantBBlkSum = -scale × zp` from `scales_fp32_` consistently for both
element types.
- A `packed_b_finalized_` flag now guards the single-shot CompInt8
packing so a re-entrant `PrePack` cannot double-pack.
### Docs
- `docs/Arm64_w2_kernel_future_enhancements.md` — forward-looking notes
on the two follow-ups (SMMLA-based I8MM TU; lane-indexed SDOT for the C8
tile). Not required for this PR to land; captures the design context so
the next contributor doesn't re-derive it.
## Performance
**Throughput comparison (tok/s):**
| seq_len | W4 (1.27 release) | W2 (1.27 release, DeQuant + fp32 GEMM) |
**W2 (PR)** | W2 PR vs W2 1.27 | W2 PR vs W4 1.27 |
|---|---|---|---|---|---|
| 32 | 878.3 | 130.7 | 757.2 | 5.8× | 0.86× |
| 64 | 904.4 | 220.3 | 953.4 | 4.3× | 1.05× |
| 128 | 797.7 | 318.2 | 1032.0 | 3.2× | 1.29× |
## Notes / follow-ups (not in this PR)
- SMMLA-based W2 I8MM TU for `FEAT_I8MM` hosts (R2+ tiles, ~2× dot
throughput).
- Lane-indexed SDOT for the C8 tile (A-load reduction).
- Both are described in `docs/Arm64_w2_kernel_future_enhancements.md` §1
and §2.