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 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
158pub 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
194fn 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
227fn 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 fn as_vectorized(&self) -> &[Vector<E::Scalar, E::Size>] {
246 unexpanded!()
247 }
248
249 fn as_vectorized_mut(&mut self) -> &mut [Vector<E::Scalar, E::Size>] {
252 unexpanded!()
253 }
254
255 fn downcast<T: CubePrimitive>(&self) -> &[T] {
260 unexpanded!()
261 }
262
263 fn downcast_mut<T: CubePrimitive>(&mut self) -> &mut [T] {
268 unexpanded!()
269 }
270
271 unsafe fn downcast_unchecked<T: CubePrimitive>(&self) -> &[T] {
277 unexpanded!()
278 }
279
280 unsafe fn downcast_mut_unchecked<T: CubePrimitive>(&mut self) -> &mut [T] {
286 unexpanded!()
287 }
288
289 #[allow(clippy::mut_from_ref)]
295 unsafe fn as_mut_unchecked(&self) -> &mut [E] {
296 unexpanded!()
297 }
298
299 unsafe fn as_ptr_unchecked(&self) -> *const E {
304 unexpanded!()
305 }
306
307 unsafe fn as_mut_ptr_unchecked(&mut self) -> *mut E {
312 unexpanded!()
313 }
314
315 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 pub fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
583 self.__extract_length(scope)
584 }
585 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}