use cubecl::zspace::SmallVec;
use crate::Delivery;
use crate::{Axis, Boundary, BoundaryPolicy, Field, Packing, Paging, Projection, Space, Storage};
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TileSpec {
pub projection: Projection,
pub boundaries: SmallVec<[Option<Boundary>; Space::MAX_RANK]>,
pub units: usize,
pub(crate) packing: Packing,
pub storage: Storage,
pub stored_tiles: Vec<(Axis, usize)>,
pub delivery: Delivery,
pub paging: Option<Paging>,
}
impl TileSpec {
pub fn new(projection: Projection) -> Self {
TileSpec {
projection,
boundaries: SmallVec::new(),
units: 0,
packing: Packing::Plain,
storage: Storage::Strided,
stored_tiles: Vec::new(),
delivery: Delivery::SyncPerUnit,
paging: None,
}
}
pub fn direct(axes: &[Axis]) -> Self {
Self::new(Projection::direct(axes))
}
pub fn axes(&self) -> &[Axis] {
self.projection.logical_axes()
}
pub fn boundaries(mut self, boundaries: &[Option<Boundary>]) -> Self {
let coord_rank = self.projection.coordinate_rank();
assert!(
boundaries.len() == coord_rank,
"TileSpec::boundaries: {} modes stated but the operand has {coord_rank} coordinate \
axes",
boundaries.len()
);
self.boundaries = match boundaries.iter().any(Option::is_some) {
true => SmallVec::from_slice(boundaries),
false => SmallVec::new(),
};
self
}
pub fn boundary(self, policy: BoundaryPolicy) -> Self {
let coord_rank = self.projection.coordinate_rank();
match policy {
BoundaryPolicy::Unchecked => self.boundaries(&vec![None; coord_rank]),
BoundaryPolicy::Every(boundary) | BoundaryPolicy::AnyExtent(boundary) => {
self.boundaries(&vec![Some(boundary); coord_rank])
}
}
}
pub fn packed(mut self, field: impl Into<Field>) -> Self {
self.packing = Packing::Packed {
field: field.into(),
};
self
}
pub fn delivery(mut self, delivery: Delivery) -> Self {
assert!(
matches!(
delivery,
Delivery::SyncPerUnit | Delivery::AsyncPerUnit | Delivery::AsyncBulk
),
"TileSpec::delivery: a tensor is moved per unit or in bulk; {delivery:?} is a tensor \
map's or a coordinate tile's"
);
self.delivery = delivery;
self
}
pub fn is_checked(&self) -> bool {
self.boundaries.iter().any(Option::is_some)
}
}