use cubecl::prelude::*;
use cubecl_std::tensor::{
layout::{CoordsDyn, Layout, LayoutExpand, as_dyn::IntoDynLayout},
view::launch::VirtualViewLayoutLaunch,
};
use crate::*;
#[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 TmaOperand {
pub fn arg(self) -> TileArgLaunch {
TileArgLaunch::tensor_map(self.map, &self.axes, self.shape)
}
}
impl TileArgLaunch {
pub fn tensor_map(tensor_map: TensorMapArg<Tiled>, axes: &[Axis], shape: TmaBox) -> Self {
let layout = Self::dyn_layout(axes, shape);
Self::of_tensor_map(
tensor_map,
VirtualViewLayoutLaunch::new::<IntoDynLayout<TmaDynLayout>>(layout),
TileSpec::direct(axes),
)
}
fn dyn_layout(axes: &[Axis], shape: TmaBox) -> TmaDynLayoutLaunch {
let batched = match (axes.len(), shape.batch) {
(2, None) => false,
(3, Some(_)) => true,
(r, batch) => panic!(
"TileArgLaunch::tensor_map: 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);
TmaDynLayoutLaunch::new(dims, batched, shape.transposed)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum TmaLanding {
Tiles,
Rows,
}
#[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
}
}