cubecl_core/frontend/container/tensor/
launch.rs1use cubecl_ir::AddressType;
2use cubecl_runtime::server::CopyDescriptor;
3use cubecl_zspace::{MetadataError, Shape, Strides, Tiling};
4
5use crate::{
6 self as cubecl,
7 compute::{KernelBuilder, KernelLauncher},
8 frontend::container::{buffer_len::expand_buffer_length_native, slice},
9 prelude::*,
10};
11
12use super::Tensor;
13
14#[derive(CubeType, CubeLaunch, Clone, Copy)]
15#[expand(derive(Clone, Copy))]
16pub struct TensorMeta {
17 pub len: usize,
18 pub rank: usize,
19}
20
21#[derive(Debug)]
23pub enum TensorArg {
24 Handle {
26 handle: TensorBinding,
28 },
29 Alias {
31 input_pos: usize,
33 strides: Strides,
34 shape: Shape,
35 },
36}
37
38pub struct TensorBinding {
41 pub handle: cubecl_runtime::server::BufferBinding,
42 pub strides: Strides,
43 pub shape: Shape,
44 pub tiling: Tiling,
47}
48
49impl Clone for TensorBinding {
50 fn clone(&self) -> Self {
51 Self {
52 handle: self.handle.clone(),
53 strides: self.strides.clone(),
54 shape: self.shape.clone(),
55 tiling: self.tiling,
56 }
57 }
58}
59
60impl TensorBinding {
61 pub fn size(&self) -> usize {
62 self.shape.iter().product()
63 }
64
65 pub fn required_address_type(&self, elem_size: usize) -> AddressType {
67 AddressType::from_len(self.handle.size() as usize / elem_size)
68 }
69
70 pub fn with_tiling(mut self, tiling: Tiling) -> Result<Self, MetadataError> {
76 tiling.logical_rank(self.shape.rank())?;
77 self.tiling = tiling;
78 Ok(self)
79 }
80
81 fn assert_untiled(&self, op: &str) {
85 assert!(
86 !self.tiling.is_tiled(),
87 "TensorBinding::{op} on a storage-tiled binding is not supported: {:?}",
88 self.tiling
89 );
90 }
91}
92
93impl core::fmt::Debug for TensorBinding {
94 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95 writeln!(
96 f,
97 "TensorHandleRef {{ strides: {:?}, shape: {:?}, tiling: {:?} }}",
98 self.strides, self.shape, self.tiling
99 )
100 }
101}
102
103#[derive(Clone, PartialEq, Eq, Hash, Debug)]
105pub struct TensorCompilationArg {
106 pub meta: TensorMetaCompilationArg,
107 pub buffer: BufferCompilationArg,
108}
109
110impl<C: CubePrimitive> LaunchArg for Tensor<C> {
111 type RuntimeArg = TensorArg;
112 type CompilationArg = TensorCompilationArg;
113
114 fn register(arg: Self::RuntimeArg, launcher: &mut KernelLauncher) -> Self::CompilationArg {
115 let elem_size = launcher.with_scope(|scope| C::__expand_size(scope));
116 let vector_size = launcher.with_scope(|scope| C::__expand_vector_size(scope));
117 let len = arg.size() / vector_size;
118 let meta_arg = TensorMetaLaunch::new(len, arg.shape().len());
119 let buffer = match &arg {
120 TensorArg::Handle { .. } => BufferCompilationArg { inplace: None },
121 TensorArg::Alias { input_pos, .. } => BufferCompilationArg {
122 inplace: Some(*input_pos),
123 },
124 };
125 launcher.register_tensor(arg, elem_size);
126 let meta = TensorMeta::register(meta_arg, launcher);
127 TensorCompilationArg { meta, buffer }
128 }
129
130 fn expand(arg: &Self::CompilationArg, builder: &mut KernelBuilder) -> TensorExpand<C> {
131 let buffer = match arg.buffer.inplace {
132 Some(id) => builder.inplace(id),
133 None => builder.tensor(C::__expand_as_type(&builder.scope)),
134 };
135 let meta = TensorMeta::expand(&arg.meta, builder);
136 let scope = &builder.scope;
137 let len = expand_buffer_length_native(scope, buffer);
138 let buffer =
139 slice::from_raw_parts::<C>(scope, buffer, 0usize.into_expand(scope), len.into());
140 TensorExpand { meta, buffer }
141 }
142}
143
144impl<C: CubePrimitive> LaunchArg for OwnedTensor<C> {
145 type RuntimeArg = TensorArg;
146 type CompilationArg = TensorCompilationArg;
147
148 fn register(arg: Self::RuntimeArg, launcher: &mut KernelLauncher) -> Self::CompilationArg {
149 Tensor::<C>::register(arg, launcher)
150 }
151
152 fn expand(arg: &Self::CompilationArg, builder: &mut KernelBuilder) -> OwnedTensorExpand<C> {
153 let tensor = Tensor::<C>::expand(arg, builder);
154 OwnedTensorExpand {
155 meta: tensor.meta,
156 buffer: tensor.buffer.expand.into(),
157 }
158 }
159}
160
161impl TensorArg {
162 pub unsafe fn from_raw_parts(
169 handle: cubecl_runtime::server::Handle,
170 strides: Strides,
171 shape: Shape,
172 ) -> Self {
173 unsafe { Self::from_raw_parts_binding(handle.binding(), strides, shape) }
174 }
175
176 pub(crate) unsafe fn from_raw_parts_binding(
177 handle: cubecl_runtime::server::BufferBinding,
178 strides: Strides,
179 shape: Shape,
180 ) -> Self {
181 unsafe {
182 Self::Handle {
183 handle: TensorBinding::from_raw_parts_binding(handle, strides, shape),
184 }
185 }
186 }
187
188 pub fn into_alias(self, position: usize) -> Self {
190 match self {
191 TensorArg::Handle { handle } => handle.into_alias(position),
192 alias @ TensorArg::Alias { .. } => alias,
193 }
194 }
195
196 pub fn size(&self) -> usize {
197 match self {
198 TensorArg::Handle { handle } => handle.size(),
199 TensorArg::Alias { shape, .. } => shape.iter().product(),
200 }
201 }
202
203 pub fn shape(&self) -> &[usize] {
204 match self {
205 TensorArg::Handle { handle } => &handle.shape,
206 TensorArg::Alias { shape, .. } => shape,
207 }
208 }
209
210 pub fn strides(&self) -> &[usize] {
211 match self {
212 TensorArg::Handle { handle } => &handle.strides,
213 TensorArg::Alias { strides, .. } => strides,
214 }
215 }
216}
217
218impl TensorArg {
219 pub fn into_buffer_arg(self) -> BufferArg {
220 match self {
221 TensorArg::Handle { handle } => {
222 let handle = unsafe {
223 let size = handle.size();
224 BufferBinding::from_raw_parts_binding(handle.handle, size)
225 };
226 BufferArg::Handle { handle }
227 }
228 TensorArg::Alias {
229 input_pos, shape, ..
230 } => BufferArg::Alias {
231 input_pos,
232 length: [shape.iter().product()],
233 },
234 }
235 }
236}
237
238impl TensorBinding {
239 pub fn into_tensor_arg(self) -> TensorArg {
241 TensorArg::Handle { handle: self }
242 }
243 pub fn into_alias(self, index: usize) -> TensorArg {
245 self.assert_untiled("into_alias");
246 TensorArg::Alias {
247 input_pos: index,
248 strides: self.strides,
249 shape: self.shape,
250 }
251 }
252 pub fn as_alias(&self, index: usize) -> TensorArg {
254 self.assert_untiled("as_alias");
255 TensorArg::Alias {
256 input_pos: index,
257 strides: self.strides.clone(),
258 shape: self.shape.clone(),
259 }
260 }
261 pub fn into_buffer_arg(self) -> BufferArg {
263 unsafe { BufferArg::from_raw_parts_binding(self.handle, self.shape.iter().product()) }
264 }
265
266 pub unsafe fn from_raw_parts(
273 handle: cubecl_runtime::server::Handle,
274 strides: Strides,
275 shape: Shape,
276 ) -> Self {
277 unsafe { Self::from_raw_parts_binding(handle.binding(), strides, shape) }
278 }
279
280 pub unsafe fn from_raw_parts_binding(
287 handle: cubecl_runtime::server::BufferBinding,
288 strides: Strides,
289 shape: Shape,
290 ) -> Self {
291 Self {
292 handle,
293 strides,
294 shape,
295 tiling: Tiling::UNTILED,
296 }
297 }
298
299 pub fn into_copy_descriptor(self, elem_size: usize) -> CopyDescriptor {
300 CopyDescriptor {
301 handle: self.handle,
302 shape: self.shape,
303 strides: self.strides,
304 elem_size,
305 }
306 }
307}