Repository navigation
epic: realize low-precision / quantized performance on the OpenXLA (IREE) backend #570
Description
Context
The OpenXLA / StableHLO backend (crate src/lib/mlxcel-xla, ADR docs/adr/0004-compute-backend-session-seam-and-stablehlo-family.md) runs the same portable graph on any IREE target (CPU, CUDA, Metal, and future NPUs via IREE HAL drivers). It is a portability / parity path, not a hand-tuned engine; MLX stays the primary Apple-Silicon backend.
Epic #513 landed the transferable low-precision arc up to f16 / bf16. Building on that:
- feat: f16/bf16 precision mode for the OpenXLA emitter and resident weights (#449) #514 / test: precision accuracy gate and per-device default precision for the OpenXLA backend (#449) #515 landed f16 / bf16 low precision (token-exact, ~1.9x on Metal) behind a precision accuracy gate.
- feat: int8 weight quantization with quantized matmul on the OpenXLA path (#449) #516 / feat: int8/int4 packed weight quantization on the OpenXLA path (#516) #568 landed int8 / int4 packed weight quantization (
MLXCEL_XLA_QUANT=packed, off by default): MLX 4/8-bit weights stay resident packed (ui32payload + f16 scales / biases) and are dequantized inside the StableHLO graph viaBuilder::dequant_affine. The loader uploads per-weight-dtype buffers through a new per-dtype weight ABI (iree.rs+csrc/xla_iree.c); the gate isConfig::supports_packed_quant(standard Llama layout). - fix(xla): load bf16 affine quant scales in the OpenXLA weight loader #569 broadened the dequant-at-load path to accept bf16 scales / biases (Qwen3 / Gemma3-27B / Qwen3-MoE MLX checkpoints), but the packed path still requires f16 scales (a known limitation to fold in).
The measured fusion gate (GB10, Grace-Blackwell, CUDA)
On GB10 with a source-built IREE CUDA runtime (Llama-3.2-1B 4-bit, greedy, warm vmfb) the packed path is token-exact with the f16 path but ~4.3x slower (~1.6 vs ~6.7 tok/s), GPU util 84% -> 96%.
Root cause: IREE's CUDA codegen does not fuse the in-graph unpack + dequant into the matmul. The decode step is ~678 dispatches and the reconstructed f32 weight is materialized to DRAM every step, so the packed path pays MORE bandwidth and compute than f16. iree-compile fusion flags (--iree-dispatch-creation-enable-aggressive-fusion, --iree-opt-generalize-matmul, --iree-dispatch-creation-enable-early-trunc-fusion) leave the dispatch count essentially unchanged (678 -> 677).
Conclusion: the memory-bandwidth payoff of quantization is not realized by authoring the dequant in the portable graph alone. It requires the TARGET to fuse dequant -> matmul (a quantized-matmul op / int8 dot_general lowering). ADR 0004 already scopes per-backend fused kernel codegen as upstream IREE's job; this epic operates exactly at that boundary.
Thesis
Land the low-precision performance that IS achievable on the IREE targets today, and de-risk the part that is not:
- Fusion-free win. Upload the resident (non-quantized) weights as f16 instead of f32, halving the per-step weight DRAM read with no dequant and no fusion required. This is enabled directly by the per-dtype weight ABI from feat: int8/int4 packed weight quantization on the OpenXLA path (#516) #568.
- Reproducible toolchain. Wrap the source-built IREE runtime (CUDA / Metal) in
maketargets so the measurement environment is reproducible rather than a local uncommitted artifact. - De-risk fusion with a spike that separates what is in-tree-achievable from what is upstream IREE work, then implement the fused quantized-matmul if in-tree-achievable, reversing the feat: int8/int4 packed weight quantization on the OpenXLA path (#516) #568 regression.
Non-goals
- Chasing MLX on Apple Silicon. MLX stays the default and primary Apple-Silicon backend; this is the portability path.
- Hand-writing Metal / CUDA kernels outside IREE, or tuning IREE's per-backend codegen (upstream work).
- New model families (use the existing config-driven emitter coverage).
Epic acceptance (functionally integrated deliverable)
By epic close, on a GPU IREE target:
- The low-precision path runs faster than the f32 baseline through the normal load / serve path (the f16-resident-weights win landed and defaulted where safe), gated by the test: precision accuracy gate and per-device default precision for the OpenXLA backend (#449) #515 accuracy harness.
- The IREE runtime build is reproducible via
make. - The quantized-matmul fusion is EITHER landed (int8 packed beats f16, reversing the feat: int8/int4 packed weight quantization on the OpenXLA path (#516) #568 regression, accuracy-gated) OR clearly characterized as upstream IREE work with the in-tree representation prepared.
Each piece must be wired into the real generation path and the default behavior, not left as a standalone module. References: ADR 0004, #513, #516 / #568.
Sub-issues
Phase 0
Phase 1
- feat: f16-resident weights on the OpenXLA path (fusion-free bandwidth win) #572 (depends on build: Makefile targets to source-build the IREE runtime (CUDA + Metal) #571)
- spike: quantized-matmul / dequant-to-matmul fusion investigation on IREE (CUDA first) #573 (depends on build: Makefile targets to source-build the IREE runtime (CUDA + Metal) #571)
Phase 2
- track(upstream-iree): fused dequant->matmul for the packed int8 bandwidth win #574 (depends on spike: quantized-matmul / dequant-to-matmul fusion investigation on IREE (CUDA first) #573): upstream IREE work (fused quantized-matmul), not in-tree achievable per spike: quantized-matmul / dequant-to-matmul fusion investigation on IREE (CUDA first) #573
Phase 3
- feat: extend the fused low-precision path to the Metal target #575 (depends on track(upstream-iree): fused dequant->matmul for the packed int8 bandwidth win #574): realized f16 lever validated on Metal (docs(xla): validate #575 low-precision transfer to Metal + oracle dumper #611), fused remainder tracked by track(upstream-iree): fused dequant->matmul for the packed int8 bandwidth win #574
Activity
build: reproducible IREE runtime toolchain via make targets (#576)
feat: f16-resident weights on the OpenXLA path (fusion-free bandwidth…
docs: fusion spike findings for the packed int8 path (#573) (#578)
inureyes commentedon Jul 2, 2026
Epic status: core acceptance met; the fused path characterized as upstream
Implemented sequentially on GB10 (this epic is hardware-in-the-loop and spike-driven, so autonomous parallel worktrees were not a good fit). Three of the four sub-issues are landed on main; the fourth is characterized as upstream per the spike.
Landed
make iree/iree-cuda/iree-metal/iree-env, plus a fresh-checkout submodule fix (benchmark + printf) and a read-only--info. Token-exact on GB10.scripts/xla/fusion_spike.sh) plus findings in the crate README.Characterized as upstream
Deferred
Against the epic acceptance:
make: met (build: Makefile targets to source-build the IREE runtime (CUDA + Metal) #571);build: reproducible IREE runtime toolchain via make targets (lablup#576)
feat: f16-resident weights on the OpenXLA path (fusion-free bandwidth…
docs: fusion spike findings for the packed int8 path (lablup#573) (la…