use crate::{Axis, ChunkSwizzle, LineBytes, Refusal, Space, StageForm};
use cubecl::prelude::TensorMapSwizzle;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum StageStorage {
Tiled {
block: Vec<(Axis, usize)>,
chunks: RowChunks,
},
Strided,
Lines {
read: UnitRead,
},
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
pub enum RowChunks {
InOrder,
Swizzled,
Padded,
}
impl RowChunks {
pub const CHUNK_BYTES: usize = 16;
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
pub enum UnitRead {
Shuffle,
#[serde(rename = "Window")]
PlaneShared,
}
impl StageStorage {
pub fn tma_swizzle(
&self,
space: &Space,
vector_size: usize,
elem_bits: usize,
) -> Result<TensorMapSwizzle, Refusal> {
assert!(
(vector_size * elem_bits).is_multiple_of(8),
"StageStorage::tma_swizzle: a line of {vector_size} {elem_bits}-bit values is not whole \
bytes"
);
let form = StageForm::dense(
space,
vector_size,
self.clone(),
LineBytes(vector_size * elem_bits / 8),
);
let swizzle = form
.rows
.tma_swizzle()
.map_err(|why| Refusal::RowsNoDescriptorLands { why })?;
let rank = space.rank();
let row = space.axis_at(rank - 1);
let period = match swizzle {
TensorMapSwizzle::None => 1,
_ => ChunkSwizzle::ROWS_PER_PERIOD,
};
for block in self.nesting(space) {
let rows = match rank {
1 => 1,
_ => block.extent_at(rank - 2),
};
if block.extent_at(rank - 1) < space.extent_at(rank - 1) || !rows.is_multiple_of(period)
{
return Err(Refusal::BoxSplitsStageBlocks {
axis: row,
rows,
period,
});
}
}
Ok(swizzle)
}
pub fn bytes(&self, space: &Space, vector_size: usize, elem_bits: usize) -> usize {
let line = vector_size * elem_bits / 8;
StageForm::dense(space, vector_size, self.clone(), LineBytes(line)).cells() * line
}
pub(crate) fn nesting(&self, space: &Space) -> Vec<Space> {
match self {
StageStorage::Lines { .. } => {
panic!("StageStorage::Lines: the plane's units are not shared memory")
}
StageStorage::Tiled { block, .. } => {
let nested = Space::new(
&space
.axes()
.map(|axis| {
let edge = block
.iter()
.find(|&&(a, _)| a == axis)
.unwrap_or_else(|| {
panic!(
"StageStorage::Tiled: the block states no edge for {axis:?}"
)
})
.1;
(axis, edge)
})
.collect::<Vec<_>>(),
);
if &nested == space {
return Vec::new();
}
vec![nested]
}
StageStorage::Strided => Vec::new(),
}
}
}