use cubecl::prelude::*;
use super::leaf as reduce;
use crate::*;
#[cube]
impl Tile {
pub fn reduce_axis(&mut self, input: &Tile, #[comptime] monoid: Monoid) {
let define!(Served) = self.element;
self.init_identity::<Served>(monoid);
self.reduce_axis_accumulate(input, monoid);
}
pub fn dot<E: Float>(&mut self, lhs: &Tile, rhs: &Tile) {
let (width, rhs_width) = (lhs.vector_size(), rhs.vector_size());
comptime!(assert!(
lhs.place.space == rhs.place.space && width == rhs_width,
"Tile::dot: both factors span one space at one width, not {:?} at {width} and {:?} \
at {rhs_width}",
lhs.place.space,
rhs.place.space,
));
let define!(Lhs) = lhs.read_element();
let define!(Rhs) = rhs.read_element();
let space = comptime!(self.place.space.clone());
let cells = comptime!(space.cells());
let size!(V) = width;
let values = reduce::dot_cells::<E, Lhs, Rhs, V>(lhs, rhs, space);
self.set_cells(&values, cells);
}
pub fn reduce_axis_accumulate(&mut self, input: &Tile, #[comptime] monoid: Monoid) {
let define!(Served) = self.element;
let define!(Source) = input.read_element();
reduce_leaf::<Served, Source>(self, input, monoid)
}
}
#[cube]
pub(crate) fn reduce_leaf<Acc: Numeric, In: Numeric>(
acc: &mut Tile,
input: &Tile,
#[comptime] monoid: Monoid,
) {
let input_space = comptime!(input.place.space.clone());
let vector_size = input.vector_size();
comptime!(assert!(
input_space
.extent_at(input_space.rank() - 1)
.is_multiple_of(vector_size),
"reduce: the input's innermost extent must be divisible by its vector size"
));
let space = comptime!(acc.place.space.clone());
match &mut acc.kind {
TileKind::Memory(g) => {
reduce::memory::<Acc, In>(g, input, space, monoid);
}
TileKind::PlaneTile(t) => {
reduce_plane_tile::<Acc, In>(t, input, space, monoid);
}
TileKind::PlanePartition(p) => {
comptime!(assert!(
p.m_tiles == 1 && p.n_tiles == 1,
"reduce_leaf: a multi-tile partition must be contracted at its partition level"
));
let mut t = p.at(0usize, 0usize);
reduce_plane_tile::<Acc, In>(&mut t, input, space, monoid);
}
TileKind::TmaGmem(_) => panic!("reduce: a tma source is not an accumulator sink"),
TileKind::Procedural(_) | TileKind::Lines(_) => {
panic!("reduce: a procedural tile and the plane's units are not an accumulator sink")
}
}
}
#[cube]
fn reduce_plane_tile<Acc: Numeric, In: Numeric>(
tile: &mut PlaneTile,
input: &Tile,
#[comptime] acc_space: Space,
#[comptime] monoid: Monoid,
) {
match tile {
PlaneTile::Registers(d) => {
reduce::register_data::<Acc, In>(d, input, acc_space, monoid);
}
PlaneTile::Cmma(_) | PlaneTile::Mma(_) | PlaneTile::Wgmma(_) => {
panic!(
"reduce: a hardware mma fragment scatters its rows across units in a \
layout the elementwise walk cannot address; reduce into a register, \
Gmem or Smem accumulator instead"
);
}
}
}