From 86d874d472864e721562f6c0f88324552dd5555d Mon Sep 17 00:00:00 2001 From: bri-prism <288398250+bri-prism@users.noreply.github.com> Date: Mon, 5 Oct 2026 12:13:47 -0700 Subject: [PATCH] cuda: keep the GDN state gather when its ids memory is reused The gather fusion skips the GET_ROWS and reads ids later in the GDN kernel, but ggml-alloc can give the ids memory to a node that runs in between. Keep the GET_ROWS when a node up to the GDN output overlaps ids, or when the GDN op runs on a concurrent stream. --- ggml/src/ggml-cuda/ggml-cuda.cu | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ggml/src/ggml-cuda/ggml-cuda.cu b/ggml/src/ggml-cuda/ggml-cuda.cu index 41b3be6317d8..22a368827f0c 100644 --- a/ggml/src/ggml-cuda/ggml-cuda.cu +++ b/ggml/src/ggml-cuda/ggml-cuda.cu @@ -2959,6 +2959,22 @@ static bool ggml_cuda_try_gdn_gather_skip(ggml_backend_cuda_context & ctx, const if (gr->ne[0] != D || v->ne[3] != 1 || ggml_nelements(cur) != D) { return false; } + // ggml-alloc sees the GET_ROWS as the last reader of ids, so a later node can reuse ids memory before the GDN kernel reads it + const char * ids_beg = (const char *) ids->data; + const char * ids_end = ids_beg + ggml_nbytes(ids); + for (int k = node_idx + 1; k <= j; ++k) { + const ggml_tensor * t = cgraph->nodes[k]; + const char * b = (const char *) t->data; + if (b != nullptr && b < ids_end && ids_beg < b + ggml_nbytes(t)) { + return false; + } + } + // on a concurrent stream, other nodes can run at the same time as the GDN op + for (const auto & [fork_node, event] : ctx.stream_context().concurrent_events) { + if (event.stream_mapping.find(n) != event.stream_mapping.end()) { + return false; + } + } ggml_cuda_gated_delta_net_gather gather; gather.base = (const float *) cache->data; gather.ids = (const int32_t *) ids->data;