Skip to main content

cubecl_core/frontend/container/slice/
base.rs

1use alloc::vec;
2use core::ops::{Deref, DerefMut};
3use pliron::{builtin::ops::FuncOp, r#type::TypeHandle, value::DefiningEntity};
4
5use alloc::boxed::Box;
6
7use crate::{
8    self as cubecl,
9    frontend::container::iter::{SizedContainer, SizedContainerExpand},
10    unexpanded,
11};
12use cubecl::prelude::*;
13use cubecl_ir::{
14    OpInserter, SliceMetadata, VectorSize,
15    attributes::{ATTR_BUFFER_BINDING, BufferBindingAttr, FuncInterface},
16    dialect::{
17        OperationPtrExt, branch::RangeLoopOp, general::ReinterpretCastOp,
18        vector::CompositeConstructOp,
19    },
20    interfaces::{TypedExt, aliasing::PointerExt},
21    pliron::{context::Context, printable::Printable, r#type::Typed, value::Value},
22    types::{
23        ArrayType, AtomicType, PointerType, RuntimeArrayType, VectorType, aggregate::SliceType,
24    },
25};
26
27pub type SliceExpand<T> = NativeExpand<[T]>;
28
29#[derive(Clone, Copy)]
30pub struct ReadOnly;
31#[derive(Clone, Copy)]
32pub struct ReadWrite;
33
34pub trait SliceVisibility: Clone + Copy + Send + Sync + 'static {}
35
36impl SliceVisibility for ReadOnly {}
37
38impl SliceVisibility for ReadWrite {}
39
40impl<E: CubePrimitive> SliceExpand<E> {
41    pub fn __extract_list(&self, scope: &Scope) -> Value {
42        scope.extract_field(self.value(scope), SliceMetadata::LIST)
43    }
44
45    pub fn __extract_offset(&self, scope: &Scope) -> NativeExpand<usize> {
46        let field = scope.extract_field(self.value(scope), SliceMetadata::OFFSET);
47        field.into()
48    }
49
50    pub fn __extract_length(&self, scope: &Scope) -> NativeExpand<usize> {
51        let field = scope.extract_field(self.value(scope), SliceMetadata::LENGTH);
52        field.into()
53    }
54}
55
56pub(crate) fn buffer_idx(scope: &Scope, list: Value) -> usize {
57    buffer_binding(scope, list).buffer_pos
58}
59
60pub(crate) fn ext_meta_idx(scope: &Scope, list: Value) -> usize {
61    buffer_binding(scope, list)
62        .ext_meta_pos
63        .expect("Should have ext meta")
64}
65
66fn buffer_binding(scope: &Scope, list: Value) -> BufferBindingAttr {
67    let ctx = scope.ctx();
68    let (entry_block, idx) = match list.defining_entity() {
69        // Op is only allowed as a source for pointers (i.e. slice), so chase the pointer to its root
70        DefiningEntity::Op(_) => {
71            let block = list
72                .get_root_defining_block(ctx)
73                .expect("Should be block arg");
74            let idx = list.find_root_index(ctx);
75            (block, idx)
76        }
77        DefiningEntity::Block(block) => (block, list.find_index(ctx)),
78    };
79    let func = entry_block.deref(ctx).get_parent_op(ctx).unwrap();
80    let func = func.as_op::<FuncOp>(ctx).expect("Should be function");
81    *func
82        .get_arg_attr::<BufferBindingAttr>(scope.ctx(), idx, &ATTR_BUFFER_BINDING)
83        .expect("Should be buffer binding")
84}
85
86pub trait SliceVectorExt<E: Scalar, N: Size> {
87    fn with_vector_size<N2: Size>(&self) -> &[Vector<E, N2>] {
88        unexpanded!()
89    }
90    fn with_vector_size_mut<N2: Size>(&mut self) -> &mut [Vector<E, N2>] {
91        unexpanded!()
92    }
93    fn __expand_with_vector_size<'infer, N2: Size>(
94        scope: &Scope,
95        this: &'infer SliceExpand<Vector<E, N>>,
96    ) -> &'infer SliceExpand<Vector<E, N2>> {
97        this.__expand_with_vector_size_method(scope)
98    }
99    fn __expand_with_vector_size_mut<'infer, N2: Size>(
100        scope: &Scope,
101        this: &'infer mut SliceExpand<Vector<E, N>>,
102    ) -> &'infer mut SliceExpand<Vector<E, N2>> {
103        this.__expand_with_vector_size_mut_method(scope)
104    }
105}
106
107impl<E: Scalar, N: Size> SliceVectorExt<E, N> for [Vector<E, N>] {}
108impl<E: Scalar, N: Size> SliceExpand<Vector<E, N>> {
109    pub fn __expand_with_vector_size_method<'infer, N2: Size>(
110        &'infer self,
111        scope: &Scope,
112    ) -> &'infer SliceExpand<Vector<E, N2>> {
113        let slice = self.with_vector_size_inner::<N2>(scope);
114        scope.create_kernel_ref(slice)
115    }
116
117    pub fn __expand_with_vector_size_mut_method<'infer, N2: Size>(
118        &'infer mut self,
119        scope: &Scope,
120    ) -> &'infer mut SliceExpand<Vector<E, N2>> {
121        let slice = self.with_vector_size_inner::<N2>(scope);
122        scope.create_kernel_ref(slice)
123    }
124}
125
126impl<E: Scalar, N: Size> SliceExpand<Vector<E, N>> {
127    fn with_vector_size_inner<N2: Size>(&self, scope: &Scope) -> SliceExpand<Vector<E, N2>> {
128        let vector_size = N2::__expand_value(scope);
129        let list = self.__extract_list(scope);
130
131        let length = self.__extract_length(scope);
132        let offset = self.__extract_offset(scope);
133
134        let current = list.vector_size(scope.ctx());
135
136        if vector_size == current {
137            return self.expand.into();
138        }
139
140        let new_ptr_ty = change_list_vectorization(scope.ctx_mut(), list, vector_size);
141        let reinterpret = ReinterpretCastOp::new(scope.ctx_mut(), new_ptr_ty, list);
142        let new_ptr = scope.register_with_result(&reinterpret);
143
144        if current < vector_size {
145            let ratio = vector_size / current;
146            let offset = offset.__expand_div_method(scope, ratio.into());
147            let length = length.__expand_div_method(scope, ratio.into());
148            from_raw_parts(scope, new_ptr, offset, length)
149        } else {
150            let ratio = current / vector_size;
151            let offset = offset.__expand_mul_method(scope, ratio.into());
152            let length = length.__expand_mul_method(scope, ratio.into());
153            from_raw_parts(scope, new_ptr, offset, length)
154        }
155    }
156}
157
158/// A slice of atomic scalars viewed as atomic vectors: what a vector atomic operation, such as an
159/// add of a whole vector at once, takes. The slice's offset and length must be multiples of the
160/// vector size.
161pub trait SliceAtomicVectorExt<E: Scalar> {
162    fn with_vector_size<N: Size>(&self) -> &[Atomic<Vector<E, N>>] {
163        unexpanded!()
164    }
165    fn __expand_with_vector_size<'infer, N: Size>(
166        scope: &Scope,
167        this: &'infer SliceExpand<Atomic<E>>,
168    ) -> &'infer SliceExpand<Atomic<Vector<E, N>>> {
169        this.__expand_with_vector_size_method(scope)
170    }
171}
172
173impl<E: Scalar> SliceAtomicVectorExt<E> for [Atomic<E>] {}
174
175impl<E: Scalar> SliceExpand<Atomic<E>> {
176    pub fn __expand_with_vector_size_method<'infer, N: Size>(
177        &'infer self,
178        scope: &Scope,
179    ) -> &'infer SliceExpand<Atomic<Vector<E, N>>> {
180        let vector_size = N::__expand_value(scope);
181        let list = self.__extract_list(scope);
182        let length = self.__extract_length(scope);
183        let offset = self.__extract_offset(scope);
184
185        let new_ptr_ty = change_list_vectorization(scope.ctx_mut(), list, vector_size);
186        let reinterpret = ReinterpretCastOp::new(scope.ctx_mut(), new_ptr_ty, list);
187        let new_ptr = scope.register_with_result(&reinterpret);
188        let offset = offset.__expand_div_method(scope, vector_size.into());
189        let length = length.__expand_div_method(scope, vector_size.into());
190        scope.create_kernel_ref(from_raw_parts(scope, new_ptr, offset, length))
191    }
192}
193
194// This is really annoying but does have a lot more checks for invariants than before
195fn change_list_vectorization(ctx: &Context, list: Value, new_vec: usize) -> TypeHandle {
196    let current_vec = list.vector_size(ctx);
197    let ty = list.get_type(ctx);
198    let PointerType {
199        inner,
200        address_space,
201    } = {
202        let ty = ty.deref(ctx);
203        *ty.downcast_ref().unwrap()
204    };
205    let (arr, runtime_arr) = {
206        let list_ty = inner.deref(ctx);
207        let arr = list_ty.downcast_ref::<ArrayType>().copied();
208        let runtime_arr = list_ty.downcast_ref::<RuntimeArrayType>().copied();
209        (arr, runtime_arr)
210    };
211    if let Some(ArrayType { inner, length }) = arr {
212        let new_length = length * current_vec / new_vec;
213        let new_vector_ty = revectorized(ctx, inner, new_vec);
214        let new_arr_ty = ArrayType::get(ctx, new_vector_ty, new_length).into();
215        let new_ptr_ty = PointerType::get(ctx, new_arr_ty, address_space);
216        return new_ptr_ty.into();
217    }
218    if let Some(RuntimeArrayType { inner }) = runtime_arr {
219        let new_vector_ty = revectorized(ctx, inner, new_vec);
220        let new_arr_ty = RuntimeArrayType::get(ctx, new_vector_ty).into();
221        let new_ptr_ty = PointerType::get(ctx, new_arr_ty, address_space);
222        return new_ptr_ty.into();
223    }
224    unreachable!("Should be static or dynamic array")
225}
226
227/// A list's element type at `new_vec` of its scalar, an atomic element staying atomic.
228fn revectorized(ctx: &Context, element: TypeHandle, new_vec: usize) -> TypeHandle {
229    let atomic = element.deref(ctx).downcast_ref::<AtomicType>().is_some();
230    let scalar_ty = element.scalar_ty(ctx);
231    let vector_ty = if new_vec > 1 {
232        VectorType::get(ctx, scalar_ty, new_vec).into()
233    } else {
234        scalar_ty
235    };
236    match atomic {
237        true => AtomicType::get(ctx, vector_ty).into(),
238        false => vector_ty,
239    }
240}
241
242pub trait SliceExt<E: CubePrimitive> {
243    /// Returns the same slice, but with the type reinterpreted as `Vector`.
244    /// Preserves existing vector size of the primitive.
245    fn as_vectorized(&self) -> &[Vector<E::Scalar, E::Size>] {
246        unexpanded!()
247    }
248
249    /// Returns the same slice, but with the type reinterpreted as `Vector`.
250    /// Preserves existing vector size of the primitive.
251    fn as_vectorized_mut(&mut self) -> &mut [Vector<E::Scalar, E::Size>] {
252        unexpanded!()
253    }
254
255    /// Downcast the slice to the given type and panic if the type isn't the same.
256    ///
257    /// This function should only be used to satisfy the Rust type system, when two generic
258    /// types are supposed to be the same.
259    fn downcast<T: CubePrimitive>(&self) -> &[T] {
260        unexpanded!()
261    }
262
263    /// Downcast the slice to the given type and panic if the type isn't the same.
264    ///
265    /// This function should only be used to satisfy the Rust type system, when two generic
266    /// types are supposed to be the same.
267    fn downcast_mut<T: CubePrimitive>(&mut self) -> &mut [T] {
268        unexpanded!()
269    }
270
271    /// Unsafely downcast the slice to the given type and panic if the type isn't the same.
272    ///
273    /// # Safety
274    /// This function converts unsafely, and should only be used for temporary storage with a dummy
275    /// type (i.e. `ReinterpretSlice`)
276    unsafe fn downcast_unchecked<T: CubePrimitive>(&self) -> &[T] {
277        unexpanded!()
278    }
279
280    /// Unsafely downcast the slice to the given type and panic if the type isn't the same.
281    ///
282    /// # Safety
283    /// This function converts unsafely, and should only be used for temporary storage with a dummy
284    /// type (i.e. `ReinterpretSlice`)
285    unsafe fn downcast_mut_unchecked<T: CubePrimitive>(&mut self) -> &mut [T] {
286        unexpanded!()
287    }
288
289    /// Unsafely cast an immutable slice to a mutable one.
290    ///
291    /// # Safety
292    /// This is safe in practice, but breaks semantics. Should only be used if absolutely necessary.
293    /// May cause problems if an immutable input is reinterpreted as mutable.
294    #[allow(clippy::mut_from_ref)]
295    unsafe fn as_mut_unchecked(&self) -> &mut [E] {
296        unexpanded!()
297    }
298
299    /// Convert the slice to a start pointer, without any bounds checks.
300    ///
301    /// # Safety
302    /// See [`get_unchecked`]([E]::get_unchecked)
303    unsafe fn as_ptr_unchecked(&self) -> *const E {
304        unexpanded!()
305    }
306
307    /// Convert the slice to a mutable start pointer, without any bounds checks.
308    ///
309    /// # Safety
310    /// See [`get_unchecked_mut`]([E]::get_unchecked_mut)
311    unsafe fn as_mut_ptr_unchecked(&mut self) -> *mut E {
312        unexpanded!()
313    }
314
315    /// Convert to an owned boxed slice. This is very unsafe as it completely erases the lifetime.
316    /// Only use it for global kernel inputs, which have a static lifetime.
317    ///
318    /// # Safety
319    /// Erases the lifetime. Only use when an owned representation is absolutely needed.
320    unsafe fn as_boxed_unchecked(&self) -> Box<[E]> {
321        unexpanded!()
322    }
323
324    fn __expand_as_vectorized<'infer>(
325        scope: &Scope,
326        this: &'infer SliceExpand<E>,
327    ) -> &'infer SliceExpand<Vector<E::Scalar, E::Size>>;
328
329    fn __expand_as_vectorized_mut<'infer>(
330        scope: &Scope,
331        this: &'infer mut SliceExpand<E>,
332    ) -> &'infer mut SliceExpand<Vector<E::Scalar, E::Size>>;
333
334    fn __expand_downcast<'infer, T: CubePrimitive>(
335        scope: &Scope,
336        this: &'infer SliceExpand<E>,
337    ) -> &'infer SliceExpand<T>;
338
339    fn __expand_downcast_mut<'infer, T: CubePrimitive>(
340        scope: &Scope,
341        this: &'infer mut SliceExpand<E>,
342    ) -> &'infer mut SliceExpand<T>;
343
344    fn __expand_downcast_unchecked<'infer, T: CubePrimitive>(
345        scope: &Scope,
346        this: &'infer SliceExpand<E>,
347    ) -> &'infer SliceExpand<T>;
348
349    fn __expand_downcast_mut_unchecked<'infer, T: CubePrimitive>(
350        scope: &Scope,
351        this: &'infer mut SliceExpand<E>,
352    ) -> &'infer mut SliceExpand<T>;
353
354    fn __expand_as_ptr(scope: &Scope, this: &SliceExpand<E>) -> *const NativeExpand<E>;
355
356    fn __expand_as_mut_ptr(scope: &Scope, this: &mut SliceExpand<E>) -> *mut NativeExpand<E>;
357
358    #[doc(hidden)]
359    unsafe fn __expand_as_ptr_unchecked(
360        scope: &Scope,
361        this: &SliceExpand<E>,
362    ) -> *const NativeExpand<E>;
363
364    #[doc(hidden)]
365    unsafe fn __expand_as_mut_ptr_unchecked(
366        scope: &Scope,
367        this: &mut SliceExpand<E>,
368    ) -> *mut NativeExpand<E>;
369
370    #[allow(clippy::mut_from_ref)]
371    #[doc(hidden)]
372    unsafe fn __expand_as_mut_unchecked<'infer>(
373        scope: &Scope,
374        this: &'infer SliceExpand<E>,
375    ) -> &'infer mut SliceExpand<E>;
376
377    #[doc(hidden)]
378    unsafe fn __expand_as_boxed_unchecked(
379        scope: &Scope,
380        this: &SliceExpand<E>,
381    ) -> NativeExpand<Box<[E]>>;
382}
383
384impl<E: CubePrimitive> SliceExt<E> for [E] {
385    fn __expand_as_vectorized<'infer>(
386        scope: &Scope,
387        this: &'infer SliceExpand<E>,
388    ) -> &'infer SliceExpand<Vector<E::Scalar, E::Size>> {
389        this.__expand_as_vectorized_method(scope)
390    }
391
392    fn __expand_as_vectorized_mut<'infer>(
393        scope: &Scope,
394        this: &'infer mut SliceExpand<E>,
395    ) -> &'infer mut SliceExpand<Vector<E::Scalar, E::Size>> {
396        this.__expand_as_vectorized_mut_method(scope)
397    }
398
399    fn __expand_downcast<'infer, T: CubePrimitive>(
400        scope: &Scope,
401        this: &'infer SliceExpand<E>,
402    ) -> &'infer SliceExpand<T> {
403        this.__expand_downcast_method::<T>(scope)
404    }
405
406    fn __expand_downcast_mut<'infer, T: CubePrimitive>(
407        scope: &Scope,
408        this: &'infer mut SliceExpand<E>,
409    ) -> &'infer mut SliceExpand<T> {
410        this.__expand_downcast_mut_method::<T>(scope)
411    }
412
413    fn __expand_downcast_unchecked<'infer, T: CubePrimitive>(
414        scope: &Scope,
415        this: &'infer SliceExpand<E>,
416    ) -> &'infer SliceExpand<T> {
417        this.__expand_downcast_unchecked_method::<T>(scope)
418    }
419
420    fn __expand_downcast_mut_unchecked<'infer, T: CubePrimitive>(
421        scope: &Scope,
422        this: &'infer mut SliceExpand<E>,
423    ) -> &'infer mut SliceExpand<T> {
424        this.__expand_downcast_mut_unchecked_method::<T>(scope)
425    }
426
427    fn __expand_as_ptr(scope: &Scope, this: &SliceExpand<E>) -> *const NativeExpand<E> {
428        this.__expand_as_ptr_method(scope)
429    }
430
431    fn __expand_as_mut_ptr(scope: &Scope, this: &mut SliceExpand<E>) -> *mut NativeExpand<E> {
432        this.__expand_as_mut_ptr_method(scope)
433    }
434
435    unsafe fn __expand_as_ptr_unchecked(
436        scope: &Scope,
437        this: &SliceExpand<E>,
438    ) -> *const NativeExpand<E> {
439        unsafe { this.__expand_as_ptr_unchecked_method(scope) }
440    }
441
442    unsafe fn __expand_as_mut_ptr_unchecked(
443        scope: &Scope,
444        this: &mut SliceExpand<E>,
445    ) -> *mut NativeExpand<E> {
446        unsafe { this.__expand_as_mut_ptr_unchecked_method(scope) }
447    }
448
449    unsafe fn __expand_as_mut_unchecked<'infer>(
450        scope: &Scope,
451        this: &'infer SliceExpand<E>,
452    ) -> &'infer mut SliceExpand<E> {
453        this.__expand_as_mut_unchecked_method(scope)
454    }
455
456    unsafe fn __expand_as_boxed_unchecked(
457        scope: &Scope,
458        this: &SliceExpand<E>,
459    ) -> NativeExpand<Box<[E]>> {
460        unsafe { this.__expand_as_boxed_unchecked_method(scope) }
461    }
462}
463
464impl<E: CubePrimitive> SliceExpand<E> {
465    pub fn __expand_as_vectorized_method(
466        &self,
467        _: &Scope,
468    ) -> &SliceExpand<Vector<E::Scalar, E::Size>> {
469        unsafe { self.as_type_ref_unchecked() }
470    }
471
472    pub fn __expand_as_vectorized_mut_method(
473        &mut self,
474        _: &Scope,
475    ) -> &mut SliceExpand<Vector<E::Scalar, E::Size>> {
476        unsafe { self.as_type_mut_unchecked() }
477    }
478
479    pub fn __expand_downcast_method<T: CubePrimitive>(&self, scope: &Scope) -> &SliceExpand<T> {
480        let ty_t = T::__expand_as_type(scope);
481        let ty_e = E::__expand_as_type(scope);
482        if ty_t != ty_e && !is_tf32_cast::<E, T>(scope) && !is_flex32_cast::<E, T>(scope) {
483            panic!(
484                "Downcast should only be used to satisfy the Rust type system.
485Expected types to be the same, got [{}, {}]",
486                ty_t.disp(scope.ctx()),
487                ty_e.disp(scope.ctx())
488            )
489        }
490
491        self.__expand_downcast_unchecked_method(scope)
492    }
493
494    pub fn __expand_downcast_mut_method<T: CubePrimitive>(
495        &mut self,
496        scope: &Scope,
497    ) -> &mut SliceExpand<T> {
498        if T::__expand_as_type(scope) != E::__expand_as_type(scope) && !is_tf32_cast::<E, T>(scope)
499        {
500            let ty_t = T::__expand_as_type(scope);
501            let ty_e = E::__expand_as_type(scope);
502            if ty_t != ty_e && !is_tf32_cast::<E, T>(scope) && !is_flex32_cast::<E, T>(scope) {
503                panic!(
504                    "Downcast should only be used to satisfy the Rust type system.
505Expected types to be the same, got [{}, {}]",
506                    ty_t.disp(scope.ctx()),
507                    ty_e.disp(scope.ctx())
508                )
509            }
510        }
511
512        self.__expand_downcast_mut_unchecked_method(scope)
513    }
514
515    #[doc(hidden)]
516    pub fn __expand_downcast_unchecked_method<T: CubePrimitive>(
517        &self,
518        _: &Scope,
519    ) -> &SliceExpand<T> {
520        unsafe { self.as_type_ref_unchecked() }
521    }
522
523    #[doc(hidden)]
524    pub fn __expand_downcast_mut_unchecked_method<T: CubePrimitive>(
525        &mut self,
526        _: &Scope,
527    ) -> &mut SliceExpand<T> {
528        unsafe { self.as_type_mut_unchecked() }
529    }
530
531    pub fn __expand_as_ptr_method(&self, scope: &Scope) -> *const NativeExpand<E> {
532        self.__expand_index_method(scope, NativeExpand::<usize>::from_lit(scope, 0))
533    }
534
535    pub fn __expand_as_mut_ptr_method(&mut self, scope: &Scope) -> *mut NativeExpand<E> {
536        self.__expand_index_mut_method(scope, NativeExpand::<usize>::from_lit(scope, 0))
537    }
538
539    #[doc(hidden)]
540    pub unsafe fn __expand_as_ptr_unchecked_method(&self, scope: &Scope) -> *const NativeExpand<E> {
541        unsafe {
542            self.__expand_get_unchecked_method(scope, NativeExpand::<usize>::from_lit(scope, 0))
543        }
544    }
545
546    #[doc(hidden)]
547    pub unsafe fn __expand_as_mut_ptr_unchecked_method(
548        &mut self,
549        scope: &Scope,
550    ) -> *mut NativeExpand<E> {
551        unsafe {
552            self.__expand_get_unchecked_mut_method(scope, NativeExpand::<usize>::from_lit(scope, 0))
553        }
554    }
555
556    pub fn __expand_as_mut_unchecked_method(&self, scope: &Scope) -> &mut SliceExpand<E> {
557        scope.create_kernel_ref(self.expand.into())
558    }
559
560    #[doc(hidden)]
561    pub unsafe fn __expand_as_boxed_unchecked_method(&self, _: &Scope) -> NativeExpand<Box<[E]>> {
562        self.expand.into()
563    }
564}
565
566pub fn from_raw_parts<E: CubePrimitive>(
567    scope: &Scope,
568    list: Value,
569    offset: NativeExpand<usize>,
570    length: NativeExpand<usize>,
571) -> SliceExpand<E> {
572    let list_ty = list.get_type(scope.ctx());
573    let offset = offset.read_value(scope);
574    let length = length.read_value(scope);
575    let ty = SliceType::get(scope.ctx(), list_ty).to_handle();
576    let op = CompositeConstructOp::new(scope.ctx_mut(), ty, vec![list, offset, length]);
577    scope.register_with_result(&op).into()
578}
579
580impl<E: CubePrimitive> SliceExpand<E> {
581    /// Get the length of the slice.
582    pub fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
583        self.__extract_length(scope)
584    }
585    /// Returns true if the slice is empty.
586    pub fn is_empty(&self, scope: &Scope) -> NativeExpand<bool> {
587        self.__extract_length(scope)
588            .__expand_eq_method(scope, &0usize.into_expand(scope))
589    }
590}
591
592impl<E: CubePrimitive> CubeType for [E] {
593    type ExpandType = SliceExpand<E>;
594}
595
596impl<E: CubePrimitive> CubeType for Box<[E]> {
597    type ExpandType = NativeExpand<Box<[E]>>;
598}
599
600impl<E> Deref for NativeExpand<Box<[E]>> {
601    type Target = NativeExpand<[E]>;
602
603    fn deref(&self) -> &Self::Target {
604        unsafe { self.as_type_ref_unchecked() }
605    }
606}
607
608impl<E> DerefMut for NativeExpand<Box<[E]>> {
609    fn deref_mut(&mut self) -> &mut Self::Target {
610        unsafe { self.as_type_mut_unchecked() }
611    }
612}
613
614macro_rules! impl_expand_traits {
615    ($generic: ident, $ty: ty) => {
616        impl<$generic: CubePrimitive> AsMutExpand for $ty {
617            fn __expand_ref_mut_method(&mut self, _: &Scope) -> &mut Self {
618                self
619            }
620        }
621
622        impl<$generic: CubePrimitive> IntoMut for $ty {
623            fn into_mut(self, _scope: &Scope) -> Self {
624                self
625            }
626        }
627    };
628}
629
630impl_expand_traits!(E, SliceExpand<E>);
631impl_expand_traits!(E, NativeExpand<Box<[E]>>);
632
633impl<'a, E: CubePrimitive> From<&'a NativeExpand<Box<[E]>>> for &'a NativeExpand<[E]> {
634    fn from(value: &'a NativeExpand<Box<[E]>>) -> Self {
635        unsafe { value.as_type_ref_unchecked() }
636    }
637}
638
639impl<'a, E: CubePrimitive> From<&'a mut NativeExpand<Box<[E]>>> for &'a mut NativeExpand<[E]> {
640    fn from(value: &'a mut NativeExpand<Box<[E]>>) -> Self {
641        unsafe { value.as_type_mut_unchecked() }
642    }
643}
644
645impl<E: CubePrimitive> SizedContainer<usize> for [E] {
646    fn len(&self) -> usize {
647        unexpanded!()
648    }
649}
650
651impl<E: CubePrimitive> SizedContainerExpand<usize> for SliceExpand<E> {
652    fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
653        self.__expand_len_method(scope)
654    }
655}
656
657impl<E: CubePrimitive> Iterable for SliceExpand<E> {
658    type Item = E::ExpandType;
659
660    fn expand(self, scope: &Scope, body: &mut dyn FnMut(&Scope, Self::Item)) {
661        let start = scope.const_usize(0);
662        let end = self.__extract_length(scope).value(scope);
663        let step = scope.const_usize(1);
664
665        let range_loop = RangeLoopOp::new(scope.ctx_mut(), start, end, step);
666        let i = range_loop.iter_var(scope.ctx());
667        let loop_body = range_loop.loop_body(scope.ctx());
668
669        let child = scope.loop_child(OpInserter::new_at_block_end(loop_body));
670
671        let index = NativeExpand::new(i.into());
672        let item = self
673            .__expand_index_method(&child, index)
674            .__expand_deref_method(&child);
675        body(&child, item);
676        child.terminate_yield();
677
678        register_range_loop::<usize>(scope, &range_loop, &child);
679        scope.update_flags_after_loop(&[child]);
680    }
681
682    fn expand_unroll(self, _scope: &Scope, _body: &mut dyn FnMut(&Scope, Self::Item)) {
683        unimplemented!("Can't unroll slice iterator")
684    }
685}
686
687impl<'a, E: CubePrimitive> Iterable for &'a SliceExpand<E> {
688    type Item = &'a E::ExpandType;
689
690    fn expand(self, scope: &Scope, body: &mut dyn FnMut(&Scope, Self::Item)) {
691        let start = scope.const_usize(0);
692        let end = self.__extract_length(scope).value(scope);
693        let step = scope.const_usize(1);
694
695        let range_loop = RangeLoopOp::new(scope.ctx_mut(), start, end, step);
696        let i = range_loop.iter_var(scope.ctx());
697        let loop_body = range_loop.loop_body(scope.ctx());
698
699        let child = scope.loop_child(OpInserter::new_at_block_end(loop_body));
700
701        let index = NativeExpand::new(i.into());
702        let item = self.__expand_index_method(&child, index);
703        body(&child, item);
704        child.terminate_yield();
705
706        register_range_loop::<usize>(scope, &range_loop, &child);
707        scope.update_flags_after_loop(&[child]);
708    }
709
710    fn expand_unroll(self, _scope: &Scope, _body: &mut dyn FnMut(&Scope, Self::Item)) {
711        unimplemented!("Can't unroll slice iterator")
712    }
713}
714
715impl<'a, E: CubePrimitive> Iterable for &'a mut SliceExpand<E> {
716    type Item = &'a mut E::ExpandType;
717
718    fn expand(self, scope: &Scope, body: &mut dyn FnMut(&Scope, Self::Item)) {
719        let start = scope.const_usize(0);
720        let end = self.__extract_length(scope).value(scope);
721        let step = scope.const_usize(1);
722
723        let range_loop = RangeLoopOp::new(scope.ctx_mut(), start, end, step);
724        let i = range_loop.iter_var(scope.ctx());
725        let loop_body = range_loop.loop_body(scope.ctx());
726
727        let child = scope.loop_child(OpInserter::new_at_block_end(loop_body));
728
729        let index = NativeExpand::new(i.into());
730        let item = self.__expand_index_mut_method(&child, index);
731        body(&child, item);
732        child.terminate_yield();
733
734        register_range_loop::<usize>(scope, &range_loop, &child);
735        scope.update_flags_after_loop(&[child]);
736    }
737
738    fn expand_unroll(self, _scope: &Scope, _body: &mut dyn FnMut(&Scope, Self::Item)) {
739        unimplemented!("Can't unroll slice iterator")
740    }
741}
742
743impl<E: CubePrimitive> SliceExpand<E> {
744    #[doc(hidden)]
745    pub unsafe fn __expand_get_unchecked_method(
746        &self,
747        scope: &Scope,
748        index: NativeExpand<usize>,
749    ) -> &NativeExpand<E> {
750        read_offset::expand::<E>(scope, self, index, false)
751    }
752
753    #[doc(hidden)]
754    pub unsafe fn __expand_get_unchecked_mut_method(
755        &mut self,
756        scope: &Scope,
757        index: NativeExpand<usize>,
758    ) -> &mut NativeExpand<E> {
759        write_offset::expand::<E>(scope, self, index, false)
760    }
761}
762
763impl<E: CubePrimitive> IndexExpand<NativeExpand<usize>> for SliceExpand<E> {
764    type Output = E::ExpandType;
765
766    fn __expand_index_method(&self, scope: &Scope, index: NativeExpand<usize>) -> &Self::Output {
767        read_offset::expand::<E>(scope, self, index, true)
768    }
769}
770
771impl<E: CubePrimitive> IndexMutExpand<NativeExpand<usize>> for SliceExpand<E> {
772    fn __expand_index_mut_method(
773        &mut self,
774        scope: &Scope,
775        index: NativeExpand<usize>,
776    ) -> &mut Self::Output {
777        write_offset::expand::<E>(scope, self, index, true)
778    }
779}
780
781impl_slice_ranges!([E: CubePrimitive] SliceExpand<E>);
782
783impl<E: CubePrimitive> List<E> for [E] {}
784impl<E: CubePrimitive> ListExpand<E> for SliceExpand<E> {
785    fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
786        self.__expand_len_method(scope)
787    }
788}
789
790impl<E: CubePrimitive> Vectorized for Box<[E]> {}
791impl<E: CubePrimitive> Vectorized for [E] {}
792impl<E: CubePrimitive> VectorizedExpand for SliceExpand<E> {
793    fn __expand_vector_size_method(&self, scope: &Scope) -> VectorSize {
794        self.__extract_list(scope).vector_size(scope.ctx())
795    }
796}
797impl<E: CubePrimitive> VectorizedExpand for NativeExpand<Box<[E]>> {
798    fn __expand_vector_size_method(&self, scope: &Scope) -> VectorSize {
799        self.__extract_list(scope).vector_size(scope.ctx())
800    }
801}
802
803mod read_offset {
804    use super::*;
805
806    pub fn expand<'a, E: CubePrimitive>(
807        scope: &Scope,
808        slice: &SliceExpand<E>,
809        index: NativeExpand<usize>,
810        checked: bool,
811    ) -> &'a <E as cubecl::prelude::CubeType>::ExpandType {
812        let list = slice.__extract_list(scope);
813        let offset = slice.__extract_offset(scope);
814        let index = offset.__expand_add_method(scope, index);
815
816        expand_index_native(scope, list, index, checked)
817    }
818}
819
820mod write_offset {
821    use super::*;
822
823    pub fn expand<'a, E: CubePrimitive>(
824        scope: &Scope,
825        slice: &SliceExpand<E>,
826        index: <usize as CubeType>::ExpandType,
827        checked: bool,
828    ) -> &'a mut E::ExpandType {
829        let list = slice.__extract_list(scope);
830        let offset = slice.__extract_offset(scope);
831        let index = offset.__expand_add_method(scope, index);
832
833        expand_index_mut_native(scope, list, index, checked)
834    }
835}