Fused kernel: computes activation(X @ W_gate^T) * (X @ W_up^T). W_gate and W_up are [intermediate_size, hidden_size] (transposed access). X is [M, K], output is [M, N] where N = intermediate_size, K = hidden_size.
(
X_ptr,
W_gate_ptr,
W_up_ptr,
Out_ptr,
M, N, K,
stride_xm, stride_xk,
stride_wgk, stride_wgn,
stride_wuk, stride_wun,
stride_om, stride_on,
USE_SILU: tl.constexpr,
BLOCK_SIZE_M: tl.constexpr,
BLOCK_SIZE_N: tl.constexpr,
BLOCK_SIZE_K: tl.constexpr,
)
| 24 | |
| 25 | @triton.jit |
| 26 | def fused_gate_up_kernel( |
| 27 | X_ptr, |
| 28 | W_gate_ptr, |
| 29 | W_up_ptr, |
| 30 | Out_ptr, |
| 31 | M, N, K, |
| 32 | stride_xm, stride_xk, |
| 33 | stride_wgk, stride_wgn, |
| 34 | stride_wuk, stride_wun, |
| 35 | stride_om, stride_on, |
| 36 | USE_SILU: tl.constexpr, |
| 37 | BLOCK_SIZE_M: tl.constexpr, |
| 38 | BLOCK_SIZE_N: tl.constexpr, |
| 39 | BLOCK_SIZE_K: tl.constexpr, |
| 40 | ): |
| 41 | """ |
| 42 | Fused kernel: computes activation(X @ W_gate^T) * (X @ W_up^T). |
| 43 | W_gate and W_up are [intermediate_size, hidden_size] (transposed access). |
| 44 | X is [M, K], output is [M, N] where N = intermediate_size, K = hidden_size. |
| 45 | """ |
| 46 | pid_m = tl.program_id(0) |
| 47 | pid_n = tl.program_id(1) |
| 48 | |
| 49 | offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M) |
| 50 | offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N) |
| 51 | offs_k = tl.arange(0, BLOCK_SIZE_K) |
| 52 | |
| 53 | # Pointers for X |
| 54 | x_ptrs = X_ptr + offs_m[:, None] * stride_xm + offs_k[None, :] * stride_xk |
| 55 | |
| 56 | # Pointers for W_gate (shape [K, N] after transpose -- stored as [N, K]) |
| 57 | wg_ptrs = W_gate_ptr + offs_k[:, None] * stride_wgk + offs_n[None, :] * stride_wgn |
| 58 | # Pointers for W_up |
| 59 | wu_ptrs = W_up_ptr + offs_k[:, None] * stride_wuk + offs_n[None, :] * stride_wun |
| 60 | |
| 61 | # Accumulators |
| 62 | acc_gate = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32) |
| 63 | acc_up = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32) |
| 64 | |
| 65 | for k_start in range(0, K, BLOCK_SIZE_K): |
| 66 | k_offs = k_start + offs_k |
| 67 | # Load X tile |
| 68 | x_mask = (offs_m[:, None] < M) & (k_offs[None, :] < K) |
| 69 | x = tl.load(x_ptrs, mask=x_mask, other=0.0) |
| 70 | |
| 71 | # Load W_gate tile |
| 72 | wg_mask = (k_offs[:, None] < K) & (offs_n[None, :] < N) |
| 73 | wg = tl.load(wg_ptrs, mask=wg_mask, other=0.0) |
| 74 | |
| 75 | # Load W_up tile |
| 76 | wu_mask = (k_offs[:, None] < K) & (offs_n[None, :] < N) |
| 77 | wu = tl.load(wu_ptrs, mask=wu_mask, other=0.0) |
| 78 | |
| 79 | acc_gate += tl.dot(x, wg) |
| 80 | acc_up += tl.dot(x, wu) |
| 81 | |
| 82 | x_ptrs += BLOCK_SIZE_K * stride_xk |
| 83 | wg_ptrs += BLOCK_SIZE_K * stride_wgk |
nothing calls this directly
no outgoing calls
no test coverage detected