cubecl_core/frontend/container/vector/
base.rs1use core::{marker::PhantomData, ops::Neg};
2
3use crate::frontend::{CubePrimitive, CubeType, NativeAssign, NativeExpand};
4use crate::ir::Scope;
5use crate::{self as cubecl, prelude::*};
6use cubecl_ir::{ConstantValue, ExpandValue, types::VectorType};
7use cubecl_macros::{cube, intrinsic};
8use num_traits::Zero;
9use pliron::r#type::TypeHandle;
10
11#[derive(Debug)]
13pub struct Vector<P: Scalar, N: Size> {
14 pub(crate) val: P,
16 pub(crate) _size: PhantomData<N>,
17}
18
19type VectorExpand<P, N> = NativeExpand<Vector<P, N>>;
20
21impl<P: Scalar, N: Size> Clone for Vector<P, N> {
22 fn clone(&self) -> Self {
23 *self
24 }
25}
26impl<P: Scalar, N: Size> Eq for Vector<P, N> {}
27impl<P: Scalar, N: Size> Copy for Vector<P, N> {}
28impl<P: Scalar + Neg<Output = P>, N: Size> Neg for Vector<P, N> {
29 type Output = Self;
30
31 fn neg(self) -> Self::Output {
32 Self {
33 val: -self.val,
34 _size: PhantomData,
35 }
36 }
37}
38impl<P: Scalar + NegNativeExpand, N: Size> NegNativeExpand for Vector<P, N> {
39 fn __expand_native_neg(scope: &Scope, this: ExpandValue) -> ExpandValue {
40 P::__expand_native_neg(scope, this)
41 }
42}
43
44mod new {
46 use cubecl_ir::VectorSize;
47 use cubecl_macros::comptime_type;
48
49 use super::*;
50
51 impl<P: Scalar, N: Size> Vector<P, N> {
52 #[allow(unused_variables)]
54 pub fn new(val: P) -> Self {
55 Self {
56 val,
57 _size: PhantomData,
58 }
59 }
60
61 pub fn __expand_new(scope: &Scope, val: NativeExpand<P>) -> VectorExpand<P, N> {
62 broadcast_value(scope, val.read_value(scope), N::__expand_value(scope)).into()
63 }
64 }
65
66 #[cube]
67 impl<P: Scalar, N: Size> Vector<P, N> {
68 pub fn broadcast(value: P) -> Vector<P, N> {
69 Self::new(value)
70 }
71 }
72
73 impl<P: Scalar, N: Size> Vector<P, N> {
74 pub fn vector_size(&self) -> comptime_type!(VectorSize) {
76 N::value()
77 }
78 }
79}
80
81mod components {
82 use cubecl_ir::{
83 dialect::vector::{
84 CompositeExtractOp, CompositeInsertOp, VectorExtractDynamicOp, VectorInsertDynamicOp,
85 },
86 interfaces::TypedExt,
87 };
88
89 use super::*;
90
91 #[cube]
92 impl<P: Scalar, N: Size> Vector<P, N> {
93 pub fn extract(self, #[comptime] index: usize) -> P {
94 intrinsic!(|scope| {
95 let this = self.read_value(scope);
96 if this.vector_size(scope.ctx()) > 1 {
97 let op = CompositeExtractOp::new(scope.ctx_mut(), this, index);
98 scope.register_with_result(&op).into()
99 } else {
100 this.into()
101 }
102 })
103 }
104
105 pub fn insert(&mut self, #[comptime] index: usize, value: P) {
106 intrinsic!(|scope| {
107 let this = self.read_value(scope);
108 let value = value.read_value(scope);
109 if this.vector_size(scope.ctx()) > 1 {
110 let op = CompositeInsertOp::new(scope.ctx_mut(), this, value, index);
111 let new_value = scope.register_with_result(&op).into();
112 assign::expand_element(scope, new_value, self.expand);
113 } else {
114 assign::expand_element(scope, value.into(), self.expand);
115 }
116 })
117 }
118
119 pub fn extract_dynamic(self, index: usize) -> P {
122 intrinsic!(|scope| {
123 let this = self.read_value(scope);
124 if this.vector_size(scope.ctx()) > 1 {
125 let index = index.read_value(scope);
126 let op = VectorExtractDynamicOp::new(scope.ctx_mut(), this, index);
127 scope.register_with_result(&op).into()
128 } else {
129 this.into()
130 }
131 })
132 }
133
134 pub fn insert_dynamic(&mut self, index: usize, value: P) {
137 intrinsic!(|scope| {
138 let this = self.read_value(scope);
139 let value = value.read_value(scope);
140 if this.vector_size(scope.ctx()) > 1 {
141 let index = index.read_value(scope);
142 let op = VectorInsertDynamicOp::new(scope.ctx_mut(), this, value, index);
143 let new_value = scope.register_with_result(&op).into();
144 assign::expand_element(scope, new_value, self.expand);
145 } else {
146 assign::expand_element(scope, value.into(), self.expand);
147 }
148 })
149 }
150 }
151}
152
153mod numeric {
154 use super::*;
155
156 #[cube]
157 impl<P: Numeric, N: Size> Vector<P, N> {
158 pub fn min_value() -> Self {
159 Self::new(P::min_value())
160 }
161 pub fn max_value() -> Self {
162 Self::new(P::max_value())
163 }
164
165 pub fn from_int(val: i64) -> Self {
174 Self::new(P::from_int(val))
175 }
176 }
177}
178
179mod fill {
181 use super::*;
182
183 #[cube]
184 impl<P: Scalar, N: Size> Vector<P, N> {
185 pub fn fill(self, value: P) -> Self {
196 intrinsic!(|scope| { Vector::<P, N>::__expand_cast_from(scope, value) })
197 }
198 }
199}
200
201mod empty {
203 use bytemuck::Zeroable;
204
205 use super::*;
206
207 #[cube]
208 impl<P: Scalar, N: Size> Vector<P, N> {
209 pub fn empty() -> Self {
210 intrinsic!(|scope| {
211 let value = Self::__expand_default(scope);
212 value.into_mut(scope)
213 })
214 }
215 }
216
217 #[cube]
218 impl<P: Scalar + Zeroable, N: Size> Vector<P, N> {
219 pub fn zeroed() -> Self {
220 intrinsic!(|scope| {
221 let zeroed = P::zeroed().__expand_runtime_method(scope);
222 Self::__expand_cast_from(scope, zeroed)
223 })
224 }
225 }
226}
227
228macro_rules! impl_vector_comparison {
230 ($name:ident, $trait: ty, $operator:ident, $comment:literal) => {
231 ::paste::paste! {
232 mod $name {
234
235 use super::*;
236
237 #[cube]
238 impl<P: Scalar + $trait, N: Size> Vector<P, N> {
239 #[doc = concat!(
240 "Return a new vector with the element-wise comparison of the first vector being ",
241 $comment,
242 " the second vector."
243 )]
244 pub fn $name(&self, other: &Self) -> Vector<bool, N> {
245 intrinsic!(|scope| {
246 let this = self.__expand_deref_method(scope).into();
247 let other = other.__expand_deref_method(scope).into();
248
249 P::Scalar::[<__expand_native_ $operator>](scope, this, other).into()
250 })
251 }
252 }
253 }
254 }
255
256 };
257}
258
259impl_vector_comparison!(equal, CubePartialEq, eq, "equal to");
260impl_vector_comparison!(not_equal, CubePartialEq, ne, "not equal to");
261impl_vector_comparison!(less_than, CubePartialOrd, lt, "less than");
262impl_vector_comparison!(greater_than, CubePartialOrd, gt, "greater than");
263impl_vector_comparison!(less_equal, CubePartialOrd, le, "less than or equal to");
264impl_vector_comparison!(
265 greater_equal,
266 CubePartialOrd,
267 ge,
268 "greater than or equal to"
269);
270
271mod bool_and {
272 use cubecl_ir::dialect::general::BoolAndOp;
273
274 use crate::prelude::binary_expand;
275
276 use super::*;
277
278 #[cube]
279 impl<N: Size> Vector<bool, N> {
280 pub fn vec_and(self, other: Self) -> Vector<bool, N> {
282 intrinsic!(
283 |scope| binary_expand(scope, self.expand, other.expand, BoolAndOp::new).into()
284 )
285 }
286 }
287}
288
289mod bool_or {
290 use cubecl_ir::dialect::general::BoolOrOp;
291
292 use crate::prelude::binary_expand;
293
294 use super::*;
295
296 #[cube]
297 impl<N: Size> Vector<bool, N> {
298 pub fn or(self, other: Self) -> Vector<bool, N> {
300 intrinsic!(
301 |scope| binary_expand(scope, self.expand, other.expand, BoolOrOp::new).into()
302 )
303 }
304 }
305}
306
307impl<P: Scalar, N: Size> CubeType for Vector<P, N> {
308 type ExpandType = NativeExpand<Self>;
309}
310
311impl<P: Scalar, N: Size> CubeDebug for Vector<P, N> {}
312
313impl<P: Scalar, N: Size> NativeAssign for Vector<P, N> {
314 fn elem_init_mut(scope: &Scope, elem: ExpandValue) -> ExpandValue {
315 P::elem_init_mut(scope, elem)
316 }
317}
318
319impl<P: Scalar, N: Size> CubePrimitive for Vector<P, N> {
320 type Scalar = P;
321 type Size = N;
322 type WithScalar<S: Scalar> = Vector<S, N>;
323
324 fn __expand_as_type(scope: &Scope) -> TypeHandle {
325 let inner = P::__expand_as_type(scope);
326 let vectorization = N::__expand_value(scope);
327 if vectorization > 1 {
328 VectorType::get(scope.ctx(), inner, vectorization).into()
329 } else {
330 inner
331 }
332 }
333
334 fn from_const_value(value: ConstantValue) -> Self {
335 Self::new(P::from_const_value(value))
336 }
337}
338
339impl<T: Dot + Scalar, N: Size> Dot for Vector<T, N> {}
340impl<T: MulHi + Scalar, N: Size> MulHi for Vector<T, N> {}
341impl<T: FloatOps + Scalar, N: Size> FloatOps for Vector<T, N> {}
342impl<T: Hypot + Scalar, N: Size> Hypot for Vector<T, N> {}
343impl<T: Rhypot + Scalar, N: Size> Rhypot for Vector<T, N> {}
344
345#[cube]
346impl<T: Int, N: Size> Vector<T, N> {
347 pub fn is_multiple_of(&self, multiple: T) -> Vector<bool, N> {
348 (*self % Vector::new(multiple)).equal(&Vector::zero())
349 }
350}