Skip to content

qwen: merge tensors on convert - #31028

Merged
ggerganov merged 3 commits into
masterfrom
aman/qwen4exp-hc-inject-merge
Oct 25, 2026
Merged

ggerganov merged 3 commits into
masterfrom
aman/qwen4exp-hc-inject-merge

Conversation

@am17an

@am17an am17an commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Overview

There are a few tensors in the qwen graph which share the same activations, this PR merges their weight on convert (similar to --fuse-gate-up-exps) but for these smaller tensors. Using the new GGUF is +7% TG and +5% prefill for me on my setup.

Additional information

Requirements

@am17an
am17an requested review from CISC and ggerganov as code owners October 23, 2026 06:42
@github-actions github-actions Bot added model Model specific conversion labels Oct 23, 2026
Comment thread conversion/qwen4exp.py Resolved
Comment thread src/models/qwen4exp.cpp
Comment on lines +231 to +246
// matmuls that read the same input: try the merged [a | b] weight the converter writes, else the separate ones
auto create_merged = [&](llm_tensor t_merged, llm_tensor t_a, llm_tensor t_b, int64_t n_in, int64_t n_a, int64_t n_b,
ggml_tensor *& merged, ggml_tensor *& a, ggml_tensor *& b) {
if (flags & TENSOR_SKIP) {
const int skip = TENSOR_NOT_REQUIRED | TENSOR_SKIP;
create_tensor(tn(t_merged, "weight", il), { n_in, n_a + n_b }, skip | TENSOR_SKIP_IF_VIRTUAL);
create_tensor(tn(t_a, "weight", il), { n_in, n_a }, skip);
create_tensor(tn(t_b, "weight", il), { n_in, n_b }, skip);
return;
}
merged = create_tensor(tn(t_merged, "weight", il), { n_in, n_a + n_b }, flags | TENSOR_NOT_REQUIRED | TENSOR_SKIP_IF_VIRTUAL);
if (!merged) {
a = create_tensor(tn(t_a, "weight", il), { n_in, n_a }, flags);
b = create_tensor(tn(t_b, "weight", il), { n_in, n_b }, flags);
}
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a good time to just introduce OTF merging?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OTF is harder problem because that involves changing llama-model-loader and last time I did it seems to break mmap and a bunch of other things.

@am17an am17an added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Oct 24, 2026
@ggerganov

Copy link
Copy Markdown
Member

Is the merge done unconditionally or do we need to pass some extra flag to the convert script?

@am17an

am17an commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor Author

It's done unconditionally. I don't see a reason to not merge them

Comment thread src/models/qwen4exp.cpp Resolved
@ggerganov
ggerganov merged commit 2280f0f into master Oct 25, 2026
26 checks passed
@ggerganov
ggerganov deleted the aman/qwen4exp-hc-inject-merge branch October 25, 2026 13:23
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 26, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
edwardyoon added a commit to edwardyoon/focus-llama that referenced this pull request Oct 26, 2026
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 26, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 26, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 26, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 27, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 31, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 31, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 31, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Oct 31, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 1, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 2, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 2, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 3, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 3, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 4, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 4, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 5, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 5, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 5, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 5, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 6, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 6, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 7, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
stew675 pushed a commit to stew675/llama.cpp that referenced this pull request Nov 8, 2026
…r, QSA/indexer)

The qwen4exp (Qwen3.8-Flash-Next) architecture support, split out of the old
block 10 (r109) so the model graph, the sparse-attention op and the
hyper-connections no longer share a commit with the slab, the fusion dispatcher
and the async input ring.  The tree is unchanged: block 10 plus this commit is
exactly what the old block 10 carried.

Contents:

- src/models/qwen4exp.cpp: the model, the HC (hyper-connection) graph, the MTP
  draft head, the PLE gather, the QSA selection/attention graph
  (build_qsa_store_k / build_qsa_top_k / build_attn_qsa) and the QSA arm policy.
- QSA/indexer: fattn-qsa.{cu,cuh}, fattn-qsa3.cu, indexer-score.{cu,cuh},
  indexer-topk.{cu,cuh}, the 4-head WMMA indexer scorer in lightning-indexer.cu,
  with the CUDA dispatch (GGML_OP_FLASH_ATTN_QSA / INDEXER_TOPK / INDEXER_SCORE /
  INDEXER_FILL) and their CPU references; the keys-only indexer cache
  (LLAMA_QSA_KEYS_ONLY, no V tensor at all) in llama-memory-hybrid-idx and the
  v_enabled parameter on llama_kv_cache.
- HC ops GGML_OP_HC_MIX / HC_COMBINE (dispatch, supports_op, the Meta split
  states, the hc_combine_mix / hc_mix / hc_combine_norm / hc_gate_mix fusion
  arms and the HC16 planar layout) in hc-mix.{cu,cuh} and hyperconn.{cu,cuh}.
- The managed lazy reader (llama-lazy-reader) and the loader's managed_budget
  (LLAMA_LAZY_BUF_MB, TENSOR_SKIP_MANAGED, lazy_read::add_range) for the PLE
  n-gram table; off by default (it measured slower than both the mmap and the
  resident path on gfx1151).
- The QSA/HC op definitions in ggml.h / ggml.c, the scheduler op allowlists, the
  CPU references, and the qwen4exp tensor-split arch gate in llama-arch.cpp (with
  the ggml-hip CMakeLists publishing GGML_USE_HIP to the main libraries so the
  dynamic-backend build reads it).
- The qwen4exp MTP draft context gets a hybrid-idx memory instead of a plain KV
  cache (LLAMA_MTP_SPARSE=0 restores the dense draft), and llama_memory_recurrent
  stops warning about the speculative verify positions for a context whose
  recurrent filter matches nothing.
- Loader/user-path fix: TENSOR_READ_LAZY is only consulted when the loader has
  files (the llama_model_init_from_user path has nothing to lazy-read from).
- The qwen4exp-family fusion arms that live in this block's own TUs, and the
  graph-optimizer passes they need: the HC_BLK16/RES16 BF16-stream marks and
  their alloc deps, and the prefill indexer relu-sum alloc dep.
- Tests: test-hc-mix and test_flash_attn_qsa in test-backend-ops (the QSA CPU
  oracle: `test-backend-ops -o FLASH_ATTN_QSA`, 18/18 minimum), test-lazy-reader,
  and the lazy_buf_size handover in test-llama-archs.

Split note (r109): the infrastructure this block is built on -- the slab, the
fusion dispatcher TU, the async input ring, the GDN/MMB/HC16 kernel work -- is
block 10 and is listed there.  A qwen4exp-only change that is implemented inside
a general kernel TU (the GDN gate/beta BF16 fusion, the HC16 MMB BF16 streams,
the weighted-down reduction, the PLE conv fusion) deliberately stays with that
TU in block 10; only the code that needs this block's own symbols is here.

- The separate-tensor (pre-ggml-org#31028) HC mixer emits its inject product right
  behind the down product, i.e. adjacent in the graph, and expands both: the two
  BF16 GEMMs read the same F32 `xn`, and the CUDA BF16 src1 cache (block 10)
  only holds one converted tensor.  ggml-org#31028's ordering (inject last, after the
  gate product whose src1 is the silu output, which evicts the entry) converted
  the whole [hc*n_embd, n_tok] tensor twice per mixer -- measured on Flash-Next
  GSQ-IQ3_XXS as 2x the F32->BF16 `convert_unary_cont_vec4` launches and +3.4 %
  prefill when restored (issue ggml-org#226 follow-up).

R175 amendment: the QSA combine launch passes the new `block_q8_1 * q8` argument
of `flash_attn_combine_results` (added by block 10's FA-combine Q8_1 publish) as
`nullptr` -- QSA's output is not fed to a quantized matmul, so it publishes
nothing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conversion merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. model Model specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants