cubecl_core/frontend/container/tensor/
launch.rs1use core::marker::PhantomData;
2
3use cubecl_ir::AddressType;
4use cubecl_runtime::{runtime::Runtime, server::CopyDescriptor};
5use cubecl_zspace::{Shape, Strides};
6
7use crate::{
8 self as cubecl,
9 compute::{KernelBuilder, KernelLauncher},
10 frontend::container::{buffer_len::expand_buffer_length_native, slice},
11 prelude::*,
12};
13
14use super::Tensor;
15
16#[derive(CubeType, CubeLaunch, Clone, Copy)]
17#[expand(derive(Clone, Copy))]
18pub struct TensorMeta {
19 pub len: usize,
20 pub rank: usize,
21}
22
23#[derive(Debug)]
25pub enum TensorArg<R: Runtime> {
26 Handle {
28 handle: TensorBinding<R>,
30 },
31 Alias {
33 input_pos: usize,
35 strides: Strides,
36 shape: Shape,
37 },
38}
39
40pub struct TensorBinding<R: Runtime> {
43 pub handle: cubecl_runtime::server::BufferBinding,
44 pub strides: Strides,
45 pub shape: Shape,
46 pub runtime: PhantomData<R>,
47}
48
49impl<R: Runtime> Clone for TensorBinding<R> {
50 fn clone(&self) -> Self {
51 Self {
52 handle: self.handle.clone(),
53 strides: self.strides.clone(),
54 shape: self.shape.clone(),
55 runtime: PhantomData,
56 }
57 }
58}
59
60impl<R: Runtime> TensorBinding<R> {
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
71impl<R: Runtime> core::fmt::Debug for TensorBinding<R> {
72 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73 writeln!(
74 f,
75 "TensorHandleRef {{ strides: {:?}, shape: {:?} }}",
76 self.strides, self.shape
77 )
78 }
79}
80
81#[derive(Clone, PartialEq, Eq, Hash, Debug)]
83pub struct TensorCompilationArg {
84 pub meta: TensorMetaCompilationArg,
85 pub buffer: BufferCompilationArg,
86}
87
88impl<C: CubePrimitive> LaunchArg for Tensor<C> {
89 type RuntimeArg<R: Runtime> = TensorArg<R>;
90 type CompilationArg = TensorCompilationArg;
91
92 fn register<R: Runtime>(
93 arg: Self::RuntimeArg<R>,
94 launcher: &mut KernelLauncher<R>,
95 ) -> Self::CompilationArg {
96 let elem_size = launcher.with_scope(|scope| C::__expand_size(scope));
97 let vector_size = launcher.with_scope(|scope| C::__expand_vector_size(scope));
98 let len = arg.size() / vector_size;
99 let meta_arg = TensorMetaLaunch::new(len, arg.shape().len());
100 let buffer = match &arg {
101 TensorArg::Handle { .. } => BufferCompilationArg { inplace: None },
102 TensorArg::Alias { input_pos, .. } => BufferCompilationArg {
103 inplace: Some(*input_pos),
104 },
105 };
106 launcher.register_tensor(arg, elem_size);
107 let meta = TensorMeta::register(meta_arg, launcher);
108 TensorCompilationArg { meta, buffer }
109 }
110
111 fn expand(arg: &Self::CompilationArg, builder: &mut KernelBuilder) -> TensorExpand<C> {
112 let buffer = match arg.buffer.inplace {
113 Some(id) => builder.inplace(id),
114 None => builder.tensor(C::__expand_as_type(&builder.scope)),
115 };
116 let meta = TensorMeta::expand(&arg.meta, builder);
117 let scope = &builder.scope;
118 let len = expand_buffer_length_native(scope, buffer);
119 let buffer =
120 slice::from_raw_parts::<C>(scope, buffer, 0usize.into_expand(scope), len.into());
121 TensorExpand { meta, buffer }
122 }
123}
124
125impl<C: CubePrimitive> LaunchArg for OwnedTensor<C> {
126 type RuntimeArg<R: Runtime> = TensorArg<R>;
127 type CompilationArg = TensorCompilationArg;
128
129 fn register<R: Runtime>(
130 arg: Self::RuntimeArg<R>,
131 launcher: &mut KernelLauncher<R>,
132 ) -> Self::CompilationArg {
133 Tensor::<C>::register(arg, launcher)
134 }
135
136 fn expand(arg: &Self::CompilationArg, builder: &mut KernelBuilder) -> OwnedTensorExpand<C> {
137 let tensor = Tensor::<C>::expand(arg, builder);
138 OwnedTensorExpand {
139 meta: tensor.meta,
140 buffer: tensor.buffer.expand.into(),
141 }
142 }
143}
144
145impl<R: Runtime> TensorArg<R> {
146 pub unsafe fn from_raw_parts(
153 handle: cubecl_runtime::server::Handle,
154 strides: Strides,
155 shape: Shape,
156 ) -> Self {
157 unsafe { Self::from_raw_parts_binding(handle.binding(), strides, shape) }
158 }
159
160 pub(crate) unsafe fn from_raw_parts_binding(
161 handle: cubecl_runtime::server::BufferBinding,
162 strides: Strides,
163 shape: Shape,
164 ) -> Self {
165 unsafe {
166 Self::Handle {
167 handle: TensorBinding::from_raw_parts_binding(handle, strides, shape),
168 }
169 }
170 }
171
172 pub fn into_alias(self, position: usize) -> Self {
174 match self {
175 TensorArg::Handle { handle } => handle.into_alias(position),
176 alias @ TensorArg::Alias { .. } => alias,
177 }
178 }
179
180 pub fn size(&self) -> usize {
181 match self {
182 TensorArg::Handle { handle } => handle.size(),
183 TensorArg::Alias { shape, .. } => shape.iter().product(),
184 }
185 }
186
187 pub fn shape(&self) -> &[usize] {
188 match self {
189 TensorArg::Handle { handle } => &handle.shape,
190 TensorArg::Alias { shape, .. } => shape,
191 }
192 }
193
194 pub fn strides(&self) -> &[usize] {
195 match self {
196 TensorArg::Handle { handle } => &handle.strides,
197 TensorArg::Alias { strides, .. } => strides,
198 }
199 }
200}
201
202impl<R: Runtime> TensorArg<R> {
203 pub fn into_buffer_arg(self) -> BufferArg<R> {
204 match self {
205 TensorArg::Handle { handle } => {
206 let handle = unsafe {
207 let size = handle.size();
208 BufferBinding::from_raw_parts_binding(handle.handle, size)
209 };
210 BufferArg::Handle { handle }
211 }
212 TensorArg::Alias {
213 input_pos, shape, ..
214 } => BufferArg::Alias {
215 input_pos,
216 length: [shape.iter().product()],
217 },
218 }
219 }
220}
221
222impl<R: Runtime> TensorBinding<R> {
223 pub fn into_tensor_arg(self) -> TensorArg<R> {
225 TensorArg::Handle { handle: self }
226 }
227 pub fn into_alias(self, index: usize) -> TensorArg<R> {
229 TensorArg::Alias {
230 input_pos: index,
231 strides: self.strides,
232 shape: self.shape,
233 }
234 }
235 pub fn as_alias(&self, index: usize) -> TensorArg<R> {
237 TensorArg::Alias {
238 input_pos: index,
239 strides: self.strides.clone(),
240 shape: self.shape.clone(),
241 }
242 }
243 pub fn into_buffer_arg(self) -> BufferArg<R> {
245 unsafe { BufferArg::from_raw_parts_binding(self.handle, self.shape.iter().product()) }
246 }
247
248 pub unsafe fn from_raw_parts(
255 handle: cubecl_runtime::server::Handle,
256 strides: Strides,
257 shape: Shape,
258 ) -> Self {
259 unsafe { Self::from_raw_parts_binding(handle.binding(), strides, shape) }
260 }
261
262 pub unsafe fn from_raw_parts_binding(
269 handle: cubecl_runtime::server::BufferBinding,
270 strides: Strides,
271 shape: Shape,
272 ) -> Self {
273 Self {
274 handle,
275 strides,
276 shape,
277 runtime: PhantomData,
278 }
279 }
280
281 pub fn into_copy_descriptor(self, elem_size: usize) -> CopyDescriptor {
282 CopyDescriptor {
283 handle: self.handle,
284 shape: self.shape,
285 strides: self.strides,
286 elem_size,
287 }
288 }
289}