Skip to main content

cubecl_core/frontend/container/array/
base.rs

1use core::ops::{Deref, DerefMut};
2
3use cubecl_ir::{
4    Scope, VectorSize,
5    interfaces::MaybeVectorizedType,
6    pliron::{
7        r#type::{Typed, TypedHandle},
8        value::Value,
9    },
10    read_value,
11    types::{ArrayType, PointerType, aggregate::SliceType},
12};
13
14use crate::frontend::{CubePrimitive, NativeExpand};
15use crate::prelude::*;
16use crate::{self as cubecl};
17use crate::{frontend::CubeType, unexpanded};
18use cubecl_macros::{cube, intrinsic};
19
20/// A contiguous array of elements.
21#[derive(Clone, Copy)]
22pub struct Array<E> {
23    _buffer: [E; 1],
24}
25
26type ArrayExpand<E> = NativeExpand<Array<E>>;
27
28impl<E> AsMutExpand for ArrayExpand<E> {
29    fn __expand_ref_mut_method(&mut self, _: &Scope) -> &mut Self {
30        self
31    }
32}
33
34/// Module that contains the implementation details of the new function.
35mod new {
36    use cubecl_ir::{attributes::ZeroAttr, types::ArrayType};
37    use cubecl_macros::intrinsic;
38
39    use super::*;
40    use crate::frontend::container::slice;
41
42    #[cube]
43    impl<T: CubePrimitive + Clone> Array<T> {
44        /// Create a new array of the given length.
45        pub fn new(#[comptime] length: usize) -> Self {
46            intrinsic!(|scope| {
47                // Allocate as a slice even though it's statically sized, so we can deref to it.
48                // Unlike Rust, we can't construct fat pointers ad-hoc without access to the scope,
49                // so it needs to be prepared in advance.
50                let elem = T::__expand_as_type(scope);
51                let ty = ArrayType::get(scope.ctx(), elem, length);
52                let null = ZeroAttr::new(ty);
53                let buffer = scope.create_local_mut(ty, Some(null.into()));
54                let slice = slice::from_raw_parts::<T>(
55                    scope,
56                    buffer,
57                    0usize.into_expand(scope),
58                    length.into_expand(scope),
59                );
60                slice.expand.into()
61            })
62        }
63    }
64}
65
66/// Module that contains the implementation details of the `vector_size` function.
67mod vector {
68    use cubecl_ir::{interfaces::TypedExt, read_value};
69
70    use super::*;
71
72    impl<P: CubePrimitive> Array<P> {
73        /// Get the size of each vector contained in the tensor.
74        ///
75        /// Same as the following:
76        ///
77        /// ```rust, ignore
78        /// let size = tensor[0].vector_size();
79        /// ```
80        pub fn vector_size(&self) -> VectorSize {
81            P::vector_size()
82        }
83
84        // Expand function of [size](Tensor::vector_size).
85        pub fn __expand_vector_size(
86            expand: <Self as CubeType>::ExpandType,
87            scope: &Scope,
88        ) -> VectorSize {
89            expand.__expand_vector_size_method(scope)
90        }
91    }
92
93    #[cube]
94    impl<P: CubePrimitive> Array<P> {
95        pub fn into_vector<N: Size>(self) -> Vector<P::Scalar, N> {
96            intrinsic!(|scope| {
97                let arr = read_value(scope, self.__extract_list(scope));
98                let vec_ty = Vector::<P::Scalar, N>::__expand_as_type(scope);
99                reinterpret_value(scope, arr, vec_ty).into()
100            })
101        }
102
103        pub fn from_vector<S: Scalar, N: Size>(vector: Vector<S, N>) -> Array<P> {
104            intrinsic!(|scope| {
105                let vec = vector.read_value(scope);
106                let vec_p = P::__expand_vector_size(scope);
107                let len = vec.vector_size(scope.ctx()) / vec_p;
108                let arr_ty =
109                    ArrayType::get(scope.ctx(), P::__expand_as_type(scope), len).to_handle();
110                reinterpret_value(scope, vec, arr_ty).into()
111            })
112        }
113    }
114}
115
116#[cube]
117impl<E: CubePrimitive> Array<E> {
118    /// Obtain the array length
119    #[allow(clippy::len_without_is_empty)]
120    pub fn len(&self) -> comptime_type!(usize) {
121        intrinsic!(|scope| {
122            let ty = inner_array_ty(scope, self.value(scope));
123            ty.deref(scope.ctx()).length
124        })
125    }
126}
127
128impl<C: CubePrimitive> Assign for ArrayExpand<C> {
129    fn __expand_assign_method(&mut self, scope: &Scope, value: Self) {
130        let value = value.__extract_list(scope);
131        let arr = self.__extract_list(scope);
132        assign::expand_element(scope, value.into(), arr.into());
133    }
134}
135
136impl<C: CubePrimitive> RuntimeAssign for ArrayExpand<C> {
137    fn init_mut(&self, scope: &Scope) -> Self::Expand {
138        let ty = inner_array_ty(scope, self.value(scope));
139        let length = ty.deref(scope.ctx()).length;
140        Array::__expand_new(scope, length)
141    }
142}
143
144impl<C: CubeType> CubeType for Array<C> {
145    type ExpandType = NativeExpand<Array<C>>;
146}
147
148impl<T: CubePrimitive> ReadValue for NativeExpand<Array<T>> {
149    fn read_value(&self, scope: &Scope) -> Value {
150        read_value(scope, self.__extract_list(scope))
151    }
152}
153
154impl<C: CubeType> IntoMut for ArrayExpand<C> {
155    fn into_mut(self, _scope: &Scope) -> Self {
156        self
157    }
158}
159
160impl<T: CubePrimitive> SizedContainer<usize> for Array<T> {
161    fn len(&self) -> usize {
162        unexpanded!()
163    }
164}
165
166impl<T: CubePrimitive> SizedContainerExpand<usize> for ArrayExpand<T> {
167    fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
168        self.__expand_len_method(scope).into_expand(scope)
169    }
170}
171
172impl<T: CubeType> Iterator for Array<T> {
173    type Item = T;
174
175    fn next(&mut self) -> Option<Self::Item> {
176        unexpanded!()
177    }
178}
179
180impl<T: CubePrimitive> Deref for Array<T> {
181    type Target = [T];
182
183    fn deref(&self) -> &Self::Target {
184        unexpanded!()
185    }
186}
187
188impl<T: CubePrimitive> DerefMut for Array<T> {
189    fn deref_mut(&mut self) -> &mut Self::Target {
190        unexpanded!()
191    }
192}
193
194impl<T: CubePrimitive> Deref for ArrayExpand<T> {
195    type Target = SliceExpand<T>;
196
197    fn deref(&self) -> &Self::Target {
198        unsafe { self.as_type_ref_unchecked() }
199    }
200}
201
202impl<T: CubePrimitive> DerefMut for ArrayExpand<T> {
203    fn deref_mut(&mut self) -> &mut Self::Target {
204        unsafe { self.as_type_mut_unchecked() }
205    }
206}
207
208impl<T: CubePrimitive> List<T> for Array<T> {}
209impl<T: CubePrimitive> ListExpand<T> for ArrayExpand<T> {
210    fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
211        Array::<T>::__expand_len(scope, self).into_expand(scope)
212    }
213}
214
215impl<T: CubePrimitive> Vectorized for Array<T> {}
216impl<T: CubePrimitive> VectorizedExpand for ArrayExpand<T> {
217    fn __expand_vector_size_method(&self, scope: &Scope) -> VectorSize {
218        let ty = inner_array_ty(scope, self.value(scope));
219        ty.deref(scope.ctx()).vector_size(scope.ctx())
220    }
221}
222
223pub(crate) fn inner_array_ty(scope: &Scope, value: Value) -> TypedHandle<ArrayType> {
224    let ctx = scope.ctx();
225    let ty = value.get_type(ctx).deref(ctx);
226    let SliceType { base_ty, .. } = *ty.downcast_ref().unwrap();
227    let base_ty = base_ty.deref(ctx);
228    let PointerType { inner, .. } = base_ty.downcast_ref().unwrap();
229    TypedHandle::from_handle(*inner, ctx).unwrap()
230}