diff --git a/fearless_simd/src/generated/avx2.rs b/fearless_simd/src/generated/avx2.rs index 078dec14..85e5a553 100644 --- a/fearless_simd/src/generated/avx2.rs +++ b/fearless_simd/src/generated/avx2.rs @@ -561,6 +561,14 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { a.simd_ne(a) } @@ -5252,6 +5260,14 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { a.simd_ne(a) } @@ -7192,6 +7208,14 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x8(self, a: f32x8) -> f32x8 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x8(self, a: f32x8) -> f32x8 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x8(self, a: f32x8) -> mask32x8 { a.simd_ne(a) } @@ -11544,6 +11568,14 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x4(self, a: f64x4) -> f64x4 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x4(self, a: f64x4) -> f64x4 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x4(self, a: f64x4) -> mask64x4 { a.simd_ne(a) } diff --git a/fearless_simd/src/generated/avx512.rs b/fearless_simd/src/generated/avx512.rs index 181573bf..d24e4862 100644 --- a/fearless_simd/src/generated/avx512.rs +++ b/fearless_simd/src/generated/avx512.rs @@ -837,6 +837,14 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { crate::kernel!( #[inline(always)] @@ -5300,6 +5308,14 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { crate::kernel!( #[inline(always)] @@ -7097,6 +7113,14 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x8(self, a: f32x8) -> f32x8 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x8(self, a: f32x8) -> f32x8 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x8(self, a: f32x8) -> mask32x8 { crate::kernel!( #[inline(always)] @@ -11409,6 +11433,14 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x4(self, a: f64x4) -> f64x4 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x4(self, a: f64x4) -> f64x4 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x4(self, a: f64x4) -> mask64x4 { crate::kernel!( #[inline(always)] @@ -13204,6 +13236,14 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x16(self, a: f32x16) -> f32x16 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x16(self, a: f32x16) -> f32x16 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x16(self, a: f32x16) -> mask32x16 { crate::kernel!( #[inline(always)] @@ -17576,6 +17616,14 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x8(self, a: f64x8) -> f64x8 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x8(self, a: f64x8) -> f64x8 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x8(self, a: f64x8) -> mask64x8 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/fallback.rs b/fearless_simd/src/generated/fallback.rs index e2828340..13cc8ac6 100644 --- a/fearless_simd/src/generated/fallback.rs +++ b/fearless_simd/src/generated/fallback.rs @@ -433,6 +433,26 @@ impl Simd for Fallback { .simd_into(self) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + [ + f32::to_degrees(a[0usize]), + f32::to_degrees(a[1usize]), + f32::to_degrees(a[2usize]), + f32::to_degrees(a[3usize]), + ] + .simd_into(self) + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + [ + f32::to_radians(a[0usize]), + f32::to_radians(a[1usize]), + f32::to_radians(a[2usize]), + f32::to_radians(a[3usize]), + ] + .simd_into(self) + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { a.simd_ne(a) } @@ -5725,6 +5745,14 @@ impl Simd for Fallback { [f64::trunc(a[0usize]), f64::trunc(a[1usize])].simd_into(self) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + [f64::to_degrees(a[0usize]), f64::to_degrees(a[1usize])].simd_into(self) + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + [f64::to_radians(a[0usize]), f64::to_radians(a[1usize])].simd_into(self) + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { a.simd_ne(a) } diff --git a/fearless_simd/src/generated/neon.rs b/fearless_simd/src/generated/neon.rs index c0d2b6ac..fd318d7c 100644 --- a/fearless_simd/src/generated/neon.rs +++ b/fearless_simd/src/generated/neon.rs @@ -511,6 +511,14 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { a.simd_ne(a) } @@ -4302,6 +4310,14 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { a.simd_ne(a) } diff --git a/fearless_simd/src/generated/simd_trait.rs b/fearless_simd/src/generated/simd_trait.rs index bc77ada1..2cb21f1c 100644 --- a/fearless_simd/src/generated/simd_trait.rs +++ b/fearless_simd/src/generated/simd_trait.rs @@ -383,6 +383,10 @@ pub trait Simd: fn fract_f32x4(self, a: f32x4) -> f32x4; #[doc = "Return the integer part of each element, rounding towards zero."] fn trunc_f32x4(self, a: f32x4) -> f32x4; + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4; + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + fn to_radians_f32x4(self, a: f32x4) -> f32x4; #[doc = "Return a mask indicating which elements are NaN."] fn is_nan_f32x4(self, a: f32x4) -> mask32x4; #[doc = "Return a mask indicating which elements are positive or negative infinite."] @@ -1662,6 +1666,10 @@ pub trait Simd: fn fract_f64x2(self, a: f64x2) -> f64x2; #[doc = "Return the integer part of each element, rounding towards zero."] fn trunc_f64x2(self, a: f64x2) -> f64x2; + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2; + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + fn to_radians_f64x2(self, a: f64x2) -> f64x2; #[doc = "Return a mask indicating which elements are NaN."] fn is_nan_f64x2(self, a: f64x2) -> mask64x2; #[doc = "Return a mask indicating which elements are positive or negative infinite."] @@ -2455,6 +2463,18 @@ pub trait Simd: let (a0, a1) = self.split_f32x8(a); self.combine_f32x4(self.trunc_f32x4(a0), self.trunc_f32x4(a1)) } + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_degrees_f32x8(self, a: f32x8) -> f32x8 { + let (a0, a1) = self.split_f32x8(a); + self.combine_f32x4(self.to_degrees_f32x4(a0), self.to_degrees_f32x4(a1)) + } + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_radians_f32x8(self, a: f32x8) -> f32x8 { + let (a0, a1) = self.split_f32x8(a); + self.combine_f32x4(self.to_radians_f32x4(a0), self.to_radians_f32x4(a1)) + } #[doc = "Return a mask indicating which elements are NaN."] fn is_nan_f32x8(self, a: f32x8) -> mask32x8; #[doc = "Return a mask indicating which elements are positive or negative infinite."] @@ -5436,6 +5456,18 @@ pub trait Simd: let (a0, a1) = self.split_f64x4(a); self.combine_f64x2(self.trunc_f64x2(a0), self.trunc_f64x2(a1)) } + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_degrees_f64x4(self, a: f64x4) -> f64x4 { + let (a0, a1) = self.split_f64x4(a); + self.combine_f64x2(self.to_degrees_f64x2(a0), self.to_degrees_f64x2(a1)) + } + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_radians_f64x4(self, a: f64x4) -> f64x4 { + let (a0, a1) = self.split_f64x4(a); + self.combine_f64x2(self.to_radians_f64x2(a0), self.to_radians_f64x2(a1)) + } #[doc = "Return a mask indicating which elements are NaN."] fn is_nan_f64x4(self, a: f64x4) -> mask64x4; #[doc = "Return a mask indicating which elements are positive or negative infinite."] @@ -6761,6 +6793,18 @@ pub trait Simd: let (a0, a1) = self.split_f32x16(a); self.combine_f32x8(self.trunc_f32x8(a0), self.trunc_f32x8(a1)) } + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_degrees_f32x16(self, a: f32x16) -> f32x16 { + let (a0, a1) = self.split_f32x16(a); + self.combine_f32x8(self.to_degrees_f32x8(a0), self.to_degrees_f32x8(a1)) + } + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_radians_f32x16(self, a: f32x16) -> f32x16 { + let (a0, a1) = self.split_f32x16(a); + self.combine_f32x8(self.to_radians_f32x8(a0), self.to_radians_f32x8(a1)) + } #[doc = "Return a mask indicating which elements are NaN."] fn is_nan_f32x16(self, a: f32x16) -> mask32x16; #[doc = "Return a mask indicating which elements are positive or negative infinite."] @@ -9745,6 +9789,18 @@ pub trait Simd: let (a0, a1) = self.split_f64x8(a); self.combine_f64x4(self.trunc_f64x4(a0), self.trunc_f64x4(a1)) } + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_degrees_f64x8(self, a: f64x8) -> f64x8 { + let (a0, a1) = self.split_f64x8(a); + self.combine_f64x4(self.to_degrees_f64x4(a0), self.to_degrees_f64x4(a1)) + } + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + #[inline(always)] + fn to_radians_f64x8(self, a: f64x8) -> f64x8 { + let (a0, a1) = self.split_f64x8(a); + self.combine_f64x4(self.to_radians_f64x4(a0), self.to_radians_f64x4(a1)) + } #[doc = "Return a mask indicating which elements are NaN."] fn is_nan_f64x8(self, a: f64x8) -> mask64x8; #[doc = "Return a mask indicating which elements are positive or negative infinite."] @@ -11353,6 +11409,10 @@ pub trait SimdFloat: fn fract(self) -> Self; #[doc = "Return the integer part of each element, rounding towards zero."] fn trunc(self) -> Self; + #[doc = "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + fn to_degrees(self) -> Self; + #[doc = "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next."] + fn to_radians(self) -> Self; #[doc = "Return a mask indicating which elements are NaN."] fn is_nan(self) -> Self::Mask; #[doc = "Return a mask indicating which elements are positive or negative infinite."] diff --git a/fearless_simd/src/generated/simd_types.rs b/fearless_simd/src/generated/simd_types.rs index 9438fb10..f0fdf890 100644 --- a/fearless_simd/src/generated/simd_types.rs +++ b/fearless_simd/src/generated/simd_types.rs @@ -337,6 +337,14 @@ impl crate::SimdFloat for f32x4 { self.simd.trunc_f32x4(self) } #[inline(always)] + fn to_degrees(self) -> Self { + self.simd.to_degrees_f32x4(self) + } + #[inline(always)] + fn to_radians(self) -> Self { + self.simd.to_radians_f32x4(self) + } + #[inline(always)] fn is_nan(self) -> Self::Mask { self.simd.is_nan_f32x4(self) } @@ -3158,6 +3166,14 @@ impl crate::SimdFloat for f64x2 { self.simd.trunc_f64x2(self) } #[inline(always)] + fn to_degrees(self) -> Self { + self.simd.to_degrees_f64x2(self) + } + #[inline(always)] + fn to_radians(self) -> Self { + self.simd.to_radians_f64x2(self) + } + #[inline(always)] fn is_nan(self) -> Self::Mask { self.simd.is_nan_f64x2(self) } @@ -4369,6 +4385,14 @@ impl crate::SimdFloat for f32x8 { self.simd.trunc_f32x8(self) } #[inline(always)] + fn to_degrees(self) -> Self { + self.simd.to_degrees_f32x8(self) + } + #[inline(always)] + fn to_radians(self) -> Self { + self.simd.to_radians_f32x8(self) + } + #[inline(always)] fn is_nan(self) -> Self::Mask { self.simd.is_nan_f32x8(self) } @@ -7229,6 +7253,14 @@ impl crate::SimdFloat for f64x4 { self.simd.trunc_f64x4(self) } #[inline(always)] + fn to_degrees(self) -> Self { + self.simd.to_degrees_f64x4(self) + } + #[inline(always)] + fn to_radians(self) -> Self { + self.simd.to_radians_f64x4(self) + } + #[inline(always)] fn is_nan(self) -> Self::Mask { self.simd.is_nan_f64x4(self) } @@ -8435,6 +8467,14 @@ impl crate::SimdFloat for f32x16 { self.simd.trunc_f32x16(self) } #[inline(always)] + fn to_degrees(self) -> Self { + self.simd.to_degrees_f32x16(self) + } + #[inline(always)] + fn to_radians(self) -> Self { + self.simd.to_radians_f32x16(self) + } + #[inline(always)] fn is_nan(self) -> Self::Mask { self.simd.is_nan_f32x16(self) } @@ -11379,6 +11419,14 @@ impl crate::SimdFloat for f64x8 { self.simd.trunc_f64x8(self) } #[inline(always)] + fn to_degrees(self) -> Self { + self.simd.to_degrees_f64x8(self) + } + #[inline(always)] + fn to_radians(self) -> Self { + self.simd.to_radians_f64x8(self) + } + #[inline(always)] fn is_nan(self) -> Self::Mask { self.simd.is_nan_f64x8(self) } diff --git a/fearless_simd/src/generated/sse2.rs b/fearless_simd/src/generated/sse2.rs index 2407528c..efd1ba5d 100644 --- a/fearless_simd/src/generated/sse2.rs +++ b/fearless_simd/src/generated/sse2.rs @@ -571,6 +571,14 @@ impl Simd for Sse2 { .simd_into(self) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { a.simd_ne(a) } @@ -5711,6 +5719,14 @@ impl Simd for Sse2 { [f64::trunc(a[0usize]), f64::trunc(a[1usize])].simd_into(self) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { a.simd_ne(a) } diff --git a/fearless_simd/src/generated/sse4_2.rs b/fearless_simd/src/generated/sse4_2.rs index 117f1a80..d220cdad 100644 --- a/fearless_simd/src/generated/sse4_2.rs +++ b/fearless_simd/src/generated/sse4_2.rs @@ -553,6 +553,14 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { a.simd_ne(a) } @@ -5226,6 +5234,14 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { a.simd_ne(a) } diff --git a/fearless_simd/src/generated/wasm.rs b/fearless_simd/src/generated/wasm.rs index b97fee85..f52da8ab 100644 --- a/fearless_simd/src/generated/wasm.rs +++ b/fearless_simd/src/generated/wasm.rs @@ -360,6 +360,14 @@ impl Simd for WasmSimd128 { f32x4_trunc(a.into()).simd_into(self) } #[inline(always)] + fn to_degrees_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f32x4(self, a: f32x4) -> f32x4 { + a * const { f32::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f32x4(self, a: f32x4) -> mask32x4 { a.simd_ne(a) } @@ -3125,6 +3133,14 @@ impl Simd for WasmSimd128 { f64x2_trunc(a.into()).simd_into(self) } #[inline(always)] + fn to_degrees_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_degrees(1.0) } + } + #[inline(always)] + fn to_radians_f64x2(self, a: f64x2) -> f64x2 { + a * const { f64::to_radians(1.0) } + } + #[inline(always)] fn is_nan_f64x2(self, a: f64x2) -> mask64x2 { a.simd_ne(a) } diff --git a/fearless_simd_gen/src/arch/fallback.rs b/fearless_simd_gen/src/arch/fallback.rs index 48ead357..03de8381 100644 --- a/fearless_simd_gen/src/arch/fallback.rs +++ b/fearless_simd_gen/src/arch/fallback.rs @@ -29,6 +29,8 @@ pub(crate) fn translate_op(op: &str, is_float: bool) -> Option<&'static str> { "fract" => "fract", "trunc" => "trunc", "sqrt" => "sqrt", + "to_degrees" => "to_degrees", + "to_radians" => "to_radians", "add" => { if is_float { "add" diff --git a/fearless_simd_gen/src/generic.rs b/fearless_simd_gen/src/generic.rs index 3f257dff..1ceb20eb 100644 --- a/fearless_simd_gen/src/generic.rs +++ b/fearless_simd_gen/src/generic.rs @@ -796,3 +796,26 @@ pub(crate) fn generic_round(method_sig: TokenStream, vec_ty: &VecType) -> TokenS } } } + +pub(crate) fn generic_to_degrees_radians( + method_sig: TokenStream, + method: &str, + vec_ty: &VecType, +) -> TokenStream { + assert_eq!(vec_ty.scalar, ScalarType::Float); + + let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits); + + // Use the constant from std, as they may offer more precision. + let factor_expr = match method { + "to_degrees" => quote! { #scalar::to_degrees(1.0) }, + "to_radians" => quote! { #scalar::to_radians(1.0) }, + _ => unimplemented!(), + }; + + quote! { + #method_sig { + a * const { #factor_expr } + } + } +} diff --git a/fearless_simd_gen/src/mk_neon.rs b/fearless_simd_gen/src/mk_neon.rs index a8234051..f40c5910 100644 --- a/fearless_simd_gen/src/mk_neon.rs +++ b/fearless_simd_gen/src/mk_neon.rs @@ -6,8 +6,8 @@ use quote::{ToTokens as _, format_ident, quote}; use crate::generic::{ count_zeros_method, fallback_method, generic_classify, generic_mask_set, generic_op_name, - integer_lane_mask_rotate, integer_lane_mask_splat_arg, reverse_method, - reverse_vector_mask_method, + generic_to_degrees_radians, integer_lane_mask_rotate, integer_lane_mask_splat_arg, + reverse_method, reverse_vector_mask_method, }; use crate::level::Level; use crate::ops::{NarrowingMode, Op, SlideGranularity, relaxed_narrow_method}; @@ -253,6 +253,10 @@ impl Level for Neon { return self.handle_count_ones(op, vec_ty); } + if matches!(method, "to_degrees" | "to_radians") { + return generic_to_degrees_radians(method_sig, method, vec_ty); + } + let args = [quote! { a.into() }]; let expr = neon::expr(method, vec_ty, &args); diff --git a/fearless_simd_gen/src/mk_wasm.rs b/fearless_simd_gen/src/mk_wasm.rs index 128d16d1..ecb3c57a 100644 --- a/fearless_simd_gen/src/mk_wasm.rs +++ b/fearless_simd_gen/src/mk_wasm.rs @@ -8,8 +8,8 @@ use crate::arch::wasm::{arch_prefix, v128_intrinsic}; use crate::generic::{ concat_swizzle_dyn_precise_body, count_zeros_method, fallback_method, generic_block_combine, generic_block_split, generic_classify, generic_mask_set, generic_op_name, generic_round, - integer_lane_mask_rotate, integer_lane_mask_splat_arg, recursive_swizzle_dyn_precise_body, - reverse_method, reverse_vector_mask_method, + generic_to_degrees_radians, integer_lane_mask_rotate, integer_lane_mask_splat_arg, + recursive_swizzle_dyn_precise_body, reverse_method, reverse_vector_mask_method, }; use crate::level::Level; use crate::ops::{ @@ -516,6 +516,10 @@ impl Level for WasmSimd128 { return generic_round(method_sig, vec_ty); } + if matches!(method, "to_degrees" | "to_radians") { + return generic_to_degrees_radians(method_sig, method, vec_ty); + } + let args = [quote! { a.into() }]; let expr = if matches!(method, "fract") { assert_eq!( diff --git a/fearless_simd_gen/src/mk_x86.rs b/fearless_simd_gen/src/mk_x86.rs index d58ca877..adc059c2 100644 --- a/fearless_simd_gen/src/mk_x86.rs +++ b/fearless_simd_gen/src/mk_x86.rs @@ -9,8 +9,9 @@ use crate::arch::x86::{ use crate::generic::{ concat_swizzle_dyn_precise_body, count_zeros_method, fallback_method, generic_block_combine, generic_block_split, generic_classify, generic_mask_from_bitmask, generic_mask_set, - generic_op_name, generic_round, integer_lane_mask_rotate, integer_lane_mask_splat_arg, - recursive_swizzle_dyn_precise_body, reverse_method, reverse_vector_mask_method, + generic_op_name, generic_round, generic_to_degrees_radians, integer_lane_mask_rotate, + integer_lane_mask_splat_arg, recursive_swizzle_dyn_precise_body, reverse_method, + reverse_vector_mask_method, }; use crate::level::Level; use crate::ops::{ @@ -2058,6 +2059,7 @@ impl X86 { match method { "round" => generic_round(method_sig, vec_ty), + "to_degrees" | "to_radians" => generic_to_degrees_radians(method_sig, method, vec_ty), "fract" => { let trunc_op = generic_op_name("trunc", vec_ty); quote! { diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index bfc4aa58..916239a0 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -1042,6 +1042,18 @@ const FLOAT_OPS: &[Op] = &[ OpSig::Unary, "Return the integer part of each element, rounding towards zero.", ), + Op::new( + "to_degrees", + OpKind::VecTraitMethod, + OpSig::Unary, + "Converts radians to degrees.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next.", + ), + Op::new( + "to_radians", + OpKind::VecTraitMethod, + OpSig::Unary, + "Converts degrees to radians.\n\nThe precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next.", + ), Op::new( "is_nan", OpKind::VecTraitMethod, diff --git a/fearless_simd_tests/tests/harness/ops/mod.rs b/fearless_simd_tests/tests/harness/ops/mod.rs index 1c2e44cf..f44766f2 100644 --- a/fearless_simd_tests/tests/harness/ops/mod.rs +++ b/fearless_simd_tests/tests/harness/ops/mod.rs @@ -103,6 +103,7 @@ mod swizzle_dyn_within_blocks; mod to_array; mod to_bitmask; mod to_bytes; +mod to_degrees_radians; mod trunc; mod unzip_high; mod unzip_low; diff --git a/fearless_simd_tests/tests/harness/ops/to_degrees_radians.rs b/fearless_simd_tests/tests/harness/ops/to_degrees_radians.rs new file mode 100644 index 00000000..77375310 --- /dev/null +++ b/fearless_simd_tests/tests/harness/ops/to_degrees_radians.rs @@ -0,0 +1,73 @@ +// Copyright 2026 the Fearless_SIMD Authors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use fearless_simd::*; +use fearless_simd_dev_macros::simd_test; + +use std::{f32, f64}; + +const VALUES_F32: &[f32] = &[ + 0.0, + 1.0, + -1.0, + 45.0, + 180.0, + 360.0, + f32::consts::PI, + f32::consts::FRAC_PI_2, + 0.0, + 1.0, + -1.0, + 45.0, + 180.0, + 360.0, + f32::consts::PI, + f32::consts::FRAC_PI_2, +]; +const VALUES_F64: &[f64] = &[ + 0.0, + 1.0, + -1.0, + 45.0, + 180.0, + 360.0, + f64::consts::PI, + f64::consts::FRAC_PI_2, +]; + +#[simd_test] +fn test_f32x4(simd: S) { + let a = f32x4::::from_slice(simd, &VALUES_F32[..f32x4::::LEN]); + assert_eq!(*(a.to_degrees()), a.map(f32::to_degrees)); + assert_eq!(*(a.to_radians()), a.map(f32::to_radians)); +} +#[simd_test] +fn test_f32x8(simd: S) { + let a = f32x8::::from_slice(simd, &VALUES_F32[..f32x8::::LEN]); + assert_eq!(*(a.to_degrees()), a.map(f32::to_degrees)); + assert_eq!(*(a.to_radians()), a.map(f32::to_radians)); +} +#[simd_test] +fn test_f32x16(simd: S) { + let a = f32x16::::from_slice(simd, &VALUES_F32[..f32x16::::LEN]); + assert_eq!(*(a.to_degrees()), a.map(f32::to_degrees)); + assert_eq!(*(a.to_radians()), a.map(f32::to_radians)); +} +#[simd_test] +fn test_f64x2(simd: S) { + let a = f64x2::::from_slice(simd, &VALUES_F64[..f64x2::::LEN]); + assert_eq!(*(a.to_degrees()), a.map(f64::to_degrees)); + assert_eq!(*(a.to_radians()), a.map(f64::to_radians)); +} +#[simd_test] +fn test_f64x4(simd: S) { + let a = f64x4::::from_slice(simd, &VALUES_F64[..f64x4::::LEN]); + assert_eq!(*(a.to_degrees()), a.map(f64::to_degrees)); + assert_eq!(*(a.to_radians()), a.map(f64::to_radians)); +} +#[simd_test] +fn test_f64x8(simd: S) { + let a = f64x8::::from_slice(simd, &VALUES_F64[..f64x8::::LEN]); + assert_eq!(*(a.to_degrees()), a.map(f64::to_degrees)); + assert_eq!(*(a.to_radians()), a.map(f64::to_radians)); +}