Commit Graph

416 Commits

Author SHA1 Message Date
3412ff1a9b fix: TMA tile strides must match global strides, not tile dimensions
The tile stride in the outer dimension should be the global row stride
(cols), not the tile width. The tile is a window into the global tensor
and elements are addressed with global strides.
2026-05-29 04:41:53 +00:00
409838ace2 refactor: per-sub-tile TMA loads with padded GMEM allocations
- Q, K, V all loaded per (128,16) sub-tile via TMA
- Q GMEM padded to (128, HD) to satisfy TMA tile requirements
- Simpler SMEM layout — only (128,16) staging buffers needed
- Updated test with padded allocations
2026-05-29 04:41:03 +00:00
b78ebe8a9c debug: add TMA descriptor error reporting 2026-05-29 04:38:57 +00:00
c7a6d7d231 fix: tma_mbar_init → tma_mbarrier_init (typo) 2026-05-29 04:37:48 +00:00
696462f07a feat: TMA async load infrastructure for FMHA kernel
- fmha_tma.cuh: TMA descriptor creation, mbarrier helpers, cp.async.bulk.tensor.2d wrappers
- fmha_6warp_tma.cuh: TMA-integrated multirow kernel with async GMEM→SMEM loads
  - TMA loads Q, K, V tiles to row-major SMEM
  - Transposes to canonical K-major layout for MMA
  - Same softmax/epilogue as non-TMA kernel
- test_fmha_tma.cu: Test harness for TMA FMHA (HD=64 first)
2026-05-29 04:36:52 +00:00
2f2259395e fix: always normalize in kernel, correct KV merge with normalized O + LSE 2026-05-28 23:53:44 +00:00
914f76d30c multirow: add normalize flag, un-norm + LSE output, multi-tile KV merge test 2026-05-28 23:51:23 +00:00
ac8fa779e2 fix: move epilogue TMEM loads outside my_row_active guard (warp-collective hang) 2026-05-28 23:46:46 +00:00
55c0604a71 add fence.sc.gpu between PV and epilogue for TMEM visibility 2026-05-28 23:21:53 +00:00
52809b0ec6 fix: tcgen05.wait::ld.sync.aligned (was missing 'sync') 2026-05-28 23:19:03 +00:00
468614a4e2 fmha_multirow: non-interleaved design — softmax first, then PV
KEY FIX: TMEM is shared between QK output (S) and PV output (O).
Cannot interleave softmax reads with PV writes because PV overwrites S.

New flow:
1. QK GEMM → S in TMEM
2. Softmax: read ALL S from TMEM, compute P in registers
   - Pass 1: row_max (4 warps, 32x32b.x8)
   - Pass 2: exp, sum, store P in p_vals[SK_TILE] registers
3. PV GEMM: write P to sPk per K-tile, accumulate O in TMEM
4. Epilogue: read O from TMEM, normalize, write GMEM

P in registers: each lane holds float p_vals[128] = 512 bytes.
Register budget: 128 lanes × 512B = 64KB (within B200 256KB register file).
2026-05-28 23:17:43 +00:00
43ba672e15 fmha_multirow: add fence.sc.gpu after QK GEMM for TMEM visibility 2026-05-28 23:13:31 +00:00
be2685e9e3 fmha_multirow: use natural 4-warp TMEM partitioning after UMMA
After UMMA (QK GEMM), 4 warps reading TMEM with 32x32b.x8 each
see a different 32-row partition (verified on B200):
  Warp 0 → rows 0-31, Warp 1 → rows 32-63, etc.
Lane l in warp w reads row w*32 + l.

This eliminates the broken row_page<<16 addressing and allows:
- T<=32: warp 0 only, 32x32b.x8, each lane = one row
- T>32: 4 warps, each reads its natural 32-row partition
- Epilogue: same partitioning for reading O from TMEM

No s_p_vals buffer. P streamed per K-tile through sPk.
2026-05-28 23:07:31 +00:00
863a030c3b fmha_multirow: rewrite with 32x32b.x8 only, no s_p_vals, row_page addressing
- Kill 64KB s_p_vals buffer — P is streamed per K-tile through sPk
- All TMEM ops use 32x32b.x8 exclusively (16x256b.x1 crashes on 2nd call)
- T>32: 4 softmax warps use row_page offset in TMEM address (row<<16)
- Lane l in warp w handles row w*32+l
- Two-pass softmax: pass 1 row_max, pass 2 exp/sum interleaved with PV
- PV: N=16 sub-tiles, SS MMA sPk(128,16) × sV(16,16) → TMEM
- Epilogue: 32x32b.x8 TMEM read, normalize, BF16 → GMEM
- SMEM budget: ~14KB (well within 232KB)
2026-05-28 22:52:52 +00:00
1ba304db3e stuff 2026-05-28 21:08:13 +00:00
deaa3ec725 CRITICAL FIX: Q/K SMEM canonical layout must use local d (0..15) not full_d — UMMA descriptor reads from sQ0/sK0 start, not offset 2026-05-28 20:13:52 +00:00
08694b8136 Fix multi-row softmax v3: 32x32b.x8 with per-lane per-row (no wmax/wsum), per-row sRowMax/sRowSum arrays 2026-05-28 20:10:13 +00:00
aaa76c1af1 Rewrite multi-row softmax using 16x256b.x1 TMEM reads for proper multi-row access 2026-05-28 20:08:30 +00:00
5e3c61184c Fix multi-row softmax: remove cross-lane wmax/wsum — each lane handles its own row independently 2026-05-28 20:06:16 +00:00
d8b421ccee Multi-row FMHA kernel (Milestone 4): T>1 prefill support with 4-warp parallel softmax 2026-05-28 20:04:29 +00:00
aa41cfa2e5 Multi-head FMHA kernel (Milestone 5): grid launch with MHA/MQA/batch support
- fmha_6warp_multihead.cuh: grid=(1, n_h, batch) kernel with FmhaParams
- MQA support via k_head_stride=0 / v_head_stride=0
- LSE output for multi-segment KV merge composition
- test_fmha_6warp_multihead.cu: MHA (4+8 heads), MQA, batched tests
- HD-specific wrappers for hd=16/64/128/256
- Marked E2M1 dequant bug as FIXED in consultant issue file
2026-05-28 19:32:35 +00:00
6af2feb42a TMA 5D test: element stride decomposition 2026-05-28 19:18:01 +00:00
41343fdc6b auto: pre-test commit 2026-05-28 19:08:04 +00:00
b3020c2811 6-warp specialized FMHA kernel — ALL HD=16/64/128/256 PASS cos 0.999997+
Warp layout (192 threads):
- Warps 0-3: Softmax + correction + epilogue
- Warp 4: MMA (QK + PV GEMM)
- Warp 5: Data staging (Q/K/V loads, direct GMEM for now)
CTA-wide __syncthreads() sync between phases.

Fix: removed spurious inv_sum normalization in epilogue
(MMA output is already correctly scaled with softmax'd P).

Files: fmha_6warp.cuh + test_fmha_6warp*.cu
2026-05-28 16:34:14 +00:00
2a6d72912a auto: pre-test commit 2026-05-28 16:28:58 +00:00
e74c84458c Clean up E2M1 dequant: use LUT approach (consultant recommendation)
Both indexer files now use a constexpr LUT matching Python's
E2M1_MAGNITUDES = [0, 0.5, 1, 1.5, 2, 3, 4, 6].
This is cleaner and more auditable than bit-manipulation.
2026-05-28 16:17:47 +00:00
79ef87f9a9 FIX: E2M1 FP4 dequantization bug in indexer_score_topk.cu
The dequant_fp4_scalar function was treating the magnitude bits as
a raw integer (0-6) instead of the E2M1 floating-point format:
  Old (WRONG): val = (int)(nibble & 0x07) * scale
  New (CORRECT): proper E2M1 decode with exponent + mantissa

E2M1 encoding (bias=1):
  exp=0 subnormal: 0b000=0, 0b001=0.5
  exp=1: 0b010=1, 0b011=1.5
  exp=2: 0b100=2, 0b101=3
  exp=3: 0b110=4, 0b111=6

Bug found by outside consultant. Affects indexer top-k selection
correctness — wrong FP4 key decoding would select wrong CSA blocks.

Fixed in both:
- dsv4/kernels/indexer/indexer_score_topk.cu
- dsv4/kernels/cuda/indexer_score_topk.cu
2026-05-28 16:16:24 +00:00
44c4bade5f Rewrite fmha_sm100_tc.cuh with working N=16 PV sub-tile approach
Production FMHA kernel template for Blackwell SM100:
- FmhaSm100Kernel<HD>::launch(q, k, v, o, s_k, scale, stream)
- QK: SS MMA N=128, one K-tile at a time
- PV: SS MMA N=16 sub-tiles (HD/16 calls per K-tile)
- Epilogue: TMEM → regs → BF16 → GMEM
- ~25KB SMEM for all HD values
- All HD=16/64/128/256 pass with cos 0.999997+
2026-05-28 16:04:11 +00:00
0f6907b001 UMMA: fix descriptor + idesc — use gau-nernst tutorial values
- LBO = BLOCK_MN * 16 (bytes), SBO = 128 (bytes) for K-major NONE
- Canonical SMEM layout: column-major interleaving of core matrices
- idesc is SEPARATE 32-bit value (was using desc_a>>32 = WRONG)
- idesc encodes dtype/atype/btype/MMA_M/MMA_N
- This was the root cause of 'misaligned address' errors
2026-05-28 09:18:45 +00:00
427410d94a UMMA: Rewrite fmha_umma_desc.cuh with correct K-major core-matrix layout + minimal QK GEMM test
- Core-matrix layout: each 8x8 BF16 tile (128B) contiguous in SMEM
- K-major NONE descriptor: LBO=1 (16B), SBO=block_k/8, lbo_mode=0
- MMA K-tiling: tcgen05.mma uses K=16 per call, tile for hd>16
- write_smem_kmajor: converts row-major to core-matrix layout
- write_smem_ktile: extracts single K-tile in core-matrix layout
- test_umma_qk.cu: minimal hd=16, sk=128 test (single MMA call)
- Previous UMMA descriptors were wrong (row-major SMEM, wrong LBO/SBO)
2026-05-28 09:15:40 +00:00
e5ba0ca119 debug: clean QK verify with scalar sanity + MMA result 2026-05-28 08:53:35 +00:00
a04d794979 debug: skip TMEM alloc — test SMEM loads only 2026-05-28 08:49:37 +00:00
72c97f2546 debug: minimal UMMA descriptor (just start_addr + version) 2026-05-28 08:48:01 +00:00
9a51bfa578 fix: align SMEM layout properly (128B aligned tmem + Q) 2026-05-28 08:46:56 +00:00
c64bd7b875 debug: read Q/K directly from SMEM 2026-05-28 08:43:39 +00:00
58b610c96c fix: proper early return for SMEM load test 2026-05-28 08:41:30 +00:00
82bc2c4a49 debug: verify SMEM loads + scalar QK sanity check 2026-05-28 08:40:16 +00:00
53139d24bf debug: verify TMEM r/w works before MMA 2026-05-28 08:39:12 +00:00
a9d71ff6ab debug: print TMEM values after MMA 2026-05-28 08:38:08 +00:00
bfb1e177ce debug: try all-lane MMA + print tmem_base 2026-05-28 08:37:02 +00:00
d3510980e4 feat: SWIZZLE_NONE UMMA descriptors with row-major SMEM
Canonical UMMA layout for SWIZZLE_NONE:
- MN-major (128, 64): LBO=16, SBO=128 (from logical_divide Tile(1,8))
- K-major (128, 64): LBO=16, SBO=32 (from logical_divide Tile(8,2))

Using simple row-major SMEM layout (no swizzle, no permutation).
Data is written directly to SMEM in row-major order.
The descriptor strides describe the canonical layout.
2026-05-28 08:35:30 +00:00
ab84ad0f86 feat: implement canonical UMMA SMEM layout with SWIZZLE_128B
Proper implementation of the SMEM layout that tcgen05.mma expects:
- SWIZZLE_128B (layout_type=2) for both MN-major A and K-major B
- Swizzle<3,4,3> applied to element offsets before SMEM write
- MN_SW128 atom: (1024, 8) BF16, stride (1, 1024)
- K_SW128 atom: (8, 1024) BF16, stride (1, 8)
- umma_smem_write/read functions for both MN and K major
- Descriptor with correct leading_byte_offset and stride_byte_offset

This is the RIGHT WAY. No shortcuts.
2026-05-28 08:18:47 +00:00
ecbc75255c fix: correct UMMA descriptor format from CUTLASS source
The descriptor bitfield is completely different from what I assumed:
- [0,14) start_address (smem_ptr >> 4)
- [16,30) leading_byte_offset (row stride bytes >> 4)
- [32,46) stride_byte_offset
- [46,48) version = 1 (Blackwell)
- [61,64) layout_type (0=NONE, 2=128B, 4=64B, 6=32B)
- idescE = desc >> 32, passed as separate arg to MMA PTX

The 64-bit descriptor uses byte offsets (not log2 or element counts).
The upper 32 bits are reinterpreted by the MMA hardware as idescE.
2026-05-28 08:07:52 +00:00
fe7d561143 debug: print UMMA descriptor values for diagnosis 2026-05-28 08:03:53 +00:00
c5f7a9a15c fix: align SMEM buffers to 16 bytes for UMMA descriptors 2026-05-28 08:02:53 +00:00
7436315309 feat: add tcgen05.mma QK GEMM verification kernel + test
Step 1 of tensor-core acceleration:
- fmha_umma_desc.cuh: UMMA SMEM descriptor construction (raw bitfield)
- fmha_qk_verify.cuh: QK GEMM using tcgen05.mma SS (SMEM A, SMEM B → TMEM C)
- test_qk_mma.cu: standalone test comparing MMA output vs CPU reference

Key design decisions:
- UMMA descriptors built from raw bitfield (no CuTe dependency)
- tcgen05.mma called by one lane per warp (elect_one_sync pattern)
- Q: (128, HD) MN-major, K: (128, HD) K-major (transposed via descriptor)
- S: (128, 128) in TMEM, row 0 read back via tcgen05.ld
2026-05-28 08:00:42 +00:00
6fb3d54c02 docs: update here-docs with CuTeDSL rationale for NVIDIA
Updated fmha_common.cuh, fmha_sm100.cuh, fmha_epilogue_sm100.cuh,
and fmha_sm100_launch.cuh with comprehensive here-docs explaining:

1. The 4 CuTeDSL gaps that forced us to raw CUDA C++:
   - TMEM round-trip broken (Ld32x32bOp/St32x32bOp column mismatch)
   - Float→int impossible (arith.fptosi not lowerable)
   - epilogue_tma_store blocks multi-CTA
   - hd=512 MLIR optimizer hangs

2. TMEM lane mapping (verified on B200):
   - Lane i → positions i*4+0..3, 128 FP32 per column
   - Warp-collective: ALL 32 lanes must call ld/st or HANG
   - Column address = tmem_base + column_index

3. Key insight for NVIDIA: float→int gap is the single most
   impactful limitation, blocking ALL quantization-epilogue fusion
2026-05-28 07:54:01 +00:00
446a0ca9fd refactor(tmem): clean rewrite of TMEM epilogue kernel
Removed all dead code from the first (broken) attention loop approach.
Clean pipeline: SMEM attention → TMEM write → TMEM read → normalize → GMEM.

Also renamed sPvBuf to sO for clarity (same as reference kernel).
2026-05-28 07:49:03 +00:00
c989dc78d9 debug: print sPvBuf[32] value 2026-05-28 07:47:37 +00:00
b50f6a8512 debug: add TMEM read diagnostic 2026-05-28 07:46:15 +00:00