#pragma once #include "common.cuh" #include "mma.cuh" // XOR swizzle for K/V SMEM tiles to avoid bank conflicts without row padding (Turing+ only). // Stride must be a multiple of 32 half2 columns, otherwise we keep +4 row padding. namespace ggml_cuda_fattn_smem_swizzle { static __host__ __device__ constexpr bool bank_aligned(const int nbatch_2) { return nbatch_2 >= 32 && nbatch_2 % 32 == 0; } static __device__ constexpr bool enabled(const int nbatch_2) { #if defined(TURING_MMA_AVAILABLE) return bank_aligned(nbatch_2); #else GGML_UNUSED(nbatch_2); return false; #endif // defined(TURING_MMA_AVAILABLE) } static __host__ bool enabled(const int nbatch_2, const int cc) { #ifdef GGML_USE_HIP GGML_UNUSED(nbatch_2); GGML_UNUSED(cc); return false; #else return turing_mma_available(cc) && bank_aligned(nbatch_2); #endif // GGML_USE_HIP } static __device__ constexpr int tile_stride(const int nbatch_2) { return enabled(nbatch_2) ? nbatch_2 : nbatch_2 + 4; } static __host__ int tile_stride(const int nbatch_2, const int cc) { return enabled(nbatch_2, cc) ? nbatch_2 : nbatch_2 + 4; } // Swizzled byte offset for tile element (row, col_h2), same map used for writes and reads. template static __device__ __forceinline__ int bytes_rc(const int row, const int col_h2) { static_assert(bank_aligned(stride_h2), "swizzled tile needs a stride that is a multiple of 32"); return ((row * stride_h2 + col_h2) * (int) sizeof(half2)) ^ ((row & 7) << 4); } // ldmatrix.x4 via 64-bit generic pointer. static __device__ __forceinline__ void ldmatrix_x4(int * xi, const half2 * addr) { #if defined(TURING_MMA_AVAILABLE) asm volatile("ldmatrix.sync.aligned.m8n8.x4.b16 {%0, %1, %2, %3}, [%4];" : "=r"(xi[0]), "=r"(xi[1]), "=r"(xi[2]), "=r"(xi[3]) : "l"(addr)); #else GGML_UNUSED_VARS(xi, addr); NO_DEVICE_CODE; #endif // defined(TURING_MMA_AVAILABLE) } static __device__ __forceinline__ void ldmatrix_x4_trans(int * xi, const half2 * addr) { #if defined(TURING_MMA_AVAILABLE) asm volatile("ldmatrix.sync.aligned.m8n8.x4.trans.b16 {%0, %1, %2, %3}, [%4];" : "=r"(xi[0]), "=r"(xi[2]), "=r"(xi[1]), "=r"(xi[3]) : "l"(addr)); #else GGML_UNUSED_VARS(xi, addr); NO_DEVICE_CODE; #endif // defined(TURING_MMA_AVAILABLE) } // Per-lane swizzled address for one tile<16, 8, half2> ldmatrix: 16 rows, 4 half2 columns per lane. template static __device__ __forceinline__ const half2 * lane_addr( const half2 * tile_base, const int base_row, const int base_col_h2, const int I, const int J) { static_assert(bank_aligned(stride_h2), "swizzled tile needs a stride that is a multiple of 32"); const int lane_row = threadIdx.x % I; const int lane_col = (threadIdx.x / I) * (J / 2); uint32_t byte_off = (uint32_t) ((base_row + lane_row)*stride_h2 + base_col_h2 + lane_col) * (uint32_t) sizeof(half2); byte_off ^= (uint32_t) (((base_row + lane_row) & 7) << 4); return (const half2 *) ((const char *) tile_base + byte_off); } template static __device__ __forceinline__ void load_ldmatrix( TileT & t, const half2 * tile_base, const int base_row, const int base_col_h2) { if constexpr (swz) { static_assert(std::is_same_v>, "the swizzled layout is only supported for tile<16, 8, half2>"); ldmatrix_x4((int *) t.x, lane_addr(tile_base, base_row, base_col_h2, TileT::I, TileT::J)); } else { ggml_cuda_mma::load_ldmatrix(t, tile_base + base_row*stride_h2 + base_col_h2, stride_h2); } } template static __device__ __forceinline__ void load_ldmatrix(TileT & t, const half2 * tile_base, const int off_h2) { if constexpr (swz) { load_ldmatrix(t, tile_base, off_h2 / stride_h2, off_h2 % stride_h2); } else { ggml_cuda_mma::load_ldmatrix(t, tile_base + off_h2, stride_h2); } } template static __device__ __forceinline__ void load_ldmatrix_trans( TileT & t, const half2 * tile_base, const int base_row, const int base_col_h2) { if constexpr (swz) { static_assert(std::is_same_v>, "the swizzled layout is only supported for tile<16, 8, half2>"); ldmatrix_x4_trans((int *) t.x, lane_addr(tile_base, base_row, base_col_h2, TileT::I, TileT::J)); } else { ggml_cuda_mma::load_ldmatrix_trans(t, tile_base + base_row*stride_h2 + base_col_h2, stride_h2); } } template static __device__ __forceinline__ void load_ldmatrix_trans(TileT & t, const half2 * tile_base, const int off_h2) { if constexpr (swz) { load_ldmatrix_trans(t, tile_base, off_h2 / stride_h2, off_h2 % stride_h2); } else { ggml_cuda_mma::load_ldmatrix_trans(t, tile_base + off_h2, stride_h2); } } } // namespace ggml_cuda_fattn_smem_swizzle