use alloc::vec;
use core::marker::PhantomData;
use crate as cubecl;
use crate::{prelude::*, unexpanded};
use cubecl_ir::{ElemType, VectorSize};
use cubecl_runtime::server::TensorMapMeta;
use cubecl_zspace::{Strides, metadata::Metadata, strides};
use paste::paste;
pub use cubecl_runtime::tma::*;
pub trait TensorMapKind: CubeType + Clone + Copy + Send + Sync + 'static {
type Args: Clone;
fn as_format(args: Self::Args) -> TensorMapFormat;
}
#[derive(CubeType, CubeLaunch, Clone, Copy)]
pub struct Tiled {}
#[derive(CubeType, CubeLaunch, Clone, Copy)]
pub struct Im2col;
#[derive(CubeType, CubeLaunch, Clone, Copy)]
pub struct Im2colWide;
impl TensorMapKind for Tiled {
type Args = TiledArgs;
fn as_format(args: Self::Args) -> TensorMapFormat {
TensorMapFormat::Tiled(args)
}
}
impl TensorMapKind for Im2col {
type Args = Im2colArgs;
fn as_format(args: Self::Args) -> TensorMapFormat {
TensorMapFormat::Im2col(args)
}
}
impl TensorMapKind for Im2colWide {
type Args = Im2colWideArgs;
fn as_format(args: Self::Args) -> TensorMapFormat {
TensorMapFormat::Im2colWide(args)
}
}
pub struct TensorMapArg<K: TensorMapKind> {
pub tensor: TensorArg,
pub metadata: TensorMapMeta,
pub _kind: PhantomData<K>,
}
impl<K: TensorMapKind> TensorMapArg<K> {
pub fn new(args: K::Args, tensor: TensorArg, storage_ty: impl Into<ElemType>) -> Self {
let storage_ty = storage_ty.into();
let TensorArg::Handle { handle, .. } = &tensor else {
panic!("Can't use alias for TensorMap")
};
let rank = handle.shape.len();
Self {
metadata: TensorMapMeta {
format: K::as_format(args),
metadata: Metadata::new(handle.shape.clone(), handle.strides.clone()),
elem_stride: strides![1; rank],
interleave: TensorMapInterleave::None,
swizzle: TensorMapSwizzle::None,
prefetch: TensorMapPrefetch::None,
oob_fill: OobFill::Zero,
elem_ty: storage_ty,
},
tensor,
_kind: PhantomData,
}
}
pub fn with_elem_stride(mut self, elem_stride: Strides) -> Self {
self.metadata.elem_stride = elem_stride;
self
}
pub fn with_interleave(mut self, interleave: TensorMapInterleave) -> Self {
self.metadata.interleave = interleave;
self
}
pub fn with_swizzle(mut self, swizzle: TensorMapSwizzle) -> Self {
self.metadata.swizzle = swizzle;
self
}
pub fn with_prefetch(mut self, prefetch: TensorMapPrefetch) -> Self {
self.metadata.prefetch = prefetch;
self
}
pub fn with_nan_fill(mut self) -> Self {
self.metadata.oob_fill = OobFill::NaN;
self
}
}
#[derive(Clone)]
pub struct TensorMap<E: CubePrimitive, K: TensorMapKind> {
_ty: PhantomData<E>,
_kind: PhantomData<K>,
}
impl<E: CubePrimitive, K: TensorMapKind> Copy for TensorMap<E, K> {}
impl<E: CubePrimitive, K: TensorMapKind> TensorMap<E, K> {}
impl<E: CubePrimitive, K: TensorMapKind> IntoMut for NativeExpand<TensorMap<E, K>> {
fn into_mut(self, _scope: &Scope) -> Self {
self
}
}
impl<E: CubePrimitive, K: TensorMapKind> CubeType for TensorMap<E, K> {
type ExpandType = NativeExpand<TensorMap<E, K>>;
}
impl<E: CubePrimitive, K: TensorMapKind> AsMutExpand for NativeExpand<TensorMap<E, K>> {
fn __expand_ref_mut_method(&mut self, _: &Scope) -> &mut Self {
self
}
}
impl<E: CubePrimitive, K: TensorMapKind> Vectorized for TensorMap<E, K> {}
impl<E: CubePrimitive, K: TensorMapKind> VectorizedExpand for NativeExpand<TensorMap<E, K>> {
fn __expand_vector_size_method(&self, _scope: &Scope) -> VectorSize {
1
}
}
impl<E: CubePrimitive, K: TensorMapKind> LaunchArg for TensorMap<E, K> {
type RuntimeArg = TensorMapArg<K>;
type CompilationArg = ();
fn register(arg: Self::RuntimeArg, launcher: &mut KernelLauncher) -> Self::CompilationArg {
let elem_size = launcher.with_scope(|scope| E::__expand_size(scope));
launcher.register_tensor_map(arg, elem_size);
}
fn expand(
_arg: &Self::CompilationArg,
builder: &mut KernelBuilder,
) -> NativeExpand<TensorMap<E, K>> {
let tensor = builder.tensor_map();
tensor.into()
}
}
pub fn tma_group_commit() {
unexpanded!()
}
pub mod tma_group_commit {
use cubecl_ir::dialect::tma::CommitGroupOp;
use super::*;
pub fn expand(scope: &Scope) {
scope.register(&CommitGroupOp::new(scope.ctx_mut()))
}
}
pub fn tma_group_wait(_max_pending: usize) {
unexpanded!()
}
pub mod tma_group_wait {
use cubecl_ir::dialect::tma::WaitGroupOp;
use super::*;
pub fn expand(scope: &Scope, max_pending: usize) {
scope.register(&WaitGroupOp::new(scope.ctx_mut(), max_pending));
}
}
pub fn tma_group_wait_read(_max_pending: usize) {
unexpanded!()
}
pub mod tma_group_wait_read {
use cubecl_ir::dialect::tma::WaitGroupReadOp;
use super::*;
pub fn expand(scope: &Scope, max_pending: usize) {
scope.register(&WaitGroupReadOp::new(scope.ctx_mut(), max_pending))
}
}
macro_rules! tma_store {
($dim: literal, $($arg: expr),*) => {
paste! {
#[allow(unused)]
pub fn [<tma_store_ $dim d>]<T: CubePrimitive, T2: CubePrimitive<Scalar = T::Scalar>>(
src: &[T2],
dst: &mut TensorMap<T, Tiled>,
$($arg: i32),*
) {
unexpanded!()
}
pub mod [<tma_store_ $dim d>] {
use cubecl_ir::dialect::tma::TmaStoreOp;
use super::*;
#[allow(clippy::too_many_arguments)]
pub fn expand<T: CubePrimitive, T2: CubePrimitive<Scalar = T::Scalar>>(
scope: &Scope,
src: &SliceExpand<T2>,
dst: &mut NativeExpand<TensorMap<T, Tiled>>,
$($arg: NativeExpand<i32>),*
) {
let source = unsafe { *src.__expand_as_ptr_method(scope) }.value(scope);
let dst = dst.value(scope);
let coordinates = vec![$($arg.read_value(scope)),*];
scope.register(&TmaStoreOp::new(
scope.ctx_mut(),
source,
dst,
coordinates,
));
}
}
}
};
}
tma_store!(1, x);
tma_store!(2, y, x);
tma_store!(3, z, y, x);
tma_store!(4, w, z, y, x);
tma_store!(5, v, w, z, y, x);
mod metadata {
use cubecl_ir::dialect::general::{ShapeOp, StrideOp};
use crate::frontend::container::buffer_len::expand_buffer_length_native;
use super::*;
type TensorMapExpand<T, K> = NativeExpand<TensorMap<T, K>>;
#[cube]
impl<T: Scalar, K: TensorMapKind> TensorMap<T, K> {
pub fn coordinate(&self, index: usize, dim: usize) -> usize {
let stride = self.stride(dim);
let shape = self.shape(dim);
(index / stride) % shape
}
}
impl<T: Scalar, K: TensorMapKind> TensorMap<T, K> {
pub fn stride(&self, _dim: usize) -> usize {
unexpanded!()
}
pub fn shape(&self, _dim: usize) -> usize {
unexpanded!()
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
unexpanded!()
}
#[allow(clippy::len_without_is_empty)]
pub fn buffer_len(&self) -> usize {
unexpanded!()
}
pub fn rank(&self) -> usize {
unexpanded!()
}
pub fn downcast<E: CubePrimitive>(&self) -> TensorMap<E, K> {
unexpanded!()
}
pub fn __expand_stride(
scope: &Scope,
expand: NativeExpand<TensorMap<T, K>>,
dim: NativeExpand<usize>,
) -> NativeExpand<usize> {
expand.__expand_stride_method(scope, dim)
}
pub fn __expand_shape(
scope: &Scope,
expand: NativeExpand<TensorMap<T, K>>,
dim: NativeExpand<usize>,
) -> NativeExpand<usize> {
expand.__expand_shape_method(scope, dim)
}
pub fn __expand_len(
scope: &Scope,
expand: NativeExpand<TensorMap<T, K>>,
) -> NativeExpand<usize> {
expand.__expand_len_method(scope)
}
pub fn __expand_buffer_len(
scope: &Scope,
expand: NativeExpand<TensorMap<T, K>>,
) -> NativeExpand<usize> {
expand.__expand_buffer_len_method(scope)
}
pub fn __expand_rank(
scope: &Scope,
expand: NativeExpand<TensorMap<T, K>>,
) -> NativeExpand<usize> {
expand.__expand_rank_method(scope)
}
}
impl<T: CubePrimitive, K: TensorMapKind> NativeExpand<TensorMap<T, K>> {
pub fn __expand_stride_method(
self,
scope: &Scope,
dim: NativeExpand<usize>,
) -> NativeExpand<usize> {
let buffer_idx = ext_meta_idx(scope, self.value(scope));
let dim = dim.read_value(scope);
let op = StrideOp::new(scope.ctx_mut(), dim, buffer_idx);
scope.register_with_result(&op).into()
}
pub fn __expand_shape_method(
self,
scope: &Scope,
dim: NativeExpand<usize>,
) -> NativeExpand<usize> {
let buffer_idx = ext_meta_idx(scope, self.value(scope));
let dim = dim.read_value(scope);
let op = ShapeOp::new(scope.ctx_mut(), dim, buffer_idx);
scope.register_with_result(&op).into()
}
pub fn __expand_len_method(self, _scope: &Scope) -> NativeExpand<usize> {
todo!()
}
pub fn __expand_buffer_len_method(self, scope: &Scope) -> NativeExpand<usize> {
expand_buffer_length_native(scope, self.value(scope)).into()
}
pub fn __expand_rank_method(self, _scope: &Scope) -> NativeExpand<usize> {
todo!()
}
pub fn __expand_downcast_method<E: CubePrimitive>(
self,
scope: &Scope,
) -> NativeExpand<TensorMap<E, K>> {
if T::__expand_as_type(scope) != E::__expand_as_type(scope)
&& !is_tf32_cast::<E, T>(scope)
{
panic!("Downcast should only be used to satisfy the Rust type system.")
}
self.expand.into()
}
}
}