use cubecl::prelude::*;
use crate::*;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) enum StageElement {
Served,
Stored,
}
#[cube]
impl<T: Numeric> Memory<T> {
pub(crate) fn fill_procedural(&mut self, src: &Procedural<T>, #[comptime] space: Space) {
comptime!(assert!(
self.store.packing == Packing::Plain
&& self.projection.is_direct()
&& self.store.vector_size == 1,
"Memory::fill_procedural: procedural sources require a plain, direct scalar destination"
));
let shape = self.window.extent.clone();
let fill = comptime!(self.access.fill);
let mut dst = self.flat_mut::<Const<1>>();
let total = dst.shape();
let stride = fill_workers(fill);
let mut i = fill_worker(fill);
while i < total {
let pos = shape.unravel(i.cast::<u32>());
dst.write(
i,
Vector::cast_from(src.read_masked(&pos, comptime!(space.clone()))),
);
i += stride;
}
}
pub(crate) fn stage(
operand: &Tile<T>,
#[comptime] level: Level,
#[comptime] storage: StageStorage,
#[comptime] width: Option<usize>,
#[comptime] owner: StageOwner,
) -> Tile<T> {
match comptime!(storage.clone()) {
StageStorage::Lines { read } => {
comptime!(refuse_for_a_plane(owner, "held in the plane's units"));
Tile::<T> {
kind: TileKind::new_Lines(Lines::<T>::new(
operand,
comptime!(level.clone()),
comptime!(read),
)),
place: comptime!(Placement::new(
level.child(&operand.place.space),
operand.place.depth + 1,
operand.place.levels.clone()
)),
}
}
_ => Memory::<T>::stage_memory(operand, level, storage, width, owner),
}
}
fn stage_memory(
operand: &Tile<T>,
#[comptime] level: Level,
#[comptime] storage: StageStorage,
#[comptime] width: Option<usize>,
#[comptime] owner: StageOwner,
) -> Tile<T> {
let decodes = operand.scaled();
let stored = operand.stage_element();
match comptime!(if decodes {
StageElement::Served
} else {
stored
}) {
StageElement::Served => {
let space = comptime!(level.child(&operand.place.space));
let projection = operand.projection();
let units = operand.units();
let source_width = operand.vector_size();
let vector_size = comptime!(match width {
Some(width) => {
assert!(
source_width == 1,
"Memory::stage: a padded stage assembles its lines from scalar \
source cells, so the operand it pads must be unvectorized (it is \
served {source_width} wide)"
);
assert!(
width > 1,
"Memory::stage: a padded stage width must widen the operand's own \
1-wide lines (got {width})"
);
width
}
None => source_width,
});
let delivery = operand.delivery();
let alignment = comptime!(match delivery.is_tma() {
true => TMA_STAGE_ALIGNMENT,
false => 0usize,
});
if comptime!(projection.is_direct() || decodes) {
Memory::smem_owned(space, vector_size, storage, units, alignment, owner)
} else {
comptime!(refuse_for_a_plane(owner, "gathered"));
Memory::smem_gathered(
space,
vector_size,
storage,
units,
projection,
&operand.runtime_map(),
operand.window_signed(),
operand.window_boundaries(),
)
}
}
StageElement::Stored => {
comptime!(refuse_for_a_plane(owner, "kept in its stored form"));
Memory::smem_stored(operand, level, storage)
}
}
}
fn smem_stored(
operand: &Tile<T>,
#[comptime] level: Level,
#[comptime] storage: StageStorage,
) -> Tile<T> {
let space = comptime!(level.child(&operand.place.space));
let vector_size = operand.vector_size();
let units = operand.units();
match &operand.kind {
TileKind::Memory(g) => match comptime!(g.store.packing) {
Packing::Plain => Memory::smem(space, vector_size, storage, units),
packing => Memory::smem_packed(space, vector_size, storage, units, packing),
},
TileKind::TmaGmem(_) => Memory::smem(space, vector_size, storage, units),
TileKind::PlaneTile(_) | TileKind::PlanePartition(_) => {
panic!("Memory::smem_stored: a fragment is not a stage source")
}
TileKind::Procedural(_) | TileKind::Lines(_) => {
panic!(
"Memory::smem_stored: a procedural tile and the plane's units are not a stage source"
)
}
}
}
}
fn refuse_for_a_plane(owner: StageOwner, form: &str) {
assert!(
owner == StageOwner::Cube,
"Memory::stage: this walk hands each plane a stage of its own, which is laid out only for \
a plain shared-memory stage of served values, and this one is {form}; stage the operand \
plain, or walk it from the cube"
);
}