1use core::ops::{Div, Neg, Not};
2use cubecl_common::{e2m1, e2m1x2, e4m3, e5m2, ue8m0};
3use cubecl_ir::dialect::{bitwise::*, general::BoolNotOp, math::*, vector::*};
4use half::{bf16, f16};
5
6use crate::{
7 flex32,
8 frontend::{DivExpand, Scalar},
9 ir::{ExpandValue, Scope},
10 prelude::{
11 CubePrimitive, CubePrimitiveExpand, CubeType, IntoExpand, NativeExpand, Reinterpret,
12 },
13 tf32, unexpanded,
14};
15
16use super::base::unary_expand;
17
18pub mod not {
19 use super::*;
20
21 pub fn expand<T: CubeNot>(scope: &Scope, x: NativeExpand<T>) -> NativeExpand<T> {
22 if T::Scalar::elem_type(scope).is_bool() {
23 unary_expand(scope, x.into(), BoolNotOp::new).into()
24 } else {
25 unary_expand(scope, x.into(), BitwiseNotOp::new).into()
26 }
27 }
28}
29
30macro_rules! define_unary_func {
31 ($trait_name:ident, $method_name:ident, $operator:expr, $($type:ty),*) => {
32 paste::paste! {
33 pub trait [<Scalar $trait_name>]: $trait_name + [<$trait_name NativeExpand>] {}
34 impl<T: $trait_name + [<$trait_name NativeExpand>]> [<Scalar $trait_name>] for T {}
35
36 pub trait $trait_name: CubePrimitive<Scalar: [<$trait_name NativeExpand>]>
37 + CubeType<ExpandType: [<$trait_name Expand>]> + Sized {
38 #[allow(unused_variables)]
39 fn $method_name(self) -> Self {
40 unexpanded!()
41 }
42
43 fn [<__expand_ $method_name>](scope: &Scope, x: NativeExpand<Self>) -> NativeExpand<Self> {
44 x.[<__expand_ $method_name _method>](scope)
45 }
46 }
47
48 pub trait [<$trait_name Expand>] {
49 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self;
50 }
51
52 pub trait [<$trait_name NativeExpand>] {
53 fn [<__expand_native_ $method_name>](scope: &Scope, input: ExpandValue) -> ExpandValue;
54 }
55
56 $(impl $trait_name for $type {})*
57 $(impl [<$trait_name NativeExpand>] for $type {
58 fn [<__expand_native_ $method_name>](scope: &Scope, input: ExpandValue) -> ExpandValue {
59 unary_expand(scope, input, $operator::new)
60 }
61 })*
62
63 impl<T: $trait_name + CubePrimitive> [<$trait_name Expand>] for NativeExpand<T> {
64 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self {
65 T::Scalar::[<__expand_native_ $method_name>](scope, self.into()).into()
66 }
67 }
68 }
69 }
70}
71
72macro_rules! impl_unary_func {
73 ($($type:ty),*; $trait_name:ident, $method_name:ident, $operator:expr) => {
74 paste::paste! {
75 $(impl $trait_name for $type {})*
76 $(impl [<$trait_name NativeExpand>] for $type {
77 fn [<__expand_native_ $method_name>](scope: &Scope, input: ExpandValue) -> ExpandValue {
78 unary_expand(scope, input, $operator::new)
79 }
80 })*
81 }
82 }
83}
84
85macro_rules! impl_unary_func_nop {
86 ($($type:ty),*; $trait_name:ident, $method_name:ident) => {
87 paste::paste! {
88 $(impl $trait_name for $type {})*
89 $(impl [<$trait_name NativeExpand>] for $type {
90 fn [<__expand_native_ $method_name>](_scope: &Scope, input: ExpandValue) -> ExpandValue {
91 input
92 }
93 })*
94 }
95 }
96}
97
98macro_rules! impl_normalize {
100 ($trait_name:ident, $method_name:ident, $operator:expr, $($type:ty),*) => {
101 paste::paste! {
102 pub trait $trait_name: CubePrimitive + CubeType<ExpandType: [<$trait_name Expand>]> + Sized + Abs + Div<Output = Self> {
103 #[allow(unused_variables)]
104 fn $method_name(self) -> Self {
105 unexpanded!()
106 }
107
108 fn [<__expand_ $method_name>](scope: &Scope, x: NativeExpand<Self>) -> NativeExpand<Self> {
109 x.[<__expand_ $method_name _method>](scope)
110 }
111 }
112
113 pub trait [<$trait_name Expand>] {
114 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self;
115 }
116
117 $(impl $trait_name for $type {})*
118 impl<T: $trait_name + CubePrimitive> [<$trait_name Expand>] for NativeExpand<T> where NativeExpand<T>: DivExpand {
119 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self {
120 if self.__expand_vector_size_method(scope) == 1 {
121 let abs = self.__expand_abs_method(scope);
123 self.__expand_div_method(scope, abs)
124 } else {
125 unary_expand(scope, self.into(), $operator::new).into()
126 }
127 }
128 }
129 }
130 }
131}
132
133macro_rules! define_unary_func_scalar_out {
134 ($trait_name:ident, $method_name:ident) => {
135 paste::paste! {
136 pub trait [<Scalar $trait_name>]: $trait_name + [<$trait_name NativeExpand>] {}
137 impl<T: $trait_name + [<$trait_name NativeExpand>]> [<Scalar $trait_name>] for T {}
138
139 pub trait $trait_name: CubePrimitive<Scalar: [<$trait_name NativeExpand>]>
140 + CubeType<ExpandType: [<$trait_name Expand>]
141 + CubePrimitiveExpand<Scalar = NativeExpand<Self::Scalar>>>
142 + Sized {
143 #[allow(unused_variables)]
144 fn $method_name(self) -> Self::Scalar {
145 unexpanded!()
146 }
147
148 fn [<__expand_ $method_name>](scope: &Scope, x: NativeExpand<Self>) -> NativeExpand<Self::Scalar> {
149 x.[<__expand_ $method_name _method>](scope)
150 }
151 }
152
153 pub trait [<$trait_name Expand>]: CubePrimitiveExpand {
154 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self::Scalar;
155 }
156
157 pub trait [<$trait_name NativeExpand>] {
158 fn [<__expand_native_ $method_name _scalar>](scope: &Scope, input: ExpandValue) -> ExpandValue;
159 fn [<__expand_native_ $method_name>](scope: &Scope, input: ExpandValue) -> ExpandValue;
160 }
161
162 impl<T: $trait_name + CubePrimitive> [<$trait_name Expand>] for NativeExpand<T> {
163 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self::Scalar {
164 if self.__expand_vector_size_method(scope) == 1 {
167 T::Scalar::[<__expand_native_ $method_name _scalar>](scope, self.into()).into()
168 } else {
169 T::Scalar::[<__expand_native_ $method_name>](scope, self.into()).into()
170 }
171 }
172 }
173 }
174 }
175}
176
177macro_rules! impl_unary_func_scalar_out {
178 ($($type:ty),*; $trait_name:ident, $method_name:ident, $operator:expr, $scalar_op: expr) => {
179 paste::paste! {
180 $(impl $trait_name for $type {})*
181 $(impl [<$trait_name NativeExpand>] for $type {
182 fn [<__expand_native_ $method_name _scalar>](scope: &Scope, input: ExpandValue) -> ExpandValue {
183 ($scalar_op)(scope, input)
184 }
185 fn [<__expand_native_ $method_name>](scope: &Scope, input: ExpandValue) -> ExpandValue {
186 unary_expand(scope, input, $operator::new)
187 }
188 })*
189 }
190 }
191}
192
193macro_rules! impl_unary_func_fixed_out_ty {
194 ($trait_name:ident, $method_name:ident, $out_ty: ty, $operator:expr, $($type:ty),*) => {
195 paste::paste! {
196 pub trait $trait_name: CubePrimitive + CubeType<ExpandType: [<$trait_name Expand>]
197 + CubePrimitiveExpand<WithScalar<$out_ty> = NativeExpand<Self::WithScalar<$out_ty>>>> + Sized {
198 #[allow(unused_variables, clippy::wrong_self_convention)]
199 fn $method_name(self) -> Self::WithScalar<$out_ty> {
200 unexpanded!()
201 }
202
203 fn [<__expand_ $method_name>](scope: &Scope, x: NativeExpand<Self>) -> NativeExpand<Self::WithScalar<$out_ty>> {
204 x.[<__expand_ $method_name _method>](scope)
205 }
206 }
207
208 pub trait [<$trait_name Expand>]: CubePrimitiveExpand {
209 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self::WithScalar<$out_ty>;
210 }
211
212 $(impl $trait_name for $type {})*
213 impl<T: $trait_name + CubePrimitive> [<$trait_name Expand>] for NativeExpand<T> {
214 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self::WithScalar<$out_ty> {
215 unary_expand(scope, self.into(), $operator::new).into()
216 }
217 }
218 }
219 }
220}
221
222macro_rules! impl_not {
224 ($trait:ident, $method_name:ident, $($type:ty),*) => {
225 paste::paste! {
226 pub trait [<Cube $trait>]:
227 $trait<Output = Self>
228 + CubePrimitive
229 + CubeType<ExpandType: [<$trait Expand>]>
230 + IntoExpand<Expand = <Self as CubeType>::ExpandType> {
231 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> NativeExpand<Self> {
232 let this = self.into_expand(scope);
233 this.[<__expand_ $method_name _method>](scope)
234 }
235
236 fn [<__expand_ $method_name>](scope: &Scope, x: NativeExpand<Self>) -> NativeExpand<Self> {
237 x.[<__expand_ $method_name _method>](scope)
238 }
239 }
240
241 pub trait [<$trait Expand>] {
242 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self;
243 }
244
245 $(impl [<Cube $trait>] for $type {})*
246 impl<T: [<Cube $trait>] + CubePrimitive> [<$trait Expand>] for NativeExpand<T> {
247 fn [<__expand_ $method_name _method>](self, scope: &Scope) -> Self {
248 not::expand(scope, self.into())
249 }
250 }
251 }
252 }
253}
254
255macro_rules! define_core_unop {
256 ($trait: ident, $method: ident) => {
257 paste::paste! {
258 pub trait [<Scalar $trait>]: [<Cube $trait>] + [<$trait NativeExpand>] {}
259 impl<T: [<Cube $trait>] + [<$trait NativeExpand>]> [<Scalar $trait>] for T {}
260
261 pub trait [<Cube $trait>]:
262 $trait<Output = Self> + CubePrimitive<Scalar: [<$trait NativeExpand>]>
263 + IntoExpand<Expand = <Self as CubeType>::ExpandType>
264 + CubeType<ExpandType: [<$trait Expand>]> + Sized {
265 fn [<__expand_ $method _method>](self, scope: &Scope) -> NativeExpand<Self> {
266 let this: NativeExpand<Self> = self.into_expand(scope);
267 this.[<__expand_ $method _method>](scope)
268 }
269
270 fn [<__expand_ $method>](
271 scope: &Scope,
272 lhs: NativeExpand<Self>,
273 ) -> NativeExpand<Self> {
274 lhs.[<__expand_ $method _method>](scope)
275 }
276 }
277
278 pub trait [<$trait Expand>] {
279 fn [<__expand_ $method _method>](self, scope: &Scope) -> Self;
280 }
281
282 pub trait [<$trait NativeExpand>] {
283 fn [<__expand_native_ $method>](scope: &Scope, this: ExpandValue) -> ExpandValue;
284 }
285
286 impl<T: $trait<Output = Self> + CubePrimitive<Scalar: [<$trait NativeExpand>]>
287 + IntoExpand<Expand = <Self as CubeType>::ExpandType>> [<Cube $trait>] for T {}
288 impl<T: [<Cube $trait>]> [<$trait Expand>] for NativeExpand<T> {
289 fn [<__expand_ $method _method>](self, scope: &Scope) -> Self {
290 T::Scalar::[<__expand_native_ $method>](scope, self.expand).into()
291 }
292 }
293 }
294 };
295}
296
297macro_rules! impl_core_unop {
298 ($($ty: ty),*; $trait: ident, $method: ident, $op: expr) => {
299 paste::paste! {
300 $(impl [<$trait NativeExpand>] for $ty {
301 fn [<__expand_native_ $method>](scope: &Scope, this: ExpandValue) -> ExpandValue {
302 unary_expand(scope, this, $op::new).into()
303 }
304 })*
305 }
306 };
307}
308
309impl_not!(
310 Not, not, bool, u8, u16, u32, u64, i8, i16, i32, i64, isize, usize
311);
312
313define_core_unop!(Neg, neg);
314impl_core_unop!(i8, i16, i32, i64, isize; Neg, neg, SNegOp);
315impl_core_unop!(f16, bf16, f32, flex32, tf32, f64; Neg, neg, FNegOp);
316
317define_unary_func!(Abs, abs, SAbsOp, i8, i16, i32, i64, isize);
318impl_unary_func_nop!(u8, u16, u32, u64, usize; Abs, abs);
319impl_unary_func!(e2m1, e4m3, e5m2, ue8m0, f16, bf16, flex32, tf32, f32, f64; Abs, abs, FAbsOp);
320
321define_unary_func!(Exp, exp, ExpOp, f16, bf16, flex32, tf32, f32, f64);
322define_unary_func!(Log, ln, LogOp, f16, bf16, flex32, tf32, f32, f64);
323define_unary_func!(Log1p, log1p, Log1pOp, f16, bf16, flex32, tf32, f32, f64);
324define_unary_func!(Expm1, exp_m1, Expm1Op, f16, bf16, flex32, tf32, f32, f64);
325define_unary_func!(Cos, cos, CosOp, f16, bf16, flex32, tf32, f32, f64);
326define_unary_func!(Sin, sin, SinOp, f16, bf16, flex32, tf32, f32, f64);
327define_unary_func!(Tan, tan, TanOp, f16, bf16, flex32, tf32, f32, f64);
328define_unary_func!(Tanh, tanh, TanhOp, f16, bf16, flex32, tf32, f32, f64);
329define_unary_func!(Sinh, sinh, SinhOp, f16, bf16, flex32, tf32, f32, f64);
330define_unary_func!(Cosh, cosh, CoshOp, f16, bf16, flex32, tf32, f32, f64);
331define_unary_func!(ArcCos, acos, ArcCosOp, f16, bf16, flex32, tf32, f32, f64);
332define_unary_func!(ArcSin, asin, ArcSinOp, f16, bf16, flex32, tf32, f32, f64);
333define_unary_func!(ArcTan, atan, ArcTanOp, f16, bf16, flex32, tf32, f32, f64);
334define_unary_func!(ArcSinh, asinh, ArcSinhOp, f16, bf16, flex32, tf32, f32, f64);
335define_unary_func!(ArcCosh, acosh, ArcCoshOp, f16, bf16, flex32, tf32, f32, f64);
336define_unary_func!(ArcTanh, atanh, ArcTanhOp, f16, bf16, flex32, tf32, f32, f64);
337define_unary_func!(
338 Degrees, to_degrees, DegreesOp, f16, bf16, flex32, tf32, f32, f64
339);
340define_unary_func!(
341 Radians, to_radians, RadiansOp, f16, bf16, flex32, tf32, f32, f64
342);
343define_unary_func!(Sqrt, sqrt, SqrtOp, f16, bf16, flex32, tf32, f32, f64);
344define_unary_func!(
345 InverseSqrt,
346 inverse_sqrt,
347 RsqrtOp,
348 f16,
349 bf16,
350 flex32,
351 tf32,
352 f32,
353 f64
354);
355define_unary_func!(Round, round, RoundOp, f16, bf16, flex32, tf32, f32, f64);
356define_unary_func!(Floor, floor, FloorOp, f16, bf16, flex32, tf32, f32, f64);
357define_unary_func!(Ceil, ceil, CeilOp, f16, bf16, flex32, tf32, f32, f64);
358define_unary_func!(Trunc, trunc, TruncOp, f16, bf16, flex32, tf32, f32, f64);
359define_unary_func!(Erf, erf, ErfOp, f16, bf16, flex32, tf32, f32, f64);
360define_unary_func!(Recip, recip, RecipOp, f16, bf16, flex32, tf32, f32, f64);
361
362define_unary_func_scalar_out!(Magnitude, magnitude);
363impl_unary_func_scalar_out!(f16, bf16, flex32, tf32, f32, f64; Magnitude, magnitude, MagnitudeOp, |scope, input| unary_expand(scope, input, FAbsOp::new));
364
365define_unary_func_scalar_out!(VectorSum, vector_sum);
366impl_unary_func_scalar_out!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; VectorSum, vector_sum, ISumOp, |_, input| input);
367impl_unary_func_scalar_out!(f16, bf16, f32, flex32, tf32, f64; VectorSum, vector_sum, FSumOp, |_, input| input);
368
369impl_normalize!(
370 Normalize,
371 normalize,
372 NormalizeOp,
373 f16,
374 bf16,
375 flex32,
376 tf32,
377 f32,
378 f64
379);
380impl_unary_func_fixed_out_ty!(
381 CountOnes,
382 count_ones,
383 u32,
384 CountOnesOp,
385 u8,
386 i8,
387 u16,
388 i16,
389 u32,
390 i32,
391 u64,
392 i64,
393 usize,
394 isize
395);
396define_unary_func!(
397 ReverseBits,
398 reverse_bits,
399 ReverseBitsOp,
400 u8,
401 i8,
402 u16,
403 i16,
404 u32,
405 i32,
406 u64,
407 i64,
408 usize,
409 isize
410);
411
412impl_unary_func_fixed_out_ty!(
413 LeadingZeros,
414 leading_zeros,
415 u32,
416 LeadingZerosBitsOp,
417 u8,
418 i8,
419 u16,
420 i16,
421 u32,
422 i32,
423 u64,
424 i64,
425 usize,
426 isize
427);
428impl_unary_func_fixed_out_ty!(
429 TrailingZeros,
430 trailing_zeros,
431 u32,
432 TrailingZerosBitsOp,
433 u8,
434 i8,
435 u16,
436 i16,
437 u32,
438 i32,
439 u64,
440 i64,
441 usize,
442 isize
443);
444impl_unary_func_fixed_out_ty!(
445 FindFirstSet,
446 find_first_set,
447 u32,
448 FindFirstSetOp,
449 u8,
450 i8,
451 u16,
452 i16,
453 u32,
454 i32,
455 u64,
456 i64,
457 usize,
458 isize
459);
460impl_unary_func_fixed_out_ty!(
461 IsNan, is_nan, bool, IsNanOp, f16, bf16, flex32, tf32, f32, f64
462);
463impl_unary_func_fixed_out_ty!(
464 IsInf, is_inf, bool, IsInfOp, f16, bf16, flex32, tf32, f32, f64
465);
466
467pub trait FloatBits:
468 CubePrimitive + CubeType<ExpandType: FloatBitsExpand<Bits = Self::Bits>>
469{
470 type Bits: CubePrimitive;
471
472 fn __expand_from_bits(scope: &Scope, bits: NativeExpand<Self::Bits>) -> NativeExpand<Self> {
473 Self::__expand_reinterpret(scope, bits)
474 }
475
476 fn __expand_to_bits(scope: &Scope, this: NativeExpand<Self>) -> NativeExpand<Self::Bits> {
477 <Self::Bits as Reinterpret>::__expand_reinterpret(scope, this)
478 }
479}
480
481pub trait FloatBitsExpand: Sized {
482 type Bits: CubePrimitive;
483
484 fn __expand_to_bits_method(self, scope: &Scope) -> NativeExpand<Self::Bits>;
485}
486
487impl<F: FloatBits> FloatBitsExpand for NativeExpand<F> {
488 type Bits = F::Bits;
489
490 fn __expand_to_bits_method(self, scope: &Scope) -> NativeExpand<Self::Bits> {
491 <Self::Bits as Reinterpret>::__expand_reinterpret(scope, self)
492 }
493}
494
495impl FloatBits for e2m1x2 {
496 type Bits = u8;
497}
498
499impl FloatBits for e5m2 {
500 type Bits = u8;
501}
502
503impl FloatBits for e4m3 {
504 type Bits = u8;
505}
506
507impl FloatBits for f16 {
508 type Bits = u16;
509}
510
511impl FloatBits for bf16 {
512 type Bits = u16;
513}
514
515impl FloatBits for f32 {
516 type Bits = u32;
517}
518
519impl FloatBits for f64 {
520 type Bits = u64;
521}