cubecl_core/frontend/container/vector/
base.rs1use core::{marker::PhantomData, ops::Neg};
2
3use crate::frontend::{CubePrimitive, CubeType, NativeAssign, NativeExpand};
4use crate::ir::{BinaryOperands, Instruction, Scope, Type};
5use crate::{self as cubecl, prelude::*};
6use cubecl_ir::{Comparison, ConstantValue, Value};
7use cubecl_macros::{cube, intrinsic};
8
9#[derive(Debug)]
11pub struct Vector<P: Scalar, N: Size> {
12 pub(crate) val: P,
14 pub(crate) _size: PhantomData<N>,
15}
16
17type VectorExpand<P, N> = NativeExpand<Vector<P, N>>;
18
19impl<P: Scalar, N: Size> Clone for Vector<P, N> {
20 fn clone(&self) -> Self {
21 *self
22 }
23}
24impl<P: Scalar, N: Size> Eq for Vector<P, N> {}
25impl<P: Scalar, N: Size> Copy for Vector<P, N> {}
26impl<P: Scalar + Neg<Output = P>, N: Size> Neg for Vector<P, N> {
27 type Output = Self;
28
29 fn neg(self) -> Self::Output {
30 Self {
31 val: -self.val,
32 _size: PhantomData,
33 }
34 }
35}
36
37mod new {
39 use cubecl_ir::VectorSize;
40 use cubecl_macros::comptime_type;
41
42 use crate::prelude::Cast;
43
44 use super::*;
45
46 impl<P: Scalar, N: Size> Vector<P, N> {
47 #[allow(unused_variables)]
49 pub fn new(val: P) -> Self {
50 Self {
51 val,
52 _size: PhantomData,
53 }
54 }
55
56 pub fn __expand_new(scope: &Scope, val: NativeExpand<P>) -> VectorExpand<P, N> {
57 Vector::<P, N>::__expand_cast_from(scope, val)
58 }
59 }
60
61 impl<P: Scalar, N: Size> Vector<P, N> {
62 pub fn vector_size(&self) -> comptime_type!(VectorSize) {
64 N::value()
65 }
66 }
67}
68
69mod components {
70 use cubecl_ir::{Operator, VectorInsertOperands};
71
72 use super::*;
73
74 #[cube]
75 impl<P: Scalar, N: Size> Vector<P, N> {
76 #[allow(unused)]
77 pub fn extract(self, index: usize) -> P {
78 intrinsic!(|scope| {
79 if self.expand.vector_size() > 1 {
80 let out = scope.create_value(P::__expand_as_type(scope));
81 scope.register(Instruction::new(
82 Operator::ExtractComponent(BinaryOperands {
83 lhs: self.expand,
84 rhs: index.expand,
85 }),
86 out,
87 ));
88 out.into()
89 } else {
90 read_value(scope, self.expand).into()
91 }
92 })
93 }
94
95 #[allow(unused)]
96 pub fn insert(&mut self, index: usize, value: P) {
97 intrinsic!(|scope| {
98 if self.expand.vector_size() > 1 {
99 let new_value = scope.create_value(self.expand.ty.unwrap_ptr());
100 scope.register(Instruction::new(
101 Operator::InsertComponent(VectorInsertOperands {
102 vector: self.expand,
103 index: index.expand,
104 value: value.expand,
105 }),
106 new_value,
107 ));
108 assign::expand_element(scope, new_value, self.expand);
109 } else {
110 assign::expand_element(scope, value.expand, self.expand);
111 }
112 })
113 }
114 }
115}
116
117mod numeric {
118 use super::*;
119
120 #[cube]
121 impl<P: Numeric, N: Size> Vector<P, N> {
122 pub fn min_value() -> Self {
123 Self::new(P::min_value())
124 }
125 pub fn max_value() -> Self {
126 Self::new(P::max_value())
127 }
128
129 pub fn from_int(val: i64) -> Self {
138 Self::new(P::from_int(val))
139 }
140 }
141}
142
143mod fill {
145 use super::*;
146
147 #[cube]
148 impl<P: Scalar, N: Size> Vector<P, N> {
149 pub fn fill(self, value: P) -> Self {
160 intrinsic!(|scope| { Vector::<P, N>::__expand_cast_from(scope, value) })
161 }
162 }
163}
164
165mod empty {
167 use bytemuck::Zeroable;
168
169 use super::*;
170
171 #[cube]
172 impl<P: Scalar, N: Size> Vector<P, N> {
173 pub fn empty() -> Self {
174 intrinsic!(|scope| {
175 let value = Self::__expand_default(scope);
176 value.into_mut(scope)
177 })
178 }
179 }
180
181 #[cube]
182 impl<P: Scalar + Zeroable, N: Size> Vector<P, N> {
183 pub fn zeroed() -> Self {
184 intrinsic!(|scope| {
185 let zeroed = P::zeroed().__expand_runtime_method(scope);
186 Self::__expand_cast_from(scope, zeroed)
187 })
188 }
189 }
190}
191
192mod size {
194 use cubecl_ir::VectorSize;
195
196 use super::*;
197
198 impl<P: Scalar, N: Size> Vector<P, N> {
199 pub fn size(&self) -> VectorSize {
210 N::value()
211 }
212
213 pub fn __expand_size(scope: &Scope, element: NativeExpand<Vector<P, N>>) -> VectorSize {
215 element.__expand_vector_size_method(scope)
216 }
217 }
218
219 impl<P: Scalar, N: Size> NativeExpand<Vector<P, N>> {
220 pub fn size(&self) -> VectorSize {
222 self.expand.ty.vector_size()
223 }
224
225 pub fn __expand_size_method(&self, _scope: &Scope) -> VectorSize {
227 self.size()
228 }
229 }
230}
231
232macro_rules! impl_vector_comparison {
234 ($name:ident, $operator:ident, $comment:literal) => {
235 ::paste::paste! {
236 mod $name {
238
239 use super::*;
240
241 #[cube]
242 impl<P: Scalar, N: Size> Vector<P, N> {
243 #[doc = concat!(
244 "Return a new vector with the element-wise comparison of the first vector being ",
245 $comment,
246 " the second vector."
247 )]
248 pub fn $name(&self, other: &Self) -> Vector<bool, N> {
249 intrinsic!(|scope| {
250 let this = self.__expand_deref_method(scope);
251 let other = other.__expand_deref_method(scope);
252 let size = this.expand.ty.vector_size();
253 let lhs = this.expand;
254 let rhs = other.expand.into();
255
256 let output = scope.create_value(Vector::<bool, N>::__expand_as_type(scope));
257
258 scope.register(Instruction::new(
259 Comparison::$operator(BinaryOperands { lhs, rhs }),
260 output.clone().into(),
261 ));
262
263 output.into()
264 })
265 }
266 }
267 }
268 }
269
270 };
271}
272
273impl_vector_comparison!(equal, Equal, "equal to");
274impl_vector_comparison!(not_equal, NotEqual, "not equal to");
275impl_vector_comparison!(less_than, Lower, "less than");
276impl_vector_comparison!(greater_than, Greater, "greater than");
277impl_vector_comparison!(less_equal, LowerEqual, "less than or equal to");
278impl_vector_comparison!(greater_equal, GreaterEqual, "greater than or equal to");
279
280mod bool_and {
281 use cubecl_ir::Operator;
282
283 use crate::prelude::binary_expand;
284
285 use super::*;
286
287 #[cube]
288 impl<N: Size> Vector<bool, N> {
289 pub fn vec_and(self, other: Self) -> Vector<bool, N> {
291 intrinsic!(
292 |scope| binary_expand(scope, self.expand, other.expand, Operator::And).into()
293 )
294 }
295 }
296}
297
298mod bool_or {
299 use cubecl_ir::Operator;
300
301 use crate::prelude::binary_expand;
302
303 use super::*;
304
305 #[cube]
306 impl<N: Size> Vector<bool, N> {
307 pub fn or(self, other: Self) -> Vector<bool, N> {
309 intrinsic!(|scope| binary_expand(scope, self.expand, other.expand, Operator::Or).into())
310 }
311 }
312}
313
314impl<P: Scalar, N: Size> CubeType for Vector<P, N> {
315 type ExpandType = NativeExpand<Self>;
316}
317
318impl<P: Scalar, N: Size> CubeDebug for Vector<P, N> {}
319
320impl<P: Scalar, N: Size> NativeAssign for Vector<P, N> {
321 fn elem_init_mut(scope: &Scope, elem: Value) -> Value {
322 P::elem_init_mut(scope, elem)
323 }
324}
325
326impl<P: Scalar, N: Size> CubePrimitive for Vector<P, N> {
327 type Scalar = P;
328 type Size = N;
329 type WithScalar<S: Scalar> = Vector<S, N>;
330
331 fn __expand_as_type(scope: &Scope) -> Type {
332 Type::with_vector_size(P::__expand_as_type(scope), N::__expand_value(scope))
333 }
334
335 fn as_type_native() -> Option<Type> {
336 P::as_type_native().and_then(|ty| {
337 let vector_size = N::try_value_const()?;
338 Some(Type::with_vector_size(ty, vector_size))
339 })
340 }
341
342 fn from_const_value(value: ConstantValue) -> Self {
343 Self::new(P::from_const_value(value))
344 }
345}
346
347impl<T: Dot + Scalar, N: Size> Dot for Vector<T, N> {}
348impl<T: MulHi + Scalar, N: Size> MulHi for Vector<T, N> {}
349impl<T: FloatOps + Scalar, N: Size> FloatOps for Vector<T, N> {}
350impl<T: Hypot + Scalar, N: Size> Hypot for Vector<T, N> {}
351impl<T: Rhypot + Scalar, N: Size> Rhypot for Vector<T, N> {}