[BUG] JIT build: attention_nax_dsplit fails to compile (extra bv template argument)
Maintainers usually reply within 3 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- cpp
- Domain
- backend, performance
Research direction
Read mlx/backend/metal/jit_kernels.cpp at get_steel_attention_nax_kernel and compare its attention_nax_dsplit template arguments with instantiate_attn_dsplit in mlx/backend/metal/kernels/steel/attn/kernels/steel_attention_nax.metal. Reproduce with the provided bf16 SDPA case on an M5 using a JIT build; done means the dsplit kernel compiles and returns results matching a precompiled build.
Written by the indexing model from the issue text.
Description
Summary
On an M5 (NAX) GPU, a JIT build of MLX fails to compile the head-dim-split attention kernel the first time a fused SDPA takes it (head dim 256, query length >= 1024, bf16, causal or array mask). The process then aborts:
[metal::Device] Unable to build metal library from source
mlx/backend/metal/kernels/steel/attn/kernels/steel_attention_nax.h:950:122: error: reference to overloaded function could not be resolved; did you mean to call it?
template [[host_name("steel_attention_dsplit_bfloat16_bq64_bk32_bd256_bv256_wm4_wn2_maskbfloat16")]] [[kernel]] decltype(attention_nax_dsplit<bfloat16_t, 64, 32, 256, 256, 4, 2, bfloat16_t>) attention_nax_dsplit<bfloat16_t, 64, 32, 256, 256, 4, 2, bfloat16_t>;
mlx/backend/metal/kernels/steel/attn/kernels/steel_attention_nax.h:525:66: note: possible target for call
mlx/backend/metal/kernels/steel/attn/kernels/steel_attention_nax.h:950:192: error: explicit instantiation of 'attention_nax_dsplit' does not refer to a function template, variable template, member function, member class, or static data member
attention_nax_dsplit is declared template <typename T, int BQ, int BK, int BD, int WM, int WN, typename MaskType = float, typename AccumType = float>, with no BV. The precompiled instantiation (instantiate_attn_dsplit in steel_attention_nax.metal) passes dtype, bq, bk, bd, wm, wn, mtype, float, which matches. But get_steel_attention_nax_kernel in mlx/backend/metal/jit_kernels.cpp passes type, bq, bk, bd, bv, wm, wn, mask_type for both attention_nax and attention_nax_dsplit, so in the dsplit case every argument after bd shifts by one. This is still the case on main.
Builds that use nojit_kernels.cpp aren't affected. mlx-swift always builds jit_kernels.cpp, so every mlx-swift app on an M5 hits this.
To Reproduce
We hit this through mlx-swift 0.33.0, which vendors MLX v0.32.4 (36969c0), running a bf16 Qwen 3.5 model (head dim 256) with a prompt of more than 1024 tokens in one forward pass. The equivalent in Python should need an MLX built with -DMLX_METAL_JIT=ON, on an M5:
import mlx.core as mx
q = mx.random.normal((1, 16, 1024, 256)).astype(mx.bfloat16)
k = mx.random.normal((1, 4, 1024, 256)).astype(mx.bfloat16)
v = mx.random.normal((1, 4, 1024, 256)).astype(mx.bfloat16)
o = mx.fast.scaled_dot_product_attention(q, k, v, scale=256**-0.5, mask="causal")
mx.eval(o)
Expected behavior
The kernel compiles and SDPA returns the same result as the precompiled build. Possible fix: drop bv from the template arguments in get_steel_attention_nax_kernel when split_d is true.
Desktop (please complete the following information):
- OS Version: macOS 27.2, Apple M5 Max
- Version: MLX v0.32.4 (36969c0) through mlx-swift 0.33.0; the same code is on main
Additional context
Head dim 512 (for example Gemma 4's global layers) takes the same dsplit path for long causal prefills. Inputs under 1024 query tokens take the unfused path and don't crash.
- Dominant language
- C++
- Stars
- 29.1k
- Forks
- 2.4k
- Avg merge
- 3d 20h
- Merged PRs (30d)
- 103
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from ml-explore/mlx
-
[BUG] `mx.expand_dims` docs: the Args section names `axes`, but the parameter is `axis`Possibly taken @Redempt1onzzZZ claimed this 3 days ago. Open
Difficulty 1/5 Under an hour Newbie friendliness 88/100
ml-explore/mlx#4829 ·
Maintainers usually reply within 3 days
-
[BUG] `mx.qqmm` docs: the Args section names `global_scale`, but the parameter is `global_scale_x`Possibly taken @XXXXRT666 claimed this 5 days ago. Open
Difficulty 1/5 Under an hour Newbie friendliness 92/100
ml-explore/mlx#4815 ·
Maintainers usually reply within 3 days
-
[BUG] FP4 quantization on CPU rounds ties toward zero while Metal rounds to evenMay be free again A pull request for this issue was closed without being merged. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
ml-explore/mlx#4753 ·
Maintainers usually reply within 3 days
-
Difficulty 4/5 3-5 days Newbie friendliness 43/100
ml-explore/mlx#4843 ·
Maintainers usually reply within 3 days
-
Metal cache admission can exceed the configured cache limitPossibly taken @tijs claimed this 1 day ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 25/100
ml-explore/mlx#4841 ·
Maintainers usually reply within 3 days
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
arvidn/libtorrent#9126 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Sunrisepeak/mcpp-language-server#80 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
xiaoyifang/goldendict-ng#3148 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 91/100
triton-inference-server/server#9069 ·
Maintainers usually reply within 1 day