use cubecl::{intrinsic, prelude::*, std::Swizzle};
use crate::MatrixLayout;
use crate::stage::{StageMemoryConfig, as_swizzle_object};
use crate::tile::variants::instruction::{
cmma::cmma_write_to_shared,
interleaved::interleaved_write_to_shared,
mma::{MmaFragment, MmaFragmentExpand, mma_write_to_shared},
plane_vec::planevec_write_to_shared,
register::register_write_to_shared,
};
use crate::tile::{Tile, TileKind, TileKindExpand, TileScope};
#[derive(CubeType, Clone)]
#[expand(derive(Clone))]
pub struct StridedTile<ES: Numeric, N: Size> {
pub container: Box<[Vector<ES, N>]>,
pub start: u32,
pub end: u32,
pub stride: u32,
pub swizzle: Swizzle,
#[cube(comptime)]
pub layout: MatrixLayout,
}
#[cube]
impl<ES: Numeric, N: Size> StridedTile<ES, N> {
pub fn new_contiguous(
container: &[Vector<ES, N>],
start: u32,
#[comptime] config: StageMemoryConfig,
) -> StridedTile<ES, N> {
let len = config.elements_per_tile() / config.vector_size;
let layout = config.matrix_layout;
let stride = match layout {
MatrixLayout::RowMajor => config.elements_per_tile_along_col,
MatrixLayout::ColMajor => config.elements_per_tile_along_row,
};
let stride = stride / config.vector_size;
StridedTile::<ES, N> {
container: unsafe { container.as_boxed_unchecked() },
start,
end: start + len,
stride,
swizzle: as_swizzle_object(config.swizzle),
layout,
}
}
pub fn new_strided(
container: &[Vector<ES, N>],
start: u32,
end: u32,
stride: u32,
swizzle: Swizzle,
#[comptime] layout: MatrixLayout,
) -> StridedTile<ES, N> {
StridedTile::<ES, N> {
container: unsafe { container.as_boxed_unchecked() },
start,
end,
stride,
swizzle,
layout,
}
}
}
#[cube]
impl<ES: Numeric, N: Size> StridedTile<ES, N> {
pub fn unvectorized_stride(&self) -> u32 {
let stage_vector_size = self.container.vector_size();
self.stride * stage_vector_size as u32
}
}
#[cube]
impl<ES: Numeric, N: Size> StridedTile<ES, N> {
pub fn as_slice(&self) -> &[Vector<ES, N>] {
&self.container[self.start as usize..self.end as usize]
}
pub fn as_slice_mut(&mut self) -> &mut [Vector<ES, N>] {
&mut self.container[self.start as usize..self.end as usize]
}
}
#[cube]
impl<ES: Numeric, N: Size> StridedTile<ES, N> {
pub fn get_vector(&self, coor_strided: u32, coor_contiguous: u32) -> Vector<ES, N> {
let offset = coor_strided * self.stride + coor_contiguous;
let offset_abs = self.start + offset;
let type_size = Vector::<ES, N>::type_size();
let offset_swizzled = self.swizzle.apply(offset_abs, type_size);
self.container[offset_swizzled as usize]
}
pub fn stage_offset(&self, relative_offset: u32) -> u32 {
let offset = self.start + relative_offset;
let type_size = Vector::<ES, N>::type_size();
self.swizzle.apply(offset, type_size)
}
#[allow(unused_variables)]
pub fn with_vector_size<N2: Size>(&self) -> StridedTile<ES, N2> {
let vector_size = N2::value();
intrinsic!(|scope| {
let stage_vector_size = self.container.vector_size();
if vector_size == self.container.vector_size() {
return self.__expand_with_stage_vector_size_method(scope);
}
let current = stage_vector_size;
let mut out: StridedTileExpand<ES, N2> =
self.clone().__expand_with_stage_vector_size_method(scope);
if current < vector_size {
let ratio = ((vector_size / current) as u32).into_expand(scope);
let start = self.start.__expand_div_method(scope, ratio);
let end = self.end.__expand_div_method(scope, ratio);
let stride = self.stride.__expand_div_method(scope, ratio);
out.start = start;
out.end = end;
out.stride = stride;
} else {
let ratio = ((current / vector_size) as u32).into_expand(scope);
let start = self.start.__expand_mul_method(scope, ratio);
let end = self.end.__expand_mul_method(scope, ratio);
let stride = self.stride.__expand_mul_method(scope, ratio);
out.start = start;
out.end = end;
out.stride = stride;
}
out
})
}
#[allow(unused)]
unsafe fn with_stage_vector_size<N2: Size>(&self) -> StridedTile<ES, N2> {
StridedTile::<ES, N2> {
container: unsafe { self.container.with_vector_size::<N2>().as_boxed_unchecked() },
start: self.start,
end: self.end,
stride: self.stride,
swizzle: self.swizzle,
layout: self.layout,
}
}
}
#[derive(CubeType, Clone)]
pub struct SharedTile<E: Numeric> {
pub(crate) container: Box<[E]>,
pub(crate) start: u32,
pub(crate) end: u32,
pub(crate) stride: u32,
pub(crate) swizzle: Swizzle,
#[cube(comptime)]
pub(crate) layout: MatrixLayout,
}
#[cube]
impl<E: Numeric> SharedTile<E> {
pub fn wrap<V: Size>(tile: StridedTile<E, V>) -> SharedTile<E> {
let container = unsafe { tile.container.downcast_unchecked::<E>() };
SharedTile::<E> {
container: unsafe { container.as_boxed_unchecked() },
start: tile.start,
end: tile.end,
stride: tile.stride,
swizzle: tile.swizzle,
layout: tile.layout,
}
}
pub fn view<V: Size>(&self) -> StridedTile<E, V> {
let container = unsafe { self.container.downcast_unchecked::<Vector<E, V>>() };
StridedTile::<E, V> {
container: unsafe { container.as_boxed_unchecked() },
start: self.start,
end: self.end,
stride: self.stride,
swizzle: self.swizzle,
layout: self.layout,
}
}
}
#[cube]
impl<E: Numeric> SharedTile<E> {
pub fn copy_from<SE: Numeric, SS: Size, L: Numeric, R: Numeric, Sc: TileScope>(
&mut self,
source: &Tile<SE, Sc>,
) {
match &source.kind {
TileKind::Cmma(t) => cmma_write_to_shared::<E, SS, SE>(self, &t.matrix),
TileKind::Bounce(b) => cmma_write_to_shared::<E, SS, SE>(self, &b.cmma.matrix),
TileKind::Mma(t) => match &t.fragment {
MmaFragment::Acc(f) => {
mma_write_to_shared::<E, SS, SE, L, R>(self, f, t.tile_size, t.mma_io_config);
}
MmaFragment::Lhs(_) | MmaFragment::Rhs(_) => {
panic!("Mma write_to_shared only supported for Acc role")
}
},
TileKind::Register(t) => {
register_write_to_shared::<E, SS, SE>(self, &t.tile.data, t.tile_size);
}
TileKind::PlaneVec(t) => {
planevec_write_to_shared::<SE, E, SS>(
self,
&t.data,
t.tile_size,
t.reduce_vector_size,
);
}
TileKind::Interleaved(t) => {
interleaved_write_to_shared::<E, SS, SE>(self, &t.data, t.tile_size);
}
_ => panic!("SharedTile::copy_from: unsupported source variant"),
}
}
}