SIGN IN SIGN UP

[rocm-libraries] ROCm/rocm-libraries#10653 (commit 23b36a4)

fix(ck): fix test_gemm_mx correctness failures on gfx1250
 (LDS read drain) (#10653)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

JIRA ID : AICK-1890

## Summary

`test_gemm_mx` fails the correctness check on gfx1250 (A0). Five tests
produce sparse wrong values, non-deterministically, at roughly a 50% hit
rate per run:

```
TestGemmMX_MK_NK/0.Large   f8  x f8  -> f16
TestGemmMX_MK_NK/1.Large   f8  x f8  -> bf16
TestGemmMX_MK_NK/2.Large   f4  x f4  -> f16
TestGemmMX_MK_NK/3.Large   f6  x f6  -> f16
TestGemmMX_MK_NK/4.Large   bf6 x bf6 -> bf16
```

The MX v3 pipeline double-buffers LDS. Each iteration reads one buffer
with `ds_load` while the hardware async copy
`global_load_async_to_lds_b128` fills the other. The barrier at the top
of `LoopFunc` is what keeps a wave from overwriting a buffer another
wave is still reading.

On gfx1250 that barrier is `block_sync_lds_async_load()`, which waits on
**ASYNCcnt**. LDS reads are tracked by **DScnt**, a different counter,
so the barrier does not wait for them. The compiler normally emits the
LDS wait itself, but in this hot loop it computes the weakest wait its
per-wave dependency analysis requires and sinks it *past* the barrier.
In the generated ISA a barrier retires with **28 `ds_load`s still
outstanding** (`s_wait_loadcnt_dscnt 0x11c`), immediately followed by an
async write into that same buffer.

Per-wave dependency analysis cannot see the cross-wave contract — that
the barrier exists so *other* waves may overwrite the buffer — so the
ordering has to be explicit in the source.

## The change

One line, in the existing gfx1250 arm of this one pipeline:

```cpp
#if defined(__gfx125__)
    llvm_amdgcn_s_wait_dscnt(0);
    block_sync_lds_async_load();
#else
```

A full drain the compiler cannot move past the barrier.

## Test plan

All runs on gfx1250 (ASIC rev 0x0).

- [x] `test_gemm_mx` full suite: **5 failing tests on every run → 0
failures, 3/3 runs**
- [x] Isolated instance, 20 repetitions per build, measured back to
back: **11/20 failures → 0/20**
- [x] `example_gemm_mx_fp8` (configured identically to the failing
instance): **10/10 incorrect → 0/10**
- [x] ISA verified: the added drain appears before the barrier at every
async site; `ds_load` count unchanged, so this is an ordering fix and
not a data-flow change
- [x] Non-gfx1250 paths untouched (change is inside `#if
defined(__gfx125__)`)

Reproducer, for anyone verifying:

```
./bin/example_gemm_mx_fp8 1 2 1 0 5120 5120 4096 4096 4096 5120 1 20 50
```

This fails on **every** run before the fix, which makes it a much better
regression gate than the test suite's ~50% hit rate.

## Performance

~1.6% throughput on the affected kernel (351.5 → 345.9 TFlops at
5120x5120x4096). The baseline is computing wrong answers, so this is the
cost of correctness rather than a regression against a working build.
A
Andriy Roshchenko committed
58072656a04e0b949a001eebf976d141427d3b36
Parent: 91bdde3
Committed by assistant-librarian[bot] <assistant-librarian[bot]@users.noreply.github.com> on 8/13/2026, 10:28:29 AM