cubecl_std/tensor/contiguous/
perpendicular.rs1use crate::tensor::{TensorHandle, into_contiguous};
2use cubecl::prelude::*;
3use cubecl_core::{
4 self as cubecl, calculate_cube_count_elemwise, tensor_vector_size_parallel,
5 tensor_vector_size_perpendicular,
6};
7use std::cmp::min;
8
9#[cube(launch_unchecked, address_type = "dynamic")]
16fn copy_perpendicular<T: Numeric, N: Size>(
17 input: &Tensor<Vector<T, N>>,
18 output: &mut Tensor<Vector<T, N>>,
19 axis_vectorized: usize,
20 #[define(T)] _elem: ElemType,
21) {
22 let vector_size = input.vector_size();
23 let last_axis = input.rank() - 1;
24
25 let num_batch = output.shape(last_axis) / vector_size;
27
28 let mut accumulators = Sequence::<Vector<T, N>>::new();
30
31 #[unroll]
32 for _ in 0..vector_size {
33 accumulators.push(Vector::empty());
34 }
35
36 let channel_input_stride_elem = input.stride(last_axis);
37 let channel_output_stride_elem = output.stride(axis_vectorized);
38
39 let channel_input_stride = channel_input_stride_elem / vector_size;
41 let channel_output_stride = channel_output_stride_elem / vector_size;
42
43 let num_runs = output.len() / (num_batch * vector_size);
45
46 if ABSOLUTE_POS >= num_runs {
47 terminate!()
48 }
49
50 let batch_index = ABSOLUTE_POS * num_batch;
52 let skip_interval = batch_index / channel_output_stride;
53 let skip_index = batch_index % channel_output_stride;
54 let skip_size = channel_output_stride_elem;
55 let global_index = (skip_interval * skip_size) + skip_index;
56
57 for b in 0..num_batch {
58 let offset_output = global_index + b;
59
60 let mut batch_offset = 0;
62 for axis in 0..input.rank() {
63 let coordinate = output.coordinate(offset_output * vector_size, axis);
64 batch_offset += coordinate * input.stride(axis);
65 }
66 let batch_offset = batch_offset / vector_size;
67
68 #[unroll]
72 for i in 0..vector_size {
73 let index = batch_offset + i * channel_input_stride;
74 let batched = input[index];
75
76 #[unroll]
79 for o in 0..vector_size {
80 let vector = accumulators.index_mut(o);
81 vector.insert(i, batched.extract(o));
82 }
83 }
84
85 #[unroll]
88 for o in 0..vector_size {
89 let index_out = offset_output + o * channel_output_stride;
90 let batched = accumulators[o];
91
92 output[index_out] = batched;
93 }
94 }
95}
96
97pub fn launch_into_contiguous_perpendicular<R: Runtime>(
103 client: &ComputeClient<R>,
104 input: TensorBinding<R>,
105 dtype: ElemType,
106) -> TensorHandle<R> {
107 if input.shape.len() <= 1 {
109 return into_contiguous(client, input, dtype);
110 }
111
112 let output = TensorHandle::empty(client, input.shape.to_vec(), dtype);
113 launch_copy_perpendicular_ref(client, input, output.clone().binding(), dtype);
114
115 output
116}
117
118pub fn launch_copy_perpendicular_ref<R: Runtime>(
124 client: &ComputeClient<R>,
125 input: TensorBinding<R>,
126 output: TensorBinding<R>,
127 dtype: ElemType,
128) {
129 let mut axis = 0;
130
131 for (i, stride) in input.strides.iter().enumerate() {
132 if *stride == 1 {
133 axis = i;
134 break;
135 }
136 }
137 let rank = output.shape.len();
138
139 let vector_size_perpendicular = tensor_vector_size_perpendicular(
140 client.io_optimized_vector_sizes(dtype.size()),
141 &input.shape,
142 &input.strides,
143 rank - 1,
144 );
145 let vector_size_parallel = tensor_vector_size_parallel(
146 client.io_optimized_vector_sizes(dtype.size()),
147 &output.shape,
148 &output.strides,
149 rank - 1,
150 );
151 let vector_size_axis = tensor_vector_size_parallel(
154 client.io_optimized_vector_sizes(dtype.size()),
155 &input.shape,
156 &input.strides,
157 axis,
158 );
159 let vector_size = min(
160 min(vector_size_perpendicular, vector_size_parallel),
161 vector_size_axis,
162 );
163
164 let num_elems = output.shape.iter().product::<usize>();
165 let working_units = num_elems / (vector_size as usize * output.shape[rank - 1]);
166 let cube_dim = CubeDim::new(client, working_units);
167 let cube_count = calculate_cube_count_elemwise(client, working_units, cube_dim);
168 let address_type = input
169 .required_address_type(dtype.size())
170 .max(output.required_address_type(dtype.size()));
171
172 unsafe {
173 copy_perpendicular::launch_unchecked::<R>(
174 client,
175 cube_count,
176 cube_dim,
177 address_type,
178 vector_size,
179 input.into_tensor_arg(),
180 output.into_tensor_arg(),
181 axis,
182 dtype,
183 );
184 }
185}