cubecl_core/frontend/
tensor_layout.rs1use 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#[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: 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}