Kernel for computing the matmul C = A x B.T. A has shape (M, K), B is pre-transposed to (K, N), and C has shape (M, N). Uses device-side tensor descriptors (TMA) for efficient memory access. NOTE: tl.dot(a, b.T) does NOT work correctly with TMA-loaded blocks — .T only swaps the logi
(
# Pointers to matrices
a_ptr, # [M, K]
b_ptr, # [K, N] (pre-transposed by wrapper)
c_ptr,
# Matrix dimensions
M, # noqa: N803
N, # noqa: N803
K, # noqa: N803
# Meta-parameters
BLOCK_SIZE_M: tl.constexpr, # noqa: N803
BLOCK_SIZE_N: tl.constexpr, # noqa: N803
BLOCK_SIZE_K: tl.constexpr, # noqa: N803
GROUP_SIZE_M: tl.constexpr, # noqa: N803
ACTIVATION: tl.constexpr, # noqa: N803
)
| 33 | ) |
| 34 | @triton.jit |
| 35 | def matmul_kernel( |
| 36 | # Pointers to matrices |
| 37 | a_ptr, # [M, K] |
| 38 | b_ptr, # [K, N] (pre-transposed by wrapper) |
| 39 | c_ptr, |
| 40 | # Matrix dimensions |
| 41 | M, # noqa: N803 |
| 42 | N, # noqa: N803 |
| 43 | K, # noqa: N803 |
| 44 | # Meta-parameters |
| 45 | BLOCK_SIZE_M: tl.constexpr, # noqa: N803 |
| 46 | BLOCK_SIZE_N: tl.constexpr, # noqa: N803 |
| 47 | BLOCK_SIZE_K: tl.constexpr, # noqa: N803 |
| 48 | GROUP_SIZE_M: tl.constexpr, # noqa: N803 |
| 49 | ACTIVATION: tl.constexpr, # noqa: N803 |
| 50 | ): |
| 51 | """Kernel for computing the matmul C = A x B.T. |
| 52 | A has shape (M, K), B is pre-transposed to (K, N), and C has shape (M, N). |
| 53 | Uses device-side tensor descriptors (TMA) for efficient memory access. |
| 54 | |
| 55 | NOTE: tl.dot(a, b.T) does NOT work correctly with TMA-loaded blocks — |
| 56 | .T only swaps the logical view without rearranging shared memory, but |
| 57 | tensor core MMA instructions depend on physical layout. And TMA enforces |
| 58 | strides[-1] == 1 so we can't describe the transpose via strides either. |
| 59 | The wrapper pre-transposes B to [K, N] contiguous. |
| 60 | """ |
| 61 | # ----------------------------------------------------------- |
| 62 | # Create device-side tensor descriptors for TMA |
| 63 | # A: [M, K] row-major contiguous |
| 64 | # B: [K, N] row-major contiguous (pre-transposed by wrapper) |
| 65 | # C: [M, N] row-major contiguous |
| 66 | a_desc = tl.make_tensor_descriptor( |
| 67 | a_ptr, |
| 68 | shape=[M, K], |
| 69 | strides=[K, 1], |
| 70 | block_shape=[BLOCK_SIZE_M, BLOCK_SIZE_K], |
| 71 | ) |
| 72 | b_desc = tl.make_tensor_descriptor( |
| 73 | b_ptr, |
| 74 | shape=[K, N], |
| 75 | strides=[N, 1], |
| 76 | block_shape=[BLOCK_SIZE_K, BLOCK_SIZE_N], |
| 77 | ) |
| 78 | c_desc = tl.make_tensor_descriptor( |
| 79 | c_ptr, |
| 80 | shape=[M, N], |
| 81 | strides=[N, 1], |
| 82 | block_shape=[BLOCK_SIZE_M, BLOCK_SIZE_N], |
| 83 | ) |
| 84 | |
| 85 | # ----------------------------------------------------------- |
| 86 | # Map program ids `pid` to the block of C it should compute. |
| 87 | # Process N dimension first, then M (matching fused kernel pattern). |
| 88 | # This enables processing many N blocks for the same M block, allowing |
| 89 | # A matrix (small M dimension) to be reused from L2 cache. |
| 90 | pid_n = tl.program_id(axis=0) # N dimension first (like vocab in fused kernel) |
| 91 | pid_m = tl.program_id(axis=1) # M dimension second (like hidden_states in fused kernel) |
| 92 |
nothing calls this directly
no test coverage detected