use cubecl::{ir::Scope, prelude::barrier::Barrier, prelude::*, unexpanded};
use cubecl_std::tensor::{
ViewMut, ViewMutExpand, VirtualViewMutExpand,
layout::{CoordsDyn, VirtualLayout},
};
use crate::*;
#[derive(CubeType, Clone)]
#[expand(derive(Clone))]
pub(crate) struct TmaData {
map: Raw<TiledMap>,
layout: VirtualLayout<CoordsDyn, Sequence<i32>>,
pos: CoordsDyn,
pub(crate) bound: CoordsDyn,
#[cube(comptime)]
pub(crate) units: usize,
#[cube(comptime)]
pub(crate) packing: Packing,
}
#[cube]
impl TmaData {
pub(crate) fn from_tensor_map<T: Numeric>(
map: TensorMap<T, Tiled>,
layout: VirtualLayout<CoordsDyn, Sequence<i32>>,
#[comptime] rank: usize,
#[comptime] units: usize,
#[comptime] packing: Packing,
) -> TmaData {
let bound = layout.shape();
let mut pos = CoordsDyn::new();
#[unroll]
for _ in 0..rank {
pos.push(0u32);
}
TmaData {
map: Raw::<TiledMap>::of::<T>(map),
layout,
pos,
bound,
units,
packing,
}
}
pub(crate) fn stage_into<T: Numeric>(&self, dst: &mut Memory, barrier: &Shared<Barrier>) {
comptime!(
dst.layout
.rows
.tma_swizzle()
.unwrap_or_else(|why| panic!("TmaData::stage_into: a TMA box cannot land {why}"))
);
match comptime!(dst.store.packing) {
Packing::Plain => self.view::<T>().tensor_map_load(
barrier,
dst.store.buffer_mut::<T>(),
self.pos.clone(),
),
Packing::Packed { .. } => self.view::<T>().tensor_map_load(
barrier,
unsafe { dst.store.buffer_mut::<u32>().downcast_mut_unchecked::<T>() },
self.pos.clone(),
),
}
}
pub(crate) fn load_into<T: Numeric>(&self, dst: &mut Memory) {
comptime!(assert!(
dst.address == AddressSpace::Shared,
"TmaData::load_into: a tensor map bulk-copies into shared memory only"
));
let barrier = Barrier::shared(CUBE_DIM, UNIT_POS == 0);
sync_async_proxy_shared();
let expected = select(UNIT_POS == 0, dst.size_bytes::<T>(), 0);
if UNIT_POS == 0 {
self.stage_into::<T>(dst, &barrier);
}
let token = barrier.arrive_and_expect_tx(1, expected);
barrier.wait(token);
}
pub(crate) fn store_from<T: Numeric>(&self, src: &Memory) {
comptime!(assert!(
src.address == AddressSpace::Shared,
"TmaData::store_from: a tensor map bulk-copies out of shared memory only"
));
comptime!(
src.layout
.rows
.assert_in_order("TmaData::store_from", "a descriptor stores a box dense")
);
sync_async_proxy_shared();
sync_cube();
if UNIT_POS == 0 {
match comptime!(src.store.packing) {
Packing::Plain => self
.view::<T>()
.tensor_map_store(src.store.buffer::<T>(), self.pos.clone())
.wait(),
Packing::Packed { .. } => self
.view::<T>()
.tensor_map_store(
unsafe { src.store.buffer::<u32>().downcast_unchecked::<T>() },
self.pos.clone(),
)
.wait(),
}
}
sync_cube();
}
#[allow(clippy::clone_on_copy)]
pub(crate) fn at(&self, step: &Step, #[comptime] space: Space) -> TmaData {
let mut pos = CoordsDyn::new();
#[unroll]
for p in 0..space.rank() {
let axis = space.axis_at(p);
match comptime!(step.level.tile(axis)) {
Some(tile) => {
let index = step.coord(axis);
pos.push(self.pos[p] + (index * tile) as u32);
}
None => pos.push(self.pos[p]),
}
}
TmaData {
map: self.map.clone(),
layout: self.layout.clone(),
pos,
bound: self.bound.clone(),
units: self.units,
packing: self.packing,
}
}
}
impl TmaData {
fn view<T: Numeric>(&self) -> ViewMut<'static, T, CoordsDyn> {
unexpanded!()
}
}
impl TmaDataExpand {
fn __expand_view_method<T: Numeric>(
&self,
scope: &Scope,
) -> ViewMutExpand<'static, T, CoordsDyn> {
let map = *self.map.__expand_at_method::<T>(scope);
let view = VirtualViewMutExpand::<T, CoordsDyn, Sequence<i32>, TensorMap<T, Tiled>>::new(
map,
self.layout.clone(),
);
ViewMutExpand::new(scope, view)
}
}