(
x_ptr,
y_ptr,
out_ptr,
M: tl.constexpr, # noqa: N803
B: tl.constexpr, # noqa: N803
BLOCK_SIZE_B: tl.constexpr, # noqa: N803
x_tile_side: tl.constexpr,
k_tile_side: tl.constexpr,
)
| 44 | ) |
| 45 | @triton.jit |
| 46 | def tl_gemv_kernel( |
| 47 | x_ptr, |
| 48 | y_ptr, |
| 49 | out_ptr, |
| 50 | M: tl.constexpr, # noqa: N803 |
| 51 | B: tl.constexpr, # noqa: N803 |
| 52 | BLOCK_SIZE_B: tl.constexpr, # noqa: N803 |
| 53 | x_tile_side: tl.constexpr, |
| 54 | k_tile_side: tl.constexpr, |
| 55 | ): |
| 56 | pid = tl.program_id(axis=0) |
| 57 | x_base_offs = tl.arange(0, x_tile_side * k_tile_side).reshape(x_tile_side, k_tile_side) |
| 58 | y_base_offs = ( |
| 59 | tl.arange(0, BLOCK_SIZE_B)[None, :] + B * tl.arange(0, x_tile_side * k_tile_side)[:, None] |
| 60 | ) |
| 61 | mult = tl.zeros((x_tile_side, x_tile_side * BLOCK_SIZE_B), dtype=tl.float32) |
| 62 | for tile_offs in range(0, M, x_tile_side * k_tile_side): |
| 63 | x_offs = x_base_offs + tile_offs |
| 64 | x_tile = tl.load(x_ptr + x_offs, mask=x_offs < M, other=0.0) |
| 65 | |
| 66 | y_offs = y_base_offs + tile_offs * B + pid * BLOCK_SIZE_B |
| 67 | row_ok = y_offs < B * M |
| 68 | col_ok = (pid * BLOCK_SIZE_B + tl.arange(0, BLOCK_SIZE_B))[None, :] < B |
| 69 | y_tile = tl.load(y_ptr + y_offs, mask=row_ok & col_ok, other=0.0) |
| 70 | y_tile = y_tile.T.reshape(BLOCK_SIZE_B * x_tile_side, k_tile_side).T |
| 71 | |
| 72 | mult = tl.dot(x_tile, y_tile, acc=mult) # (M, B*M) |
| 73 | indices = ( |
| 74 | tl.arange(0, x_tile_side)[:, None] + x_tile_side * tl.arange(0, BLOCK_SIZE_B)[None, :] |
| 75 | ) # (M, B) |
| 76 | diagonals = mult.gather(axis=1, index=indices) # (M, B) |
| 77 | dot_product = diagonals.sum(0) # (B) |
| 78 | tl.store( |
| 79 | out_ptr + pid * BLOCK_SIZE_B + tl.arange(0, BLOCK_SIZE_B), |
| 80 | dot_product, |
| 81 | mask=pid * BLOCK_SIZE_B + tl.arange(0, BLOCK_SIZE_B) < B, |
| 82 | ) |
nothing calls this directly
no outgoing calls
no test coverage detected