use cubecl::ir::{ElemType, Scope};
use cubecl::prelude::*;
use super::{Reads, Recipe, RecipeCoords};
use crate::*;
#[derive(CubeType, Clone)]
#[expand(derive(Clone))]
pub struct MemoryValues {
memory: Memory,
#[cube(comptime)]
element: ElemType,
}
#[cube]
impl Tile {
pub fn values(&self) -> MemoryValues {
match &self.kind {
TileKind::Memory(memory) => MemoryValues {
memory: memory.clone(),
element: comptime!(self.element),
},
TileKind::TmaGmem(_)
| TileKind::PlaneTile(_)
| TileKind::PlanePartition(_)
| TileKind::Procedural(_)
| TileKind::Lines(_) => {
panic!("Tile::values: only a memory tile is read one value at a time")
}
}
}
}
#[cube]
impl MemoryValues {
pub fn read<T: Numeric>(&self, #[comptime] axes: Vec<Axis>, coordinates: &Coords<u32>) -> T {
let define!(Stored) = self.element;
let logical = comptime!(self.memory.projection.logical_axes().to_vec());
let mut position = Coords::<u32>::new();
#[allow(clippy::needless_range_loop)]
#[unroll]
for p in 0..logical.len() {
let axis = comptime!(logical[p]);
match comptime!(axes.iter().position(|&named| named == axis)) {
Some(named) => position.push(coordinates.at(named)),
None => position.push(u32::cast_from(self.memory.window.origin.at(p))),
}
}
let size!(One) = 1usize;
let view = self.memory.read_view::<Stored, One>(self.memory.base());
T::cast_from(view.read_checked(position.to_dyn()).extract(0usize))
}
}
#[cube]
impl<T: Numeric> Recipe<T> for MemoryValues {
fn evaluate(&self, coordinates: &RecipeCoords) -> T {
let axes = comptime!(coordinates.space.axes().collect::<Vec<_>>());
let mut at = Coords::<u32>::new();
#[unroll]
for p in 0..axes.len() {
at.push(coordinates.at(p));
}
self.read::<T>(axes, &at)
}
}
impl Reads for MemoryValuesExpand {
fn reads(&self, _scope: &Scope, axis: Axis) -> bool {
self.memory.projection.logical_axes().contains(&axis)
}
}