Skip to main content

cubecl_core/frontend/
tensor_layout.rs

1use alloc::boxed::Box;
2
3use cubecl_ir::{ClampMode, Instruction, SemanticType, TensorIndexingOps};
4
5use crate::{self as cubecl, unexpanded};
6
7use crate::prelude::*;
8
9#[derive_cube_comptime]
10pub enum TensorClampMode {
11    Undefined,
12    Constant(u32),
13    ClampToEdge,
14    Repeat,
15    RepeatMirrored,
16}
17
18impl From<TensorClampMode> for ClampMode {
19    fn from(value: TensorClampMode) -> Self {
20        match value {
21            TensorClampMode::Undefined => ClampMode::Undefined,
22            TensorClampMode::Constant(val) => ClampMode::Constant(val),
23            TensorClampMode::ClampToEdge => ClampMode::ClampToEdge,
24            TensorClampMode::Repeat => ClampMode::Repeat,
25            TensorClampMode::RepeatMirrored => ClampMode::RepeatMirrored,
26        }
27    }
28}
29
30// OpTypeTensorLayoutNV with optional OpTypeTensorViewNV
31#[derive(CubeType, Clone)]
32pub struct TensorView<T: CubePrimitive> {
33    #[allow(unused)]
34    pub(crate) buffer: Box<[T]>,
35    #[allow(unused)]
36    pub(crate) layout: TensorLayout,
37    #[allow(unused)]
38    pub(crate) view: ComptimeOption<TensorReinterpret>,
39}
40
41#[derive_cube_comptime]
42pub struct TensorLayout;
43
44#[derive_cube_comptime]
45pub struct TensorReinterpret;
46
47impl CubeType for TensorLayout {
48    type ExpandType = NativeExpand<TensorLayout>;
49}
50
51impl CubeDebug for TensorLayout {}
52impl CubePrimitive for TensorLayout {
53    type Scalar = u32;
54    type Size = Const<1>;
55    type WithScalar<S: Scalar> = S;
56
57    fn from_const_value(_: cubecl_ir::ConstantValue) -> Self {
58        panic!("Can't construct tensor layout from constant")
59    }
60}
61
62impl NativeAssign for TensorLayout {}
63
64impl CubeType for TensorReinterpret {
65    type ExpandType = NativeExpand<TensorReinterpret>;
66}
67
68impl CubeDebug for TensorReinterpret {}
69impl CubePrimitive for TensorReinterpret {
70    type Scalar = u32;
71    type Size = Const<1>;
72    type WithScalar<S: Scalar> = S;
73
74    fn from_const_value(_: cubecl_ir::ConstantValue) -> Self {
75        panic!("Can't construct tensor layout from constant")
76    }
77}
78
79impl NativeAssign for TensorReinterpret {}
80
81#[derive(CubeType, CubeLaunch)]
82pub struct TensorViewBuilder<T: CubePrimitive> {
83    #[allow(unused)]
84    buffer: Box<[T]>,
85    #[allow(unused)]
86    shape: Sequence<u32>,
87    /// Strides default to contiguous strides
88    strides: ComptimeOption<Sequence<u32>>,
89    #[cube(comptime)]
90    clamp_mode: TensorClampMode,
91}
92
93#[cube]
94impl<T: CubePrimitive> TensorView<T> {
95    #[allow(clippy::new_ret_no_self)]
96    pub fn new(buffer: &[T], shape: Sequence<u32>) -> TensorViewBuilder<T> {
97        TensorViewBuilder::<T> {
98            buffer: unsafe { buffer.as_boxed_unchecked() },
99            shape,
100            strides: ComptimeOption::new_None(),
101            clamp_mode: comptime![TensorClampMode::Constant(0)],
102        }
103    }
104
105    #[allow(unused)]
106    pub fn slice(&self, offsets: Sequence<u32>, shape: Sequence<u32>) -> TensorView<T> {
107        intrinsic!(|scope| {
108            assert_eq!(
109                offsets.len(),
110                self.layout.rank(),
111                "Offsets and view rank must match"
112            );
113            assert_eq!(
114                offsets.len(),
115                shape.len(),
116                "Offsets and shape must have same rank"
117            );
118            let new_layout = scope.create_value(self.layout.expand.ty);
119            scope.register(Instruction::new(
120                TensorIndexingOps::Slice {
121                    layout: self.layout.expand,
122                    offsets: offsets.iter_cloned().map(|it| it.expand).collect(),
123                    shape: shape.iter_cloned().map(|it| it.expand).collect(),
124                },
125                new_layout,
126            ));
127            TensorViewExpand {
128                buffer: self.buffer.clone(),
129                layout: new_layout.into(),
130                view: self.view.clone(),
131            }
132        })
133    }
134}
135
136impl NativeExpand<TensorLayout> {
137    fn rank(&self) -> usize {
138        if let Type::Semantic(SemanticType::TensorLayout(rank, _)) = &self.expand.ty {
139            *rank
140        } else {
141            unreachable!()
142        }
143    }
144}
145
146impl<T: CubePrimitive> TensorView<T> {
147    pub fn permuted(&self, _permutation: Sequence<usize>) -> TensorView<T> {
148        unexpanded!()
149    }
150}
151
152impl<T: CubePrimitive> TensorViewExpand<T> {
153    pub fn __expand_permuted_method(
154        self,
155        scope: &Scope,
156        permutation: SequenceExpand<usize>,
157    ) -> TensorViewExpand<T> {
158        let dims = permutation.len();
159        assert!(dims <= 5, "Max 5 dims allowed");
160        let permutation = permutation
161            .iter_cloned()
162            .map(|it| {
163                it.constant()
164                    .expect("permutation must be constant")
165                    .as_u32()
166            })
167            .collect::<alloc::vec::Vec<_>>();
168        let mut perm_dims = [0; 5];
169        perm_dims[..dims].copy_from_slice(&permutation);
170        let view = scope.create_value(Type::semantic(SemanticType::TensorView(
171            dims, false, perm_dims,
172        )));
173        scope.register(Instruction::new(TensorIndexingOps::CreateView, view));
174        TensorViewExpand {
175            buffer: self.buffer,
176            layout: self.layout,
177            view: ComptimeOptionExpand::Some(view.into()),
178        }
179    }
180}
181
182impl<T: CubePrimitive> TensorViewBuilder<T> {
183    pub fn with_strides(mut self, strides: Sequence<u32>) -> Self {
184        self.strides = ComptimeOption::Some(strides);
185        self
186    }
187
188    pub fn with_clamp_mode(mut self, clamp_mode: TensorClampMode) -> Self {
189        self.clamp_mode = clamp_mode;
190        self
191    }
192
193    pub fn finish(self) -> TensorView<T> {
194        unexpanded!()
195    }
196}
197
198impl<T: CubePrimitive> TensorViewBuilderExpand<T> {
199    pub fn __expand_with_strides_method(
200        mut self,
201        _scope: &Scope,
202        strides: SequenceExpand<u32>,
203    ) -> Self {
204        self.strides = ComptimeOptionExpand::Some(strides);
205        self
206    }
207
208    pub fn __expand_with_clamp_mode_method(
209        mut self,
210        _scope: &Scope,
211        clamp_mode: TensorClampMode,
212    ) -> Self {
213        self.clamp_mode = clamp_mode;
214        self
215    }
216
217    pub fn __expand_finish_method(self, scope: &Scope) -> TensorViewExpand<T> {
218        let layout = scope.create_value(Type::semantic(SemanticType::TensorLayout(
219            self.shape.len(),
220            self.clamp_mode.into(),
221        )));
222        scope.register(Instruction::new(
223            TensorIndexingOps::CreateLayout {
224                shape: self.shape.iter_cloned().map(|it| it.expand).collect(),
225                strides: match self.strides {
226                    ComptimeOptionExpand::None => None,
227                    ComptimeOptionExpand::Some(strides) => {
228                        Some(strides.iter_cloned().map(|it| it.expand).collect())
229                    }
230                },
231                clamp_mode: self.clamp_mode.into(),
232            },
233            layout,
234        ));
235        TensorViewExpand {
236            buffer: self.buffer,
237            layout: layout.into(),
238            view: ComptimeOptionExpand::None,
239        }
240    }
241}
242
243impl<T: CubePrimitive> LaunchArg for TensorView<T> {
244    type RuntimeArg<R: Runtime> = TensorViewBuilderLaunch<T, R>;
245    type CompilationArg = TensorViewBuilderCompilationArg<T>;
246
247    fn register<R: Runtime>(
248        arg: Self::RuntimeArg<R>,
249        launcher: &mut KernelLauncher<R>,
250    ) -> Self::CompilationArg {
251        TensorViewBuilder::<T>::register(arg, launcher)
252    }
253
254    fn expand(
255        arg: &Self::CompilationArg,
256        builder: &mut KernelBuilder,
257    ) -> <Self as CubeType>::ExpandType {
258        let build = TensorViewBuilder::<T>::expand(arg, builder);
259        build.__expand_finish_method(&builder.scope)
260    }
261}