use cubecl::prelude::*;
use crate::tile::accumulator::smem_cyclic::SmemCyclicAccumulation;
use crate::*;
#[derive(CubeType)]
pub struct PlanesOutput<A: Numeric, T: Numeric> {
out: Tile<T>,
merged: ComptimeOption<SmemCyclicAccumulation<A, T>>,
#[cube(comptime)]
sharing: Vec<(Axis, usize)>,
}
#[cube]
impl<T: Numeric> Tile<T> {
pub fn planes_output<A: Numeric>(&self, cube: &Region) -> PlanesOutput<A, T> {
let space = comptime!(self.place.space.clone());
let sharing = comptime!(cube.path.planes_along(|axis| !space.contains(axis)));
let writers = comptime!(sharing.iter().map(|&(_, count)| count).product::<usize>());
let merged = if comptime!(writers == 1) {
ComptimeOption::new_None()
} else {
ComptimeOption::new_Some(self.smem_cyclic_accumulation::<A>(writers))
};
PlanesOutput::<A, T> {
out: self.clone(),
merged,
sharing,
}
}
}
#[cube]
impl<A: Numeric, T: Numeric> PlanesOutput<A, T> {
pub fn drain<P: Numeric>(&self, partial: &Tile<P>, plane: &Region) {
#[comptime]
match &self.merged {
ComptimeOption::None => partial.drained_into(&self.out.at(plane)),
ComptimeOption::Some(merged) => {
merged.drain_at(partial, plane, PlanesOutput::<A, T>::writer(self, plane))
}
}
}
pub fn write(&mut self) {
#[comptime]
match &self.merged {
ComptimeOption::None => {}
ComptimeOption::Some(merged) => self.out.copy_from(&merged.source),
}
}
fn writer(&self, plane: &Region) -> usize {
let mut writer = 0usize;
#[unroll]
for i in 0..comptime!(self.sharing.len()) {
let (axis, count) = comptime!(self.sharing[i]);
writer = writer * count + plane.coord(axis);
}
writer
}
}