Skip to content

feat(BACKEND-ROCM): kKdaGatedDeltaRule ROCm kernel — the per-K-channel-decay recurrence - #3120

Merged
localai-org-maint-bot merged 5 commits into
mainfrom
row/BACKEND-ROCM-KDA
Sep 10, 2026
Merged

feat(BACKEND-ROCM): kKdaGatedDeltaRule ROCm kernel — the per-K-channel-decay recurrence#3120
localai-org-maint-bot merged 5 commits into
mainfrom
row/BACKEND-ROCM-KDA

Conversation

@localai-org-maint-bot

@localai-org-maint-bot localai-org-maint-bot commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Ports kKdaGatedDeltaRule to AMD ROCm/HIP. This is the second of four
ops required for GLM-5.3-Flash on ROCm (issue #2942).

The kernel is a hand-translation of the CUDA KdaScanKernel
(cuda_gdn.cu:3139-3235) to HIP, readable side by side against the
template rocm_gdn_scan.hip (GdnScanK). Three differences from GDN:

  1. Shared memory is 3*dk not 2*dk (extra d_sh buffer for
    per-K-channel decay).
  2. Per-K-channel decay vector instead of scalar: indexes
    g[(t*hv_n+hv)*dk+i] instead of g[t*hv_n+hv].
  3. State math uses the vector decay.

State dtype is float only (no f16/bf16 state dispatch unlike GDN). The
launcher passes nullptr for state_idx.

Staged slice

The op lands unreached by the model's forward. glm5_next_kda.cpp:322
refuses any non-CPU queue, so the only call site (:404) cannot run on
ROCm. Lifting that refusal is W9c-2's job, which depends on W9b
(keep-quant residency). The spec lists this wiring under ## Owed.
Issue #2942 stays open — this lands op 2 of 4.

Gate status

  • CPU focused test: PASS — test_backend_cross_device KDA case, 39/39
    assertions green. The test reaches the op through the production ABI
    (vt::KdaGatedDeltaRule -> GetOp registry), not hand-construction.
  • Commit style: PASS (check-commit-style.py).
  • Commit trailers: PASS (check-commit-trailers.py --filled).
  • Pre-push checkers: PASS (prompt-contract, now-current, readme-structure).
  • ROCm device gate: PENDING — no hipcc toolchain on this host. The
    .hip TU is not compiled and the GPU kernel has not run. The CPU-only
    test compares CPU-vs-CPU (trivially exact); the meaningful
    ROCm-vs-CPU-oracle verification is owed.

Files

  • src/vt/rocm/rocm_kda_scan.hip (NEW, 155 lines) — KDA scan kernel,
    launcher, entry point
  • src/vt/rocm/rocm_ops.hip (+10 lines) — RegisterOp for
    kKdaGatedDeltaRule on kROCM
  • CMakeLists.txt (+2 lines) — added rocm_kda_scan.hip to both HIP
    source lists
  • tests/vt/test_backend_cross_device.cpp (+94 lines) — cross-device
    test case mirroring the GDN test
  • .agents/specs/rocm-kda-gated-delta-rule.md (NEW) — spec

Fresh review

A fresh reviewer (separate agent) reviewed the implementation statically
and performed mutation analysis. Verdict: NEEDS_REPAIR -> repaired (one
wrong CPU oracle citation cpu_ops.cpp:4046 -> :2241). The kernel,
registration, CMake, test, and commit trailers were confirmed correct.
All five mutations (decay indexing, shared memory, state math, deleted
registration, deleted test call) would be caught by the test or build on
a ROCm build.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:regolo-glm5.2 [maki]

…hannel-decay recurrence

The second of #2942's four unregistered ROCm ops. The CUDA donor
(cuda_gdn.cu:3139 KdaScanKernel) is byte-for-byte the GDN scan kernel
except the state decay is per-K-channel: GDN uses one scalar
expf(g[t*hv_n+hv]); KDA stages a dk-vector expf(g[(t*hv_n+hv)*dk+i])
in shared memory. The ROCm GDN kernel (rocm_gdn_scan.hip, 181 lines)
is a clean hand-translation of the CUDA GDN kernel; the KDA port is
the same hand-translation, one step further.

The op lands unreached: glm5_next_kda.cpp:322 refuses any non-CPU
queue, so the model's only call site (:404) cannot run on ROCm.
Lifting that refusal is W9c-2's job, and it depends on W9b
(keep-quant residency). This is a staged slice: the commit body and
PR body name what is unreached, the owning row, and the tracking issue.

Issue: #2942, which STAYS OPEN. It tracks four unregistered ops; this
lands the second. No closing keyword appears in this body, deliberately.
Row: BACKEND-ROCM. Spec: .agents/specs/rocm-kda-gated-delta-rule.md.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:regolo-glm5.2 [maki]
…l-decay recurrence

Hand-translates the CUDA KdaScanKernel (cuda_gdn.cu:3139) into HIP as
src/vt/rocm/rocm_kda_scan.hip, mirroring the existing ROCm GDN kernel
(rocm_gdn_scan.hip). The KDA scan is byte-for-byte GdnScanK except the
state decay is per-K-channel: GDN uses one scalar expf(g[t*hv_n+hv]);
KDA stages a dk-vector expf(g[(t*hv_n+hv)*dk+i]) in shared memory and
applies s_row[ki] *= d_sh[ki]. Three differences from GdnScanK: shared
memory is 3*dk (adds a per-K decay vector), decay is per-channel not
scalar, and state math indexes d_sh[ki] instead of a scalar. State is
float only (no f16/bf16 state dispatch, unlike GDN); the launcher passes
nullptr for state_idx.

Registers the op in rocm_ops.hip and adds the .hip TU to both
VLLM_CPP_HIP source lists in CMakeLists.txt. The cross-device test case
in test_backend_cross_device.cpp checks NMSE on output and state vs the
CPU oracle, OpRegistered unconditionally on a ROCm build, and that
GetReferenceTierHits does not increase.

This is a staged slice: the op is unreached by the model's forward on
its default configuration. glm5_next_kda.cpp:322 refuses any non-CPU
queue, so the only call site (:404) cannot run on ROCm. Lifting that
refusal is W9c-2's job (spec glm5-next-flash.md), depending on W9b
(keep-quant residency). The cross-device test exercises the kernel
directly through vt::KdaGatedDeltaRule, the production entry point for
the op.

CPU-only build and test pass (39 cases, 44 assertions, 0 failures). The
ROCm device gate is PENDING: no HIP toolchain or AMD device in this
session. The .hip TU is PENDING compilation for the same reason.

Issue: #2942, which STAYS OPEN. It tracks four unregistered ops; this
lands the second. No closing keyword appears in this body, deliberately.
Row: BACKEND-ROCM. Spec: .agents/specs/rocm-kda-gated-delta-rule.md.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus [maki]
The spec's ## Now said "implementation pending." The implementation
landed in 8d0186d, so that line is stale. This commit updates ## Now
to reflect the committed state: CPU-only build and test pass, the ROCm
.hip TU and the gfx1151 test case are pending a HIP toolchain and AMD
device.

Issue: #2942. Row: BACKEND-ROCM. Spec: .agents/specs/rocm-kda-gated-delta-rule.md.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus [maki]
…nd spec

The KDA kernel header and spec cited the CPU oracle at cpu_ops.cpp:4046,
but KdaGatedDeltaRuleKernel is at :2241 (recurrence math in KdaHeadTokenStep
:2208). Line 4046 is QkvSplitKernel. Found by fresh review.


FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:regolo-glm5.2 [maki]
@mudler
mudler force-pushed the row/BACKEND-ROCM-KDA branch 2 times, most recently from 8b1e7ff to c86332c Compare September 10, 2026 14:48
KDA dispatches Tin/Tout in {float, __hip_bfloat16} only and TState is
always float, so the __half overloads carried over from the GDN template
are dead code.  With -Werror they trip -Wunused-function on gfx1151.
Drop them and keep the __hip_bfloat16 overloads that the bf16 dispatch
paths need.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:regolo-glm5.2 [maki]
@mudler
mudler force-pushed the row/BACKEND-ROCM-KDA branch from ae8242c to 70cd2bc Compare September 10, 2026 15:08
@localai-org-maint-bot
localai-org-maint-bot merged commit 0c6dc8d into main Sep 10, 2026
25 of 29 checks passed
@mudler
mudler deleted the row/BACKEND-ROCM-KDA branch September 10, 2026 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants