use cubecl::prelude::*;
use cubecl::std::tensor::{
ViewMut,
layout::{CoordsDyn, Layout, LayoutExpand},
view::launch::ViewArg,
};
use crate::*;
#[derive(CubeType, CubeLaunch)]
pub struct TmaTileArg<E: Numeric> {
pub view: ViewMut<'static, E, CoordsDyn>,
#[cube(comptime)]
pub spec: TileSpec,
}
#[cube]
impl<E: Numeric> TmaTileArg<E> {
pub fn tile(&self, #[comptime] space: Partitioning) -> Tile<E> {
let own = comptime!(space.space().subspace(self.spec.axes()));
let data = TmaData::from_tensor_map(
self.view.clone(),
comptime!(own.rank()),
comptime!(self.spec.units),
);
Tile::new(
TileKind::new_TmaGmem(data),
comptime!(Placement::root(own.clone(), space.levels().to_vec())),
)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct TmaBox {
pub rows: u32,
pub cols: u32,
pub batch: Option<u32>,
pub transposed: bool,
}
pub struct TmaOperand {
pub map: TensorMapArg<Tiled>,
pub axes: Vec<Axis>,
pub shape: TmaBox,
}
impl<E: Numeric> TmaTileArgLaunch<E> {
pub fn tensor_map(tensor_map: TensorMapArg<Tiled>, axes: &[Axis], shape: TmaBox) -> Self {
let batched = match (axes.len(), shape.batch) {
(2, None) => false,
(3, Some(_)) => true,
(r, batch) => panic!(
"TmaTileArg: the descriptor is (batch, row, col); {r} axes with batch {batch:?} \
is not a matrix nor a batched one"
),
};
let dims = (shape.batch.unwrap_or(1), shape.rows, shape.cols);
let layout = TmaDynLayoutLaunch::new(dims, batched, shape.transposed);
let view = ViewArg::new_tensor_map_tiled::<TmaDynLayout>(tensor_map, layout);
Self::new(view, TileSpec::direct(axes))
}
pub fn tensor_map_stored(
tensor_map: TensorMapArg<Tiled>,
axes: &[Axis],
dims: (u32, u32),
tile: (u32, u32),
) -> Self {
assert_eq!(
axes.len(),
2,
"TmaTileArg: a storage-tiled descriptor is a matrix; batch it by launching per batch"
);
let layout = TmaStoredLayoutLaunch::new(dims, tile);
let view = ViewArg::new_tensor_map_tiled::<TmaStoredLayout>(tensor_map, layout);
Self::new(view, TileSpec::direct(axes))
}
}
#[derive(CubeType, CubeLaunch, Clone)]
pub(crate) struct TmaStoredLayout {
dims: (u32, u32),
tile: (u32, u32),
}
#[cube]
impl Layout for TmaStoredLayout {
type Coordinates = CoordsDyn;
type SourceCoordinates = CoordsDyn;
fn to_source_pos(&self, pos: Self::Coordinates) -> Self::SourceCoordinates {
let (tile_rows, tile_cols) = self.tile;
let mut src = CoordsDyn::new();
src.push(pos[0] / tile_rows);
src.push(pos[1] / tile_cols);
src.push(0u32);
src.push(0u32);
src
}
fn to_source_pos_checked(&self, pos: Self::Coordinates) -> (Self::SourceCoordinates, bool) {
(self.to_source_pos(pos), true)
}
fn shape(&self) -> Self::Coordinates {
let (rows, cols) = self.dims;
let mut s = CoordsDyn::new();
s.push(rows);
s.push(cols);
s
}
fn is_in_bounds(&self, _pos: Self::Coordinates) -> bool {
true
}
}
#[derive(CubeType, CubeLaunch, Clone)]
pub(crate) struct TmaDynLayout {
dims: (u32, u32, u32),
#[cube(comptime)]
batched: bool,
#[cube(comptime)]
transposed: bool,
}
#[cube]
impl Layout for TmaDynLayout {
type Coordinates = CoordsDyn;
type SourceCoordinates = CoordsDyn;
fn to_source_pos(&self, pos: Self::Coordinates) -> Self::SourceCoordinates {
let (batch, _rows, _cols) = self.dims;
let mut src = CoordsDyn::new();
if comptime!(self.batched) {
src.push(select(batch == 1, 0u32, pos[0]));
} else {
src.push(0u32);
}
let (r, c) = comptime!(if self.batched { (1, 2) } else { (0, 1) });
if comptime!(self.transposed) {
src.push(pos[c]);
src.push(pos[r]);
} else {
src.push(pos[r]);
src.push(pos[c]);
}
src
}
fn to_source_pos_checked(&self, pos: Self::Coordinates) -> (Self::SourceCoordinates, bool) {
(self.to_source_pos(pos), true)
}
fn shape(&self) -> Self::Coordinates {
let (batch, rows, cols) = self.dims;
let mut s = CoordsDyn::new();
if comptime!(self.batched) {
s.push(batch);
}
s.push(rows);
s.push(cols);
s
}
fn is_in_bounds(&self, _pos: Self::Coordinates) -> bool {
true
}
}