| |
|
|
| from typing import Type, Union, Optional |
|
|
| import cutlass |
| import cutlass.cute as cute |
| import cutlass.utils.hopper_helpers as sm90_utils_og |
| from cutlass.cute.nvgpu import warpgroup |
| from cutlass.cutlass_dsl import Numeric, dsl_user_op |
| from cutlass import Float32, Int32, Boolean, const_expr |
| from cutlass.utils import LayoutEnum |
|
|
|
|
| @dsl_user_op |
| def make_smem_layout( |
| dtype: Type[Numeric], |
| layout: LayoutEnum, |
| tile: cute.Tile, |
| stage: Optional[int] = None, |
| major_mode_size: Optional[int] = None, |
| *, |
| loc=None, |
| ip=None, |
| ) -> Union[cute.Layout, cute.ComposedLayout]: |
| shape = cute.product_each(cute.shape(tile, loc=loc, ip=ip), loc=loc, ip=ip) |
| if const_expr(major_mode_size is None): |
| major_mode_size = shape[1] if layout.is_n_major_c() else shape[0] |
| smem_layout_atom = warpgroup.make_smem_layout_atom( |
| sm90_utils_og.get_smem_layout_atom(layout, dtype, major_mode_size), |
| dtype, |
| ) |
| order = (1, 0, 2) if const_expr(layout.is_m_major_c()) else (0, 1, 2) |
| smem_layout_staged = cute.tile_to_shape( |
| smem_layout_atom, |
| cute.append(shape, stage) if const_expr(stage is not None) else shape, |
| order=order if const_expr(stage is not None) else order[:2], |
| ) |
| return smem_layout_staged |
|
|
|
|
| |
| make_smem_layout_epi = make_smem_layout |
|
|
|
|
| @dsl_user_op |
| def partition_for_epilogue( |
| cT: cute.Tensor, |
| epi_tile: cute.Tile, |
| tiled_copy: cute.TiledCopy, |
| tidx: Int32, |
| reference_src: bool, |
| *, |
| loc=None, |
| ip=None, |
| ) -> cute.Tensor: |
| thr_copy = tiled_copy.get_slice(tidx) |
| cT_epi = cute.flat_divide(cT, epi_tile) |
| |
| if const_expr(reference_src): |
| return thr_copy.partition_S(cT_epi, loc=loc, ip=ip) |
| else: |
| return thr_copy.partition_D(cT_epi, loc=loc, ip=ip) |
|
|
|
|
| @cute.jit |
| def gemm( |
| tiled_mma: cute.TiledMma, |
| acc: cute.Tensor, |
| tCrA: cute.Tensor, |
| tCrB: cute.Tensor, |
| zero_init: cutlass.Constexpr[bool] = False, |
| wg_wait: cutlass.Constexpr[int] = 0, |
| |
| swap_AB: cutlass.Constexpr[bool] = False, |
| ) -> None: |
| if const_expr(swap_AB): |
| gemm(tiled_mma, acc, tCrB, tCrA, zero_init=zero_init, wg_wait=wg_wait, swap_AB=False) |
| else: |
| warpgroup.fence() |
| |
| |
| mma_atom = cute.make_mma_atom(tiled_mma.op) |
| mma_atom.set(warpgroup.Field.ACCUMULATE, not zero_init) |
| for k in cutlass.range_constexpr(cute.size(tCrA.shape[2])): |
| cute.gemm(mma_atom, acc, tCrA[None, None, k], tCrB[None, None, k], acc) |
| mma_atom.set(warpgroup.Field.ACCUMULATE, True) |
| warpgroup.commit_group() |
| if const_expr(wg_wait >= 0): |
| warpgroup.wait_group(wg_wait) |
|
|
|
|
| def gemm_zero_init( |
| tiled_mma: cute.TiledMma, |
| shape: cute.Shape, |
| tCrA: cute.Tensor, |
| tCrB: cute.Tensor, |
| A_idx: Optional[Int32] = None, |
| B_idx: Optional[Int32] = None, |
| wg_wait: int = -1, |
| swap_AB: bool = False, |
| ) -> cute.Tensor: |
| if const_expr(swap_AB): |
| return gemm_zero_init( |
| tiled_mma, shape[::-1], tCrB, tCrA, B_idx, A_idx, wg_wait, swap_AB=False |
| ) |
| else: |
| acc = cute.make_rmem_tensor(tiled_mma.partition_shape_C(shape), Float32) |
| rA = tCrA if const_expr(A_idx is None) else tCrA[None, None, None, A_idx] |
| rB = tCrB if const_expr(B_idx is None) else tCrB[None, None, None, B_idx] |
| gemm(tiled_mma, acc, rA, rB, zero_init=True, wg_wait=wg_wait) |
| return acc |
|
|
|
|
| def gemm_w_idx( |
| tiled_mma: cute.TiledMma, |
| acc: cute.Tensor, |
| tCrA: cute.Tensor, |
| tCrB: cute.Tensor, |
| zero_init: Boolean, |
| A_idx: Optional[Int32] = None, |
| B_idx: Optional[Int32] = None, |
| wg_wait: int = -1, |
| swap_AB: bool = False, |
| ) -> None: |
| if const_expr(swap_AB): |
| gemm_w_idx(tiled_mma, acc, tCrB, tCrA, zero_init, B_idx, A_idx, wg_wait, swap_AB=False) |
| else: |
| rA = tCrA if const_expr(A_idx is None) else tCrA[None, None, None, A_idx] |
| rB = tCrB if const_expr(B_idx is None) else tCrB[None, None, None, B_idx] |
| gemm(tiled_mma, acc, rA, rB, zero_init=zero_init, wg_wait=wg_wait) |
|
|
|
|
| def partition_fragment_ABC( |
| thr_mma: cute.ThrMma, |
| shape_mnk: cute.Shape, |
| sA: Optional[cute.Tensor], |
| sB: Optional[cute.Tensor], |
| swap_AB: bool = False, |
| ): |
| is_rs = thr_mma.op.a_src == warpgroup.OperandSource.RMEM |
| if const_expr(not swap_AB): |
| acc = cute.make_rmem_tensor(thr_mma.partition_shape_C(shape_mnk[:2]), Float32) |
| if const_expr(not is_rs): |
| assert sA is not None |
| tCrA = thr_mma.make_fragment_A(thr_mma.partition_A(sA)) |
| else: |
| tCrA = thr_mma.make_fragment_A(thr_mma.partition_shape_A((shape_mnk[0], shape_mnk[2]))) |
| assert sB is not None |
| tCrB = thr_mma.make_fragment_B(thr_mma.partition_B(sB)) |
| else: |
| acc = cute.make_rmem_tensor( |
| thr_mma.partition_shape_C((shape_mnk[1], shape_mnk[0])), Float32 |
| ) |
| if const_expr(not is_rs): |
| assert sB is not None |
| tCrB = thr_mma.make_fragment_A(thr_mma.partition_A(sB)) |
| else: |
| tCrB = thr_mma.make_fragment_A(thr_mma.partition_shape_A((shape_mnk[1], shape_mnk[2]))) |
| assert sA is not None |
| tCrA = thr_mma.make_fragment_B(thr_mma.partition_B(sA)) |
| return acc, tCrA, tCrB |
|
|