Skip to content

QSMLA blocked by the #104/#257 TransB contract change: kernels fail to compile with legacy usage, and #257-adapted usage is rejected by SuperScalarModel gfrun (opposite TransB semantics) #122

Description

@CYR-Firework

Summary

The QSMLA operator in SuperNPUBench is blocked at two layers after #104 (the pto-spec #257 adaptation), with no kernel form able to both compile and run:

  1. Legacy usage (Shared B declared [kTk, kTd] + transpose_b()) → compile-time static_assert failures at template_asm.hpp:3898/3911 (effective-K mismatch / cooperative D shape mismatch).
  2. #257-adapted usage (QK path: no transpose_b; PV path: transpose_b) → compiles clean, but gfrun aborts at SuperScalarModel emulator/SoftCore.cpp:2245 (ADR-0100 cooperative TMATMUL check).

This is filed here (TileOP-API) per maintainers' tracking preference, but the remaining defect itself lives in SuperScalarModel — details below.

Reproduction (QSMLA, 4-PE HIF8)

Verified versions (2026-09-10):

Component Version
Linx-TileOP-API linx @ 748ac69 (includes #104 01d62c4, #105)
SuperScalarModel main @ db88b82 (ops-20260908 baseline, 2026-09-10 guard report)
llvm-project dev-llvm15_56 @ 10abd6e
SuperNPUBench ops-20260910 (2c107e9, QSMLA kernel still on legacy usage)

Cases: swa_small / csa_small / ori_sparse_small (test/solution/quant_sparse_flash_mla, IMPL=*_tadd_4pe, QSMLA_DTYPE=HIF8).

Layer 1: compile (expected, this is the migration)

QSMLA's K staging is tileKMatrix = SharedMatrixRight<kvdtype, kTk=32, kTd=64> — one KV token per row, D contiguous, i.e. the physical [N,K] form. Under the new contract that is TransB=0, so the legacy transpose_b() calls no longer compile (static_asserts above). Layer 1 is working as designed per #104; the QSMLA kernel adaptation is:

  • QK (Q @ K^T): remove transpose_b() — physical [32,64] declares [N,K].
  • PV (P @ V): add transpose_b() — the same physical [32,64] layout is [K,N] for the PV math (N contiguous).

Layer 2: gfrun rejects the adapted form — the actual defect (SuperScalarModel)

gfrun at db88b82 still consumes TransB with the pre-#255 math-transpose-flag semantics — the exact opposite of the post-#104 contract:

Physical Shared B layout Math B TileOP #104 expects gfrun db88b82 expects
[N,K] (K contiguous) [K,N] TransB=0 TransB=1
[K,N] (N contiguous) [K,N] TransB=1 TransB=0

Both consumption sites in emulator/SoftCore.cpp use the old reading:

  • validation (:2218): rightPhysicalRows = transB ? n : k — under #257 this must be transB ? k : n;
  • execution (:2346): LoadSharedMatrix(..., block->transB) — must be !block->transB (TransB=0 means the physical source is the transposed store, so the read must transpose).

Notably, TransA in the same function IS aligned with #257 (leftPhysicalRows = transA ? k : expectedLeftRows) — only TransB is inverted, which looks like a missed update when #255/#257 landed, not an intentional divergence.

This also explains why #103's verification did not catch it: the reported checks ("emits LB1=32(N), LB2=64(K) for B declared <32,64>; compiles 0 error") stop at the compile/emission level. A runtime cross-check (compile with #104, then run gfrun) would have exposed the mismatch immediately.

Verified fix (2-line flip in SuperScalarModel)

--- a/emulator/SoftCore.cpp
-    const size_t rightPhysicalRows = block->transB ? n : k;
-    const size_t rightPhysicalCols = block->transB ? k : n;
+    /* pto-spec #257: TransB describes the PHYSICAL stored RowMajor shape.
+     * TransB=0 stores [N, K] (rows=N); TransB=1 stores [K, N] (rows=K). */
+    const size_t rightPhysicalRows = block->transB ? k : n;
+    const size_t rightPhysicalCols = block->transB ? n : k;
 ...
-        std::vector<uint64_t> right = LoadSharedMatrix(rightSharedId, rightType,
-                                    k, n, requestRightSubview, block->transB);
+        std::vector<uint64_t> right = LoadSharedMatrix(rightSharedId, rightType,
+                                    k, n, requestRightSubview, !block->transB);

And the QSMLA kernel adaptation (SuperNPUBench, for reference):

--- a/.../quant_sparse_flash_mla.hpp
-                        TMATMUL(tScoreCube, tQShared, tKShared,
-                                fixp::keep_acc().transpose_b());   // QK, x4 sites
+                        TMATMUL(tScoreCube, tQShared, tKShared,
+                                fixp::keep_acc());
 ...
-                    TMATMUL(tPVCube, tPShared, tVShared,
-                            fixp::keep_acc());                     // PV
+                    TMATMUL(tPVCube, tPShared, tVShared,
+                            fixp::keep_acc().transpose_b());

Verification

With both patches applied, all three QSMLA cases pass gfrun at 100% with results bitwise identical to the pre-#104 baseline:

Case Result max_abs
swa_small 32768/32768 (100%) 0.004920
csa_small 32768/32768 (100%) 0.004677
ori_sparse_small 32768/32768 (100%) 0.009071

Bitwise-identical max_abs across the semantic change confirms the flip direction is correct (a wrong direction would transpose B the wrong way and fail broadly). Note gfsim's TimingSim does not consume transB numerically, but its embedded functional verification hits the same assert, so gfsim must be rebuilt with the fix.

Ask

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions