From f00d8bdaf3b6273b646d024eca3c8320acbb891e Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 6 Sep 2026 16:38:32 +0100 Subject: [PATCH] Move abs() from SimdFloat to SimdBase, implement it on integers --- fearless_simd/src/generated/avx2.rs | 164 ++++-- fearless_simd/src/generated/avx512.rs | 240 ++++++--- fearless_simd/src/generated/fallback.rs | 78 ++- fearless_simd/src/generated/neon.rs | 80 ++- fearless_simd/src/generated/simd_trait.rs | 176 ++++-- fearless_simd/src/generated/simd_types.rs | 144 ++++- fearless_simd/src/generated/sse2.rs | 90 +++- fearless_simd/src/generated/sse4_2.rs | 82 ++- fearless_simd/src/generated/wasm.rs | 32 +- fearless_simd_gen/src/arch/fallback.rs | 8 +- fearless_simd_gen/src/arch/x86.rs | 4 + fearless_simd_gen/src/level.rs | 4 +- fearless_simd_gen/src/mk_simd_trait.rs | 10 +- fearless_simd_gen/src/mk_x86.rs | 21 + fearless_simd_gen/src/ops.rs | 16 +- fearless_simd_tests/tests/generics.rs | 5 + fearless_simd_tests/tests/harness/ops/abs.rs | 532 +++++++++++++++++++ 17 files changed, 1441 insertions(+), 245 deletions(-) diff --git a/fearless_simd/src/generated/avx2.rs b/fearless_simd/src/generated/avx2.rs index 818690cc..b318ae31 100644 --- a/fearless_simd/src/generated/avx2.rs +++ b/fearless_simd/src/generated/avx2.rs @@ -116,6 +116,16 @@ impl Simd for Avx2 { unsafe { vectorize_avx2(f) } } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: f32x4) -> f32x4 { + _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { crate::kernel!( #[inline(always)] @@ -148,16 +158,6 @@ impl Simd for Avx2 { }) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx2, a: f32x4) -> f32x4 { - _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -730,6 +730,16 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i8x16) -> i8x16 { + _mm_abs_epi8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { crate::kernel!( #[inline(always)] @@ -2096,6 +2106,16 @@ impl Simd for Avx2 { kernel(self, a, b) } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i16x8) -> i16x8 { + _mm_abs_epi16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { crate::kernel!( #[inline(always)] @@ -3399,6 +3419,16 @@ impl Simd for Avx2 { kernel(self, a, b) } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i32x4) -> i32x4 { + _mm_abs_epi32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { crate::kernel!( #[inline(always)] @@ -4672,6 +4702,16 @@ impl Simd for Avx2 { kernel(self, a, b) } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: f64x2) -> f64x2 { + _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { crate::kernel!( #[inline(always)] @@ -4704,16 +4744,6 @@ impl Simd for Avx2 { }) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx2, a: f64x2) -> f64x2 { - _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5280,6 +5310,18 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i64x2) -> i64x2 { + let a = a.into(); + let mask = _mm_cmpgt_epi64(_mm_setzero_si128(), a); + _mm_sub_epi64(_mm_xor_si128(a, mask), mask).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { crate::kernel!( #[inline(always)] @@ -6457,6 +6499,16 @@ impl Simd for Avx2 { kernel(self, a, b) } #[inline(always)] + fn abs_f32x8(self, a: f32x8) -> f32x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: f32x8) -> f32x8 { + _mm256_andnot_ps(_mm256_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x8(self, val: f32) -> f32x8 { crate::kernel!( #[inline(always)] @@ -6512,16 +6564,6 @@ impl Simd for Avx2 { }) } #[inline(always)] - fn abs_f32x8(self, a: f32x8) -> f32x8 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx2, a: f32x8) -> f32x8 { - _mm256_andnot_ps(_mm256_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x8(self, a: f32x8) -> f32x8 { crate::kernel!( #[inline(always)] @@ -6962,6 +7004,16 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_i8x32(self, a: i8x32) -> i8x32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i8x32) -> i8x32 { + _mm256_abs_epi8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x32(self, val: i8) -> i8x32 { crate::kernel!( #[inline(always)] @@ -8240,6 +8292,16 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_i16x16(self, a: i16x16) -> i16x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i16x16) -> i16x16 { + _mm256_abs_epi16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x16(self, val: i16) -> i16x16 { crate::kernel!( #[inline(always)] @@ -9449,6 +9511,16 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_i32x8(self, a: i32x8) -> i32x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i32x8) -> i32x8 { + _mm256_abs_epi32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x8(self, val: i32) -> i32x8 { crate::kernel!( #[inline(always)] @@ -10628,6 +10700,16 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_f64x4(self, a: f64x4) -> f64x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: f64x4) -> f64x4 { + _mm256_andnot_pd(_mm256_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x4(self, val: f64) -> f64x4 { crate::kernel!( #[inline(always)] @@ -10683,16 +10765,6 @@ impl Simd for Avx2 { }) } #[inline(always)] - fn abs_f64x4(self, a: f64x4) -> f64x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx2, a: f64x4) -> f64x4 { - _mm256_andnot_pd(_mm256_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x4(self, a: f64x4) -> f64x4 { crate::kernel!( #[inline(always)] @@ -11166,6 +11238,18 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn abs_i64x4(self, a: i64x4) -> i64x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i64x4) -> i64x4 { + let a = a.into(); + let mask = _mm256_cmpgt_epi64(_mm256_setzero_si256(), a); + _mm256_sub_epi64(_mm256_xor_si256(a, mask), mask).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x4(self, val: i64) -> i64x4 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/avx512.rs b/fearless_simd/src/generated/avx512.rs index dd51f985..80d731e8 100644 --- a/fearless_simd/src/generated/avx512.rs +++ b/fearless_simd/src/generated/avx512.rs @@ -390,6 +390,16 @@ impl Simd for Avx512 { unsafe { vectorize_avx512(f) } } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f32x4) -> f32x4 { + _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { crate::kernel!( #[inline(always)] @@ -422,16 +432,6 @@ impl Simd for Avx512 { }) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx512, a: f32x4) -> f32x4 { - _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -949,6 +949,16 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i8x16) -> i8x16 { + _mm_abs_epi8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { crate::kernel!( #[inline(always)] @@ -2206,6 +2216,16 @@ impl Simd for Avx512 { } } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i16x8) -> i16x8 { + _mm_abs_epi16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { crate::kernel!( #[inline(always)] @@ -3365,6 +3385,16 @@ impl Simd for Avx512 { } } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i32x4) -> i32x4 { + _mm_abs_epi32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { crate::kernel!( #[inline(always)] @@ -4522,6 +4552,16 @@ impl Simd for Avx512 { } } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f64x2) -> f64x2 { + _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { crate::kernel!( #[inline(always)] @@ -4554,16 +4594,6 @@ impl Simd for Avx512 { }) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx512, a: f64x2) -> f64x2 { - _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5071,6 +5101,16 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i64x2) -> i64x2 { + _mm_abs_epi64(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { crate::kernel!( #[inline(always)] @@ -6149,6 +6189,16 @@ impl Simd for Avx512 { } } #[inline(always)] + fn abs_f32x8(self, a: f32x8) -> f32x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f32x8) -> f32x8 { + _mm256_andnot_ps(_mm256_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x8(self, val: f32) -> f32x8 { crate::kernel!( #[inline(always)] @@ -6221,16 +6271,6 @@ impl Simd for Avx512 { }) } #[inline(always)] - fn abs_f32x8(self, a: f32x8) -> f32x8 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx512, a: f32x8) -> f32x8 { - _mm256_andnot_ps(_mm256_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x8(self, a: f32x8) -> f32x8 { crate::kernel!( #[inline(always)] @@ -6683,6 +6723,16 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn abs_i8x32(self, a: i8x32) -> i8x32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i8x32) -> i8x32 { + _mm256_abs_epi8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x32(self, val: i8) -> i8x32 { crate::kernel!( #[inline(always)] @@ -7900,6 +7950,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_i16x16(self, a: i16x16) -> i16x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i16x16) -> i16x16 { + _mm256_abs_epi16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x16(self, val: i16) -> i16x16 { crate::kernel!( #[inline(always)] @@ -9021,6 +9081,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_i32x8(self, a: i32x8) -> i32x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i32x8) -> i32x8 { + _mm256_abs_epi32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x8(self, val: i32) -> i32x8 { crate::kernel!( #[inline(always)] @@ -10140,6 +10210,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_f64x4(self, a: f64x4) -> f64x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f64x4) -> f64x4 { + _mm256_andnot_pd(_mm256_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x4(self, val: f64) -> f64x4 { crate::kernel!( #[inline(always)] @@ -10212,16 +10292,6 @@ impl Simd for Avx512 { }) } #[inline(always)] - fn abs_f64x4(self, a: f64x4) -> f64x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx512, a: f64x4) -> f64x4 { - _mm256_andnot_pd(_mm256_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x4(self, a: f64x4) -> f64x4 { crate::kernel!( #[inline(always)] @@ -10661,6 +10731,16 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn abs_i64x4(self, a: i64x4) -> i64x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i64x4) -> i64x4 { + _mm256_abs_epi64(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x4(self, val: i64) -> i64x4 { crate::kernel!( #[inline(always)] @@ -11733,6 +11813,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_f32x16(self, a: f32x16) -> f32x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f32x16) -> f32x16 { + _mm512_andnot_ps(_mm512_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x16(self, val: f32) -> f32x16 { crate::kernel!( #[inline(always)] @@ -11808,16 +11898,6 @@ impl Simd for Avx512 { }) } #[inline(always)] - fn abs_f32x16(self, a: f32x16) -> f32x16 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx512, a: f32x16) -> f32x16 { - _mm512_andnot_ps(_mm512_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x16(self, a: f32x16) -> f32x16 { crate::kernel!( #[inline(always)] @@ -12292,6 +12372,16 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn abs_i8x64(self, a: i8x64) -> i8x64 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i8x64) -> i8x64 { + _mm512_abs_epi8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x64(self, val: i8) -> i8x64 { crate::kernel!( #[inline(always)] @@ -13521,6 +13611,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_i16x32(self, a: i16x32) -> i16x32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i16x32) -> i16x32 { + _mm512_abs_epi16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x32(self, val: i16) -> i16x32 { crate::kernel!( #[inline(always)] @@ -14656,6 +14756,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_i32x16(self, a: i32x16) -> i32x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i32x16) -> i32x16 { + _mm512_abs_epi32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x16(self, val: i32) -> i32x16 { crate::kernel!( #[inline(always)] @@ -15796,6 +15906,16 @@ impl Simd for Avx512 { ) } #[inline(always)] + fn abs_f64x8(self, a: f64x8) -> f64x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f64x8) -> f64x8 { + _mm512_andnot_pd(_mm512_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x8(self, val: f64) -> f64x8 { crate::kernel!( #[inline(always)] @@ -15871,16 +15991,6 @@ impl Simd for Avx512 { }) } #[inline(always)] - fn abs_f64x8(self, a: f64x8) -> f64x8 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Avx512, a: f64x8) -> f64x8 { - _mm512_andnot_pd(_mm512_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x8(self, a: f64x8) -> f64x8 { crate::kernel!( #[inline(always)] @@ -16330,6 +16440,16 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn abs_i64x8(self, a: i64x8) -> i64x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i64x8) -> i64x8 { + _mm512_abs_epi64(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x8(self, val: i64) -> i64x8 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/fallback.rs b/fearless_simd/src/generated/fallback.rs index 8b7aab99..08805d4f 100644 --- a/fearless_simd/src/generated/fallback.rs +++ b/fearless_simd/src/generated/fallback.rs @@ -198,6 +198,16 @@ impl Simd for Fallback { vectorize_inner(f) } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + [ + f32::abs(a[0usize]), + f32::abs(a[1usize]), + f32::abs(a[2usize]), + f32::abs(a[3usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { [val; 4usize].simd_into(self) } @@ -213,16 +223,6 @@ impl Simd for Fallback { dest.simd_into(self) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - [ - f32::abs(a[0usize]), - f32::abs(a[1usize]), - f32::abs(a[2usize]), - f32::abs(a[3usize]), - ] - .simd_into(self) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { [ f32::neg(a[0usize]), @@ -625,6 +625,28 @@ impl Simd for Fallback { .simd_into(self) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + [ + i8::wrapping_abs(a[0usize]), + i8::wrapping_abs(a[1usize]), + i8::wrapping_abs(a[2usize]), + i8::wrapping_abs(a[3usize]), + i8::wrapping_abs(a[4usize]), + i8::wrapping_abs(a[5usize]), + i8::wrapping_abs(a[6usize]), + i8::wrapping_abs(a[7usize]), + i8::wrapping_abs(a[8usize]), + i8::wrapping_abs(a[9usize]), + i8::wrapping_abs(a[10usize]), + i8::wrapping_abs(a[11usize]), + i8::wrapping_abs(a[12usize]), + i8::wrapping_abs(a[13usize]), + i8::wrapping_abs(a[14usize]), + i8::wrapping_abs(a[15usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { [val; 16usize].simd_into(self) } @@ -2883,6 +2905,20 @@ impl Simd for Fallback { result.simd_into(self) } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + [ + i16::wrapping_abs(a[0usize]), + i16::wrapping_abs(a[1usize]), + i16::wrapping_abs(a[2usize]), + i16::wrapping_abs(a[3usize]), + i16::wrapping_abs(a[4usize]), + i16::wrapping_abs(a[5usize]), + i16::wrapping_abs(a[6usize]), + i16::wrapping_abs(a[7usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { [val; 8usize].simd_into(self) } @@ -4378,6 +4414,16 @@ impl Simd for Fallback { result.simd_into(self) } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + [ + i32::wrapping_abs(a[0usize]), + i32::wrapping_abs(a[1usize]), + i32::wrapping_abs(a[2usize]), + i32::wrapping_abs(a[3usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { [val; 4usize].simd_into(self) } @@ -5367,6 +5413,10 @@ impl Simd for Fallback { result.simd_into(self) } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + [f64::abs(a[0usize]), f64::abs(a[1usize])].simd_into(self) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { [val; 2usize].simd_into(self) } @@ -5382,10 +5432,6 @@ impl Simd for Fallback { dest.simd_into(self) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - [f64::abs(a[0usize]), f64::abs(a[1usize])].simd_into(self) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { [f64::neg(a[0usize]), f64::neg(a[1usize])].simd_into(self) } @@ -5681,6 +5727,10 @@ impl Simd for Fallback { [a[0usize] as i64, a[1usize] as i64].simd_into(self) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + [i64::wrapping_abs(a[0usize]), i64::wrapping_abs(a[1usize])].simd_into(self) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { [val; 2usize].simd_into(self) } diff --git a/fearless_simd/src/generated/neon.rs b/fearless_simd/src/generated/neon.rs index afe41495..7a887338 100644 --- a/fearless_simd/src/generated/neon.rs +++ b/fearless_simd/src/generated/neon.rs @@ -109,6 +109,16 @@ impl Simd for Neon { unsafe { vectorize_neon(f) } } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: f32x4) -> f32x4 { + vabsq_f32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { crate::kernel!( #[inline(always)] @@ -141,16 +151,6 @@ impl Simd for Neon { }) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Neon, a: f32x4) -> f32x4 { - vabsq_f32(a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -580,6 +580,16 @@ impl Simd for Neon { self.cvt_i32_f32x4(a) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i8x16) -> i8x16 { + vabsq_s8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { crate::kernel!( #[inline(always)] @@ -1612,6 +1622,16 @@ impl Simd for Neon { } } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i16x8) -> i16x8 { + vabsq_s16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { crate::kernel!( #[inline(always)] @@ -2665,6 +2685,16 @@ impl Simd for Neon { } } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i32x4) -> i32x4 { + vabsq_s32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { crate::kernel!( #[inline(always)] @@ -3737,6 +3767,16 @@ impl Simd for Neon { } } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: f64x2) -> f64x2 { + vabsq_f64(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { crate::kernel!( #[inline(always)] @@ -3769,16 +3809,6 @@ impl Simd for Neon { }) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Neon, a: f64x2) -> f64x2 { - vabsq_f64(a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -4211,6 +4241,16 @@ impl Simd for Neon { self.cvt_i64_f64x2(a) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i64x2) -> i64x2 { + vabsq_s64(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/simd_trait.rs b/fearless_simd/src/generated/simd_trait.rs index 03488ae7..a89691dc 100644 --- a/fearless_simd/src/generated/simd_trait.rs +++ b/fearless_simd/src/generated/simd_trait.rs @@ -213,6 +213,8 @@ pub trait Simd: #[doc = r" assert_eq!(values, [2, 4, 6, 8, 10]);"] #[doc = r" ```"] fn vectorize R, R>(self, f: F) -> R; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs_f32x4(self, a: f32x4) -> f32x4; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_f32x4(self, val: f32) -> f32x4; #[doc = "Reverse the order of the vector's elements."] @@ -243,8 +245,6 @@ pub trait Simd: fn swizzle_dyn_precise_f32x4(self, a: f32x4, indices: u8x16) -> f32x4 { Bytes::from_bytes(self.swizzle_dyn_precise_u8x16(Bytes::to_bytes(a), indices)) } - #[doc = "Compute the absolute value of each element."] - fn abs_f32x4(self, a: f32x4) -> f32x4; #[doc = "Negate each element of the vector."] fn neg_f32x4(self, a: f32x4) -> f32x4; #[doc = "Compute the square root of each element.\n\nNegative elements other than `-0.0` will become NaN."] @@ -351,6 +351,8 @@ pub trait Simd: fn cvt_i32_f32x4(self, a: f32x4) -> i32x4; #[doc = "Convert each floating-point element to a signed 32-bit integer, truncating towards zero.\n\nOut-of-range values are saturated to the closest in-range value. NaN becomes 0."] fn cvt_i32_precise_f32x4(self, a: f32x4) -> i32x4; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs_i8x16(self, a: i8x16) -> i8x16; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_i8x16(self, val: i8) -> i8x16; #[doc = "Reverse the order of the vector's elements."] @@ -469,6 +471,11 @@ pub trait Simd: ) -> (); #[doc = "Widen every lane into two same-width vectors.\n\nThe first result contains the widened lower lanes and the second contains the widened upper lanes."] fn widen_i8x16(self, a: i8x16) -> (i16x8, i16x8); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u8x16(self, a: u8x16) -> u8x16 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_u8x16(self, val: u8) -> u8x16; #[doc = "Reverse the order of the vector's elements."] @@ -623,6 +630,8 @@ pub trait Simd: fn all_false_mask8x16(self, a: mask8x16) -> bool; #[doc = "Combine two vectors into a single vector with twice the width.\n\n`a` provides the lower elements and `b` provides the upper elements."] fn combine_mask8x16(self, a: mask8x16, b: mask8x16) -> mask8x32; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs_i16x8(self, a: i16x8) -> i16x8; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_i16x8(self, val: i16) -> i16x8; #[doc = "Reverse the order of the vector's elements."] @@ -747,6 +756,11 @@ pub trait Simd: fn saturating_narrow_i16x8(self, a: i16x8, b: i16x8) -> i8x16; #[doc = "Narrow the lanes of two vectors using the cheapest operation for the active SIMD backend and concatenate them into one same-width vector.\n\nInputs must fit in the destination type; in debug mode this function will panic if any of the inputs do not fit. Out-of-range results in release builds produce arbitrary values (but remain memory-safe).\n\n`a` provides the lower result lanes and `b` provides the upper result lanes."] fn relaxed_narrow_i16x8(self, a: i16x8, b: i16x8) -> i8x16; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u16x8(self, a: u16x8) -> u16x8 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_u16x8(self, val: u16) -> u16x8; #[doc = "Reverse the order of the vector's elements."] @@ -916,6 +930,8 @@ pub trait Simd: fn all_false_mask16x8(self, a: mask16x8) -> bool; #[doc = "Combine two vectors into a single vector with twice the width.\n\n`a` provides the lower elements and `b` provides the upper elements."] fn combine_mask16x8(self, a: mask16x8, b: mask16x8) -> mask16x16; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs_i32x4(self, a: i32x4) -> i32x4; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_i32x4(self, val: i32) -> i32x4; #[doc = "Reverse the order of the vector's elements."] @@ -1042,6 +1058,11 @@ pub trait Simd: fn relaxed_narrow_i32x4(self, a: i32x4, b: i32x4) -> i16x8; #[doc = "Convert each signed 32-bit integer element to a floating-point value.\n\nValues that cannot be exactly represented are rounded to the nearest representable value."] fn cvt_f32_i32x4(self, a: i32x4) -> f32x4; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u32x4(self, a: u32x4) -> u32x4 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_u32x4(self, val: u32) -> u32x4; #[doc = "Reverse the order of the vector's elements."] @@ -1213,6 +1234,8 @@ pub trait Simd: fn all_false_mask32x4(self, a: mask32x4) -> bool; #[doc = "Combine two vectors into a single vector with twice the width.\n\n`a` provides the lower elements and `b` provides the upper elements."] fn combine_mask32x4(self, a: mask32x4, b: mask32x4) -> mask32x8; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs_f64x2(self, a: f64x2) -> f64x2; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_f64x2(self, val: f64) -> f64x2; #[doc = "Reverse the order of the vector's elements."] @@ -1243,8 +1266,6 @@ pub trait Simd: fn swizzle_dyn_precise_f64x2(self, a: f64x2, indices: u8x16) -> f64x2 { Bytes::from_bytes(self.swizzle_dyn_precise_u8x16(Bytes::to_bytes(a), indices)) } - #[doc = "Compute the absolute value of each element."] - fn abs_f64x2(self, a: f64x2) -> f64x2; #[doc = "Negate each element of the vector."] fn neg_f64x2(self, a: f64x2) -> f64x2; #[doc = "Compute the square root of each element.\n\nNegative elements other than `-0.0` will become NaN."] @@ -1355,6 +1376,8 @@ pub trait Simd: fn cvt_i64_f64x2(self, a: f64x2) -> i64x2; #[doc = "Convert each floating-point element to a signed 64-bit integer, truncating towards zero.\n\nOut-of-range values are saturated to the closest in-range value. NaN becomes 0."] fn cvt_i64_precise_f64x2(self, a: f64x2) -> i64x2; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs_i64x2(self, a: i64x2) -> i64x2; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_i64x2(self, val: i64) -> i64x2; #[doc = "Reverse the order of the vector's elements."] @@ -1479,6 +1502,11 @@ pub trait Simd: fn relaxed_narrow_i64x2(self, a: i64x2, b: i64x2) -> i32x4; #[doc = "Convert each signed 64-bit integer element to a floating-point value.\n\nValues that cannot be exactly represented are rounded to the nearest representable value."] fn cvt_f64_i64x2(self, a: i64x2) -> f64x2; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u64x2(self, a: u64x2) -> u64x2 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat_u64x2(self, val: u64) -> u64x2; #[doc = "Reverse the order of the vector's elements."] @@ -1648,6 +1676,12 @@ pub trait Simd: fn all_false_mask64x2(self, a: mask64x2) -> bool; #[doc = "Combine two vectors into a single vector with twice the width.\n\n`a` provides the lower elements and `b` provides the upper elements."] fn combine_mask64x2(self, a: mask64x2, b: mask64x2) -> mask64x4; + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_f32x8(self, a: f32x8) -> f32x8 { + let (a0, a1) = self.split_f32x8(a); + self.combine_f32x4(self.abs_f32x4(a0), self.abs_f32x4(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_f32x8(self, val: f32) -> f32x8 { @@ -1691,12 +1725,6 @@ pub trait Simd: fn swizzle_dyn_precise_f32x8(self, a: f32x8, indices: u8x32) -> f32x8 { Bytes::from_bytes(self.swizzle_dyn_precise_u8x32(Bytes::to_bytes(a), indices)) } - #[doc = "Compute the absolute value of each element."] - #[inline(always)] - fn abs_f32x8(self, a: f32x8) -> f32x8 { - let (a0, a1) = self.split_f32x8(a); - self.combine_f32x4(self.abs_f32x4(a0), self.abs_f32x4(a1)) - } #[doc = "Negate each element of the vector."] #[inline(always)] fn neg_f32x8(self, a: f32x8) -> f32x8 { @@ -2037,6 +2065,12 @@ pub trait Simd: self.cvt_i32_precise_f32x4(a1), ) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i8x32(self, a: i8x32) -> i8x32 { + let (a0, a1) = self.split_i8x32(a); + self.combine_i8x16(self.abs_i8x16(a0), self.abs_i8x16(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i8x32(self, val: i8) -> i8x32 { @@ -2337,6 +2371,11 @@ pub trait Simd: let (a10, a11) = self.widen_i8x16(a1); (self.combine_i16x8(a00, a01), self.combine_i16x8(a10, a11)) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u8x32(self, a: u8x32) -> u8x32 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u8x32(self, val: u8) -> u8x32 { @@ -2747,6 +2786,12 @@ pub trait Simd: fn combine_mask8x32(self, a: mask8x32, b: mask8x32) -> mask8x64; #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask8x32(self, a: mask8x32) -> (mask8x16, mask8x16); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i16x16(self, a: i16x16) -> i16x16 { + let (a0, a1) = self.split_i16x16(a); + self.combine_i16x8(self.abs_i16x8(a0), self.abs_i16x8(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i16x16(self, val: i16) -> i16x16 { @@ -3078,6 +3123,11 @@ pub trait Simd: self.relaxed_narrow_i16x8(b0, b1), ) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u16x16(self, a: u16x16) -> u16x16 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u16x16(self, val: u16) -> u16x16 { @@ -3520,6 +3570,12 @@ pub trait Simd: fn combine_mask16x16(self, a: mask16x16, b: mask16x16) -> mask16x32; #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask16x16(self, a: mask16x16) -> (mask16x8, mask16x8); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i32x8(self, a: i32x8) -> i32x8 { + let (a0, a1) = self.split_i32x8(a); + self.combine_i32x4(self.abs_i32x4(a0), self.abs_i32x4(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i32x8(self, val: i32) -> i32x8 { @@ -3853,6 +3909,11 @@ pub trait Simd: let (a0, a1) = self.split_i32x8(a); self.combine_f32x4(self.cvt_f32_i32x4(a0), self.cvt_f32_i32x4(a1)) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u32x8(self, a: u32x8) -> u32x8 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u32x8(self, val: u32) -> u32x8 { @@ -4297,6 +4358,12 @@ pub trait Simd: fn combine_mask32x8(self, a: mask32x8, b: mask32x8) -> mask32x16; #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask32x8(self, a: mask32x8) -> (mask32x4, mask32x4); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_f64x4(self, a: f64x4) -> f64x4 { + let (a0, a1) = self.split_f64x4(a); + self.combine_f64x2(self.abs_f64x2(a0), self.abs_f64x2(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_f64x4(self, val: f64) -> f64x4 { @@ -4340,12 +4407,6 @@ pub trait Simd: fn swizzle_dyn_precise_f64x4(self, a: f64x4, indices: u8x32) -> f64x4 { Bytes::from_bytes(self.swizzle_dyn_precise_u8x32(Bytes::to_bytes(a), indices)) } - #[doc = "Compute the absolute value of each element."] - #[inline(always)] - fn abs_f64x4(self, a: f64x4) -> f64x4 { - let (a0, a1) = self.split_f64x4(a); - self.combine_f64x2(self.abs_f64x2(a0), self.abs_f64x2(a1)) - } #[doc = "Negate each element of the vector."] #[inline(always)] fn neg_f64x4(self, a: f64x4) -> f64x4 { @@ -4705,6 +4766,12 @@ pub trait Simd: self.cvt_i64_precise_f64x2(a1), ) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i64x4(self, a: i64x4) -> i64x4 { + let (a0, a1) = self.split_i64x4(a); + self.combine_i64x2(self.abs_i64x2(a0), self.abs_i64x2(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i64x4(self, val: i64) -> i64x4 { @@ -5030,6 +5097,11 @@ pub trait Simd: let (a0, a1) = self.split_i64x4(a); self.combine_f64x2(self.cvt_f64_i64x2(a0), self.cvt_f64_i64x2(a1)) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u64x4(self, a: u64x4) -> u64x4 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u64x4(self, val: u64) -> u64x4 { @@ -5466,6 +5538,12 @@ pub trait Simd: fn combine_mask64x4(self, a: mask64x4, b: mask64x4) -> mask64x8; #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask64x4(self, a: mask64x4) -> (mask64x2, mask64x2); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_f32x16(self, a: f32x16) -> f32x16 { + let (a0, a1) = self.split_f32x16(a); + self.combine_f32x8(self.abs_f32x8(a0), self.abs_f32x8(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_f32x16(self, val: f32) -> f32x16 { @@ -5513,12 +5591,6 @@ pub trait Simd: fn swizzle_dyn_precise_f32x16(self, a: f32x16, indices: u8x64) -> f32x16 { Bytes::from_bytes(self.swizzle_dyn_precise_u8x64(Bytes::to_bytes(a), indices)) } - #[doc = "Compute the absolute value of each element."] - #[inline(always)] - fn abs_f32x16(self, a: f32x16) -> f32x16 { - let (a0, a1) = self.split_f32x16(a); - self.combine_f32x8(self.abs_f32x8(a0), self.abs_f32x8(a1)) - } #[doc = "Negate each element of the vector."] #[inline(always)] fn neg_f32x16(self, a: f32x16) -> f32x16 { @@ -5867,6 +5939,12 @@ pub trait Simd: self.cvt_i32_precise_f32x8(a1), ) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i8x64(self, a: i8x64) -> i8x64 { + let (a0, a1) = self.split_i8x64(a); + self.combine_i8x32(self.abs_i8x32(a0), self.abs_i8x32(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i8x64(self, val: i8) -> i8x64 { @@ -6165,6 +6243,11 @@ pub trait Simd: let (a10, a11) = self.widen_i8x32(a1); (self.combine_i16x16(a00, a01), self.combine_i16x16(a10, a11)) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u8x64(self, a: u8x64) -> u8x64 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u8x64(self, val: u8) -> u8x64 { @@ -6571,6 +6654,12 @@ pub trait Simd: } #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask8x64(self, a: mask8x64) -> (mask8x32, mask8x32); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i16x32(self, a: i16x32) -> i16x32 { + let (a0, a1) = self.split_i16x32(a); + self.combine_i16x16(self.abs_i16x16(a0), self.abs_i16x16(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i16x32(self, val: i16) -> i16x32 { @@ -6906,6 +6995,11 @@ pub trait Simd: self.relaxed_narrow_i16x16(b0, b1), ) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u16x32(self, a: u16x32) -> u16x32 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u16x32(self, val: u16) -> u16x32 { @@ -7353,6 +7447,12 @@ pub trait Simd: } #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask16x32(self, a: mask16x32) -> (mask16x16, mask16x16); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i32x16(self, a: i32x16) -> i32x16 { + let (a0, a1) = self.split_i32x16(a); + self.combine_i32x8(self.abs_i32x8(a0), self.abs_i32x8(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i32x16(self, val: i32) -> i32x16 { @@ -7688,6 +7788,11 @@ pub trait Simd: let (a0, a1) = self.split_i32x16(a); self.combine_f32x8(self.cvt_f32_i32x8(a0), self.cvt_f32_i32x8(a1)) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u32x16(self, a: u32x16) -> u32x16 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u32x16(self, val: u32) -> u32x16 { @@ -8132,6 +8237,12 @@ pub trait Simd: } #[doc = "Split a vector into two vectors of half the width.\n\nReturns a tuple of (lower half, upper half)."] fn split_mask32x16(self, a: mask32x16) -> (mask32x8, mask32x8); + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_f64x8(self, a: f64x8) -> f64x8 { + let (a0, a1) = self.split_f64x8(a); + self.combine_f64x4(self.abs_f64x4(a0), self.abs_f64x4(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_f64x8(self, val: f64) -> f64x8 { @@ -8175,12 +8286,6 @@ pub trait Simd: fn swizzle_dyn_precise_f64x8(self, a: f64x8, indices: u8x64) -> f64x8 { Bytes::from_bytes(self.swizzle_dyn_precise_u8x64(Bytes::to_bytes(a), indices)) } - #[doc = "Compute the absolute value of each element."] - #[inline(always)] - fn abs_f64x8(self, a: f64x8) -> f64x8 { - let (a0, a1) = self.split_f64x8(a); - self.combine_f64x4(self.abs_f64x4(a0), self.abs_f64x4(a1)) - } #[doc = "Negate each element of the vector."] #[inline(always)] fn neg_f64x8(self, a: f64x8) -> f64x8 { @@ -8538,6 +8643,12 @@ pub trait Simd: self.cvt_i64_precise_f64x4(a1), ) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_i64x8(self, a: i64x8) -> i64x8 { + let (a0, a1) = self.split_i64x8(a); + self.combine_i64x4(self.abs_i64x4(a0), self.abs_i64x4(a1)) + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_i64x8(self, val: i64) -> i64x8 { @@ -8861,6 +8972,11 @@ pub trait Simd: let (a0, a1) = self.split_i64x8(a); self.combine_f64x4(self.cvt_f64_i64x4(a0), self.cvt_f64_i64x4(a1)) } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + #[inline(always)] + fn abs_u64x8(self, a: u64x8) -> u64x8 { + a + } #[doc = "Create a SIMD vector with all elements set to the given value."] #[inline(always)] fn splat_u64x8(self, val: u64) -> u64x8 { @@ -9845,6 +9961,8 @@ pub trait SimdBase: _ => unreachable!(), } } + #[doc = "Compute the absolute value of each element.\n\nUnsigned integers are unchanged. Signed integers use wrapping absolute value: the minimum representable value remains unchanged. This matches `i32::abs()`.\n\nFor floating-point elements, clear the sign bit, preserving all other bits. For example, negative zero becomes positive zero."] + fn abs(self) -> Self; #[doc = "Create a SIMD vector with all elements set to the given value."] fn splat(simd: S, val: Self::Element) -> Self; #[doc = "Reverse the order of the vector's elements."] @@ -9935,8 +10053,6 @@ pub trait SimdFloat: fn to_int_precise>(self) -> T { T::truncate_from_precise(self) } - #[doc = "Compute the absolute value of each element."] - fn abs(self) -> Self; #[doc = "Compute the square root of each element.\n\nNegative elements other than `-0.0` will become NaN."] fn sqrt(self) -> Self; #[doc = "Compute an approximate reciprocal (`1. / x`) for each element.\n\nThis uses a fast hardware estimate where available, and falls back to exact division otherwise.\n\nOn x86 for `f32`, this has a relative error less than `1.5 × 2^-12`. On `AArch64` (`f32` and `f64`), this has a relative error less than `2^-8`. The precision of this operation may change as new platform support is added."] diff --git a/fearless_simd/src/generated/simd_types.rs b/fearless_simd/src/generated/simd_types.rs index 41f137be..0ad8de4a 100644 --- a/fearless_simd/src/generated/simd_types.rs +++ b/fearless_simd/src/generated/simd_types.rs @@ -155,6 +155,10 @@ impl SimdBase for f32x4 { .swizzle_dyn_precise_f32x4(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_f32x4(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_f32x4(self) } @@ -244,10 +248,6 @@ impl SimdBase for f32x4 { } } impl crate::SimdFloat for f32x4 { - #[inline(always)] - fn abs(self) -> Self { - self.simd.abs_f32x4(self) - } #[inline(always)] fn sqrt(self) -> Self { self.simd.sqrt_f32x4(self) @@ -509,6 +509,10 @@ impl SimdBase for i8x16 { .swizzle_dyn_precise_i8x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i8x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i8x16(self) } @@ -811,6 +815,10 @@ impl SimdBase for u8x16 { .swizzle_dyn_precise_u8x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u8x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u8x16(self) } @@ -1211,6 +1219,10 @@ impl SimdBase for i16x8 { .swizzle_dyn_precise_i16x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i16x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i16x8(self) } @@ -1520,6 +1532,10 @@ impl SimdBase for u16x8 { .swizzle_dyn_precise_u16x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u16x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u16x8(self) } @@ -1923,6 +1939,10 @@ impl SimdBase for i32x4 { .swizzle_dyn_precise_i32x4(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i32x4(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i32x4(self) } @@ -2232,6 +2252,10 @@ impl SimdBase for u32x4 { .swizzle_dyn_precise_u32x4(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u32x4(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u32x4(self) } @@ -2647,6 +2671,10 @@ impl SimdBase for f64x2 { .swizzle_dyn_precise_f64x2(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_f64x2(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_f64x2(self) } @@ -2736,10 +2764,6 @@ impl SimdBase for f64x2 { } } impl crate::SimdFloat for f64x2 { - #[inline(always)] - fn abs(self) -> Self { - self.simd.abs_f64x2(self) - } #[inline(always)] fn sqrt(self) -> Self { self.simd.sqrt_f64x2(self) @@ -2989,6 +3013,10 @@ impl SimdBase for i64x2 { .swizzle_dyn_precise_i64x2(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i64x2(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i64x2(self) } @@ -3291,6 +3319,10 @@ impl SimdBase for u64x2 { .swizzle_dyn_precise_u64x2(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u64x2(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u64x2(self) } @@ -3711,6 +3743,10 @@ impl SimdBase for f32x8 { .swizzle_dyn_precise_f32x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_f32x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_f32x8(self) } @@ -3800,10 +3836,6 @@ impl SimdBase for f32x8 { } } impl crate::SimdFloat for f32x8 { - #[inline(always)] - fn abs(self) -> Self { - self.simd.abs_f32x8(self) - } #[inline(always)] fn sqrt(self) -> Self { self.simd.sqrt_f32x8(self) @@ -4076,6 +4108,10 @@ impl SimdBase for i8x32 { .swizzle_dyn_precise_i8x32(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i8x32(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i8x32(self) } @@ -4389,6 +4425,10 @@ impl SimdBase for u8x32 { .swizzle_dyn_precise_u8x32(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u8x32(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u8x32(self) } @@ -4792,6 +4832,10 @@ impl SimdBase for i16x16 { .swizzle_dyn_precise_i16x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i16x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i16x16(self) } @@ -5105,6 +5149,10 @@ impl SimdBase for u16x16 { .swizzle_dyn_precise_u16x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u16x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u16x16(self) } @@ -5516,6 +5564,10 @@ impl SimdBase for i32x8 { .swizzle_dyn_precise_i32x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i32x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i32x8(self) } @@ -5832,6 +5884,10 @@ impl SimdBase for u32x8 { .swizzle_dyn_precise_u32x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u32x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u32x8(self) } @@ -6242,6 +6298,10 @@ impl SimdBase for f64x4 { .swizzle_dyn_precise_f64x4(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_f64x4(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_f64x4(self) } @@ -6331,10 +6391,6 @@ impl SimdBase for f64x4 { } } impl crate::SimdFloat for f64x4 { - #[inline(always)] - fn abs(self) -> Self { - self.simd.abs_f64x4(self) - } #[inline(always)] fn sqrt(self) -> Self { self.simd.sqrt_f64x4(self) @@ -6579,6 +6635,10 @@ impl SimdBase for i64x4 { .swizzle_dyn_precise_i64x4(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i64x4(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i64x4(self) } @@ -6876,6 +6936,10 @@ impl SimdBase for u64x4 { .swizzle_dyn_precise_u64x4(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u64x4(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u64x4(self) } @@ -7300,6 +7364,10 @@ impl SimdBase for f32x16 { .swizzle_dyn_precise_f32x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_f32x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_f32x16(self) } @@ -7390,10 +7458,6 @@ impl SimdBase for f32x16 { } } impl crate::SimdFloat for f32x16 { - #[inline(always)] - fn abs(self) -> Self { - self.simd.abs_f32x16(self) - } #[inline(always)] fn sqrt(self) -> Self { self.simd.sqrt_f32x16(self) @@ -7692,6 +7756,10 @@ impl SimdBase for i8x64 { .swizzle_dyn_precise_i8x64(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i8x64(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i8x64(self) } @@ -8031,6 +8099,10 @@ impl SimdBase for u8x64 { .swizzle_dyn_precise_u8x64(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u8x64(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u8x64(self) } @@ -8444,6 +8516,10 @@ impl SimdBase for i16x32 { .swizzle_dyn_precise_i16x32(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i16x32(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i16x32(self) } @@ -8767,6 +8843,10 @@ impl SimdBase for u16x32 { .swizzle_dyn_precise_u16x32(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u16x32(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u16x32(self) } @@ -9180,6 +9260,10 @@ impl SimdBase for i32x16 { .swizzle_dyn_precise_i32x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i32x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i32x16(self) } @@ -9499,6 +9583,10 @@ impl SimdBase for u32x16 { .swizzle_dyn_precise_u32x16(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u32x16(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u32x16(self) } @@ -9916,6 +10004,10 @@ impl SimdBase for f64x8 { .swizzle_dyn_precise_f64x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_f64x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_f64x8(self) } @@ -10005,10 +10097,6 @@ impl SimdBase for f64x8 { } } impl crate::SimdFloat for f64x8 { - #[inline(always)] - fn abs(self) -> Self { - self.simd.abs_f64x8(self) - } #[inline(always)] fn sqrt(self) -> Self { self.simd.sqrt_f64x8(self) @@ -10259,6 +10347,10 @@ impl SimdBase for i64x8 { .swizzle_dyn_precise_i64x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_i64x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_i64x8(self) } @@ -10562,6 +10654,10 @@ impl SimdBase for u64x8 { .swizzle_dyn_precise_u64x8(self, indices.simd_into(self.simd)) } #[inline(always)] + fn abs(self) -> Self { + self.simd.abs_u64x8(self) + } + #[inline(always)] fn reverse(self) -> Self { self.simd.reverse_u64x8(self) } diff --git a/fearless_simd/src/generated/sse2.rs b/fearless_simd/src/generated/sse2.rs index 11f47293..01328053 100644 --- a/fearless_simd/src/generated/sse2.rs +++ b/fearless_simd/src/generated/sse2.rs @@ -212,6 +212,16 @@ impl Simd for Sse2 { unsafe { vectorize_sse2(f) } } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: f32x4) -> f32x4 { + _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { crate::kernel!( #[inline(always)] @@ -242,16 +252,6 @@ impl Simd for Sse2 { }) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Sse2, a: f32x4) -> f32x4 { - _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -809,6 +809,28 @@ impl Simd for Sse2 { .simd_into(self) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + [ + i8::wrapping_abs(a[0usize]), + i8::wrapping_abs(a[1usize]), + i8::wrapping_abs(a[2usize]), + i8::wrapping_abs(a[3usize]), + i8::wrapping_abs(a[4usize]), + i8::wrapping_abs(a[5usize]), + i8::wrapping_abs(a[6usize]), + i8::wrapping_abs(a[7usize]), + i8::wrapping_abs(a[8usize]), + i8::wrapping_abs(a[9usize]), + i8::wrapping_abs(a[10usize]), + i8::wrapping_abs(a[11usize]), + i8::wrapping_abs(a[12usize]), + i8::wrapping_abs(a[13usize]), + i8::wrapping_abs(a[14usize]), + i8::wrapping_abs(a[15usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { crate::kernel!( #[inline(always)] @@ -2449,6 +2471,20 @@ impl Simd for Sse2 { } } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + [ + i16::wrapping_abs(a[0usize]), + i16::wrapping_abs(a[1usize]), + i16::wrapping_abs(a[2usize]), + i16::wrapping_abs(a[3usize]), + i16::wrapping_abs(a[4usize]), + i16::wrapping_abs(a[5usize]), + i16::wrapping_abs(a[6usize]), + i16::wrapping_abs(a[7usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { crate::kernel!( #[inline(always)] @@ -3825,6 +3861,16 @@ impl Simd for Sse2 { } } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + [ + i32::wrapping_abs(a[0usize]), + i32::wrapping_abs(a[1usize]), + i32::wrapping_abs(a[2usize]), + i32::wrapping_abs(a[3usize]), + ] + .simd_into(self) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { crate::kernel!( #[inline(always)] @@ -5183,6 +5229,16 @@ impl Simd for Sse2 { } } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: f64x2) -> f64x2 { + _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5213,16 +5269,6 @@ impl Simd for Sse2 { }) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Sse2, a: f64x2) -> f64x2 { - _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5712,6 +5758,10 @@ impl Simd for Sse2 { [a[0usize] as i64, a[1usize] as i64].simd_into(self) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + [i64::wrapping_abs(a[0usize]), i64::wrapping_abs(a[1usize])].simd_into(self) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/sse4_2.rs b/fearless_simd/src/generated/sse4_2.rs index ff9bc6cc..823bf451 100644 --- a/fearless_simd/src/generated/sse4_2.rs +++ b/fearless_simd/src/generated/sse4_2.rs @@ -190,6 +190,16 @@ impl Simd for Sse4_2 { unsafe { vectorize_sse4_2(f) } } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: f32x4) -> f32x4 { + _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { crate::kernel!( #[inline(always)] @@ -222,16 +232,6 @@ impl Simd for Sse4_2 { }) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Sse4_2, a: f32x4) -> f32x4 { - _mm_andnot_ps(_mm_set1_ps(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -880,6 +880,16 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: i8x16) -> i8x16 { + _mm_abs_epi8(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { crate::kernel!( #[inline(always)] @@ -2253,6 +2263,16 @@ impl Simd for Sse4_2 { } } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: i16x8) -> i16x8 { + _mm_abs_epi16(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { crate::kernel!( #[inline(always)] @@ -3555,6 +3575,16 @@ impl Simd for Sse4_2 { } } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: i32x4) -> i32x4 { + _mm_abs_epi32(a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { crate::kernel!( #[inline(always)] @@ -4819,6 +4849,16 @@ impl Simd for Sse4_2 { } } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: f64x2) -> f64x2 { + _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { crate::kernel!( #[inline(always)] @@ -4851,16 +4891,6 @@ impl Simd for Sse4_2 { }) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - crate::kernel!( - #[inline(always)] - fn kernel(token: Sse4_2, a: f64x2) -> f64x2 { - _mm_andnot_pd(_mm_set1_pd(-0.0), a.into()).simd_into(token) - } - ); - kernel(self, a) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5452,6 +5482,18 @@ impl Simd for Sse4_2 { [a[0usize] as i64, a[1usize] as i64].simd_into(self) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: i64x2) -> i64x2 { + let a = a.into(); + let mask = _mm_cmpgt_epi64(_mm_setzero_si128(), a); + _mm_sub_epi64(_mm_xor_si128(a, mask), mask).simd_into(token) + } + ); + kernel(self, a) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/wasm.rs b/fearless_simd/src/generated/wasm.rs index 0fad5c79..64189dcf 100644 --- a/fearless_simd/src/generated/wasm.rs +++ b/fearless_simd/src/generated/wasm.rs @@ -200,6 +200,10 @@ impl Simd for WasmSimd128 { vectorize_inner(f) } #[inline(always)] + fn abs_f32x4(self, a: f32x4) -> f32x4 { + f32x4_abs(a.into()).simd_into(self) + } + #[inline(always)] fn splat_f32x4(self, val: f32) -> f32x4 { f32x4_splat(val).simd_into(self) } @@ -225,10 +229,6 @@ impl Simd for WasmSimd128 { }) } #[inline(always)] - fn abs_f32x4(self, a: f32x4) -> f32x4 { - f32x4_abs(a.into()).simd_into(self) - } - #[inline(always)] fn neg_f32x4(self, a: f32x4) -> f32x4 { f32x4_neg(a.into()).simd_into(self) } @@ -545,6 +545,10 @@ impl Simd for WasmSimd128 { i32x4_trunc_sat_f32x4(a.into()).simd_into(self) } #[inline(always)] + fn abs_i8x16(self, a: i8x16) -> i8x16 { + i8x16_abs(a.into()).simd_into(self) + } + #[inline(always)] fn splat_i8x16(self, val: i8) -> i8x16 { i8x16_splat(val).simd_into(self) } @@ -1436,6 +1440,10 @@ impl Simd for WasmSimd128 { } } #[inline(always)] + fn abs_i16x8(self, a: i16x8) -> i16x8 { + i16x8_abs(a.into()).simd_into(self) + } + #[inline(always)] fn splat_i16x8(self, val: i16) -> i16x8 { i16x8_splat(val).simd_into(self) } @@ -2143,6 +2151,10 @@ impl Simd for WasmSimd128 { } } #[inline(always)] + fn abs_i32x4(self, a: i32x4) -> i32x4 { + i32x4_abs(a.into()).simd_into(self) + } + #[inline(always)] fn splat_i32x4(self, val: i32) -> i32x4 { i32x4_splat(val).simd_into(self) } @@ -2834,6 +2846,10 @@ impl Simd for WasmSimd128 { } } #[inline(always)] + fn abs_f64x2(self, a: f64x2) -> f64x2 { + f64x2_abs(a.into()).simd_into(self) + } + #[inline(always)] fn splat_f64x2(self, val: f64) -> f64x2 { f64x2_splat(val).simd_into(self) } @@ -2859,10 +2875,6 @@ impl Simd for WasmSimd128 { }) } #[inline(always)] - fn abs_f64x2(self, a: f64x2) -> f64x2 { - f64x2_abs(a.into()).simd_into(self) - } - #[inline(always)] fn neg_f64x2(self, a: f64x2) -> f64x2 { f64x2_neg(a.into()).simd_into(self) } @@ -3151,6 +3163,10 @@ impl Simd for WasmSimd128 { [a[0usize] as i64, a[1usize] as i64].simd_into(self) } #[inline(always)] + fn abs_i64x2(self, a: i64x2) -> i64x2 { + i64x2_abs(a.into()).simd_into(self) + } + #[inline(always)] fn splat_i64x2(self, val: i64) -> i64x2 { i64x2_splat(val).simd_into(self) } diff --git a/fearless_simd_gen/src/arch/fallback.rs b/fearless_simd_gen/src/arch/fallback.rs index 158e7940..d06b0638 100644 --- a/fearless_simd_gen/src/arch/fallback.rs +++ b/fearless_simd_gen/src/arch/fallback.rs @@ -7,7 +7,13 @@ use quote::quote; pub(crate) fn translate_op(op: &str, is_float: bool) -> Option<&'static str> { Some(match op { - "abs" => "abs", + "abs" => { + if is_float { + "abs" + } else { + "wrapping_abs" + } + } "copysign" => "copysign", "neg" => { if is_float { diff --git a/fearless_simd_gen/src/arch/x86.rs b/fearless_simd_gen/src/arch/x86.rs index b0971565..41611e70 100644 --- a/fearless_simd_gen/src/arch/x86.rs +++ b/fearless_simd_gen/src/arch/x86.rs @@ -71,6 +71,10 @@ pub(crate) fn expr(op: &str, ty: &VecType, args: &[TokenStream]) -> TokenStream } _ => unreachable!(), }, + "abs" if ty.scalar == ScalarType::Int => { + let intrinsic = simple_intrinsic("abs", ty); + quote! { #intrinsic( #( #args ),* ) } + } "abs" => { let set1 = set1_intrinsic(ty); let andnot = simple_intrinsic("andnot", ty); diff --git a/fearless_simd_gen/src/level.rs b/fearless_simd_gen/src/level.rs index 97c2e017..0e74bf13 100644 --- a/fearless_simd_gen/src/level.rs +++ b/fearless_simd_gen/src/level.rs @@ -137,7 +137,9 @@ pub(crate) trait Level { let mut methods = vec![]; for vec_ty in SIMD_TYPES { for op in ops_for_type(vec_ty) { - if op.sig.should_route_swizzle_through_bytes(vec_ty) + // Unsigned absolute value uses the identity default at every width. + if (op.method == "abs" && vec_ty.scalar == ScalarType::Unsigned) + || op.sig.should_route_swizzle_through_bytes(vec_ty) || op.reversed_compare_method().is_some() || self.should_use_generic_op(&op, vec_ty) { diff --git a/fearless_simd_gen/src/mk_simd_trait.rs b/fearless_simd_gen/src/mk_simd_trait.rs index fa0ff91f..c40d42be 100644 --- a/fearless_simd_gen/src/mk_simd_trait.rs +++ b/fearless_simd_gen/src/mk_simd_trait.rs @@ -24,7 +24,15 @@ pub(crate) fn mk_simd_trait() -> TokenStream { let doc_alias = op .doc_alias() .map(|alias| quote! { #[doc(alias = #alias)] }); - if op.sig.should_route_swizzle_through_bytes(vec_ty) { + if op.method == "abs" && vec_ty.scalar == ScalarType::Unsigned { + methods.extend(quote! { + #[doc = #doc] + #[inline(always)] + #method_sig { + a + } + }); + } else if op.sig.should_route_swizzle_through_bytes(vec_ty) { let method = byte_swizzle_op(&op, vec_ty); methods.extend(quote! { #[doc = #doc] diff --git a/fearless_simd_gen/src/mk_x86.rs b/fearless_simd_gen/src/mk_x86.rs index 589415c8..8061ab79 100644 --- a/fearless_simd_gen/src/mk_x86.rs +++ b/fearless_simd_gen/src/mk_x86.rs @@ -1833,6 +1833,27 @@ impl X86 { method: &str, vec_ty: &VecType, ) -> TokenStream { + if method == "abs" && vec_ty.scalar == ScalarType::Int { + if *self == Self::Sse2 { + return fallback_method(op, vec_ty); + } + if vec_ty.scalar_bits == 64 && *self != Self::Avx512 { + // Packed i64 abs requires AVX-512. With an all-ones mask for + // negative lanes, (a ^ mask) - mask computes wrapping abs. + let zero = intrinsic_ident("setzero", coarse_type(vec_ty), vec_ty.n_bits()); + let cmpgt = simple_intrinsic("cmpgt", vec_ty); + let xor = intrinsic_ident("xor", coarse_type(vec_ty), vec_ty.n_bits()); + let sub = simple_intrinsic("sub", vec_ty); + return self.kernel_method(op, vec_ty, |token| { + quote! { + let a = a.into(); + let mask = #cmpgt(#zero(), a); + #sub(#xor(a, mask), mask).simd_into(#token) + } + }); + } + } + if method == "reverse" { if vec_ty.scalar == ScalarType::Mask { if *self == Self::Avx512 { diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index 3d62fc99..fb22cfb7 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -557,6 +557,16 @@ fn splat_arg_ty(vec_ty: &VecType) -> TokenStream { } const BASE_OPS: &[Op] = &[ + Op::new( + "abs", + OpKind::BaseTraitMethod, + OpSig::Unary, + "Compute the absolute value of each element.\n\n\ + Unsigned integers are unchanged. Signed integers use wrapping absolute value: \ + the minimum representable value remains unchanged. This matches `i32::abs()`.\n\n\ + For floating-point elements, clear the sign bit, preserving all other bits. \ + For example, negative zero becomes positive zero.", + ), Op::new( "splat", OpKind::BaseTraitMethod, @@ -846,12 +856,6 @@ const MASK_REPRESENTATION_OPS: &[Op] = &[ ]; const FLOAT_OPS: &[Op] = &[ - Op::new( - "abs", - OpKind::VecTraitMethod, - OpSig::Unary, - "Compute the absolute value of each element.", - ), Op::new( "neg", OpKind::Overloaded(CoreOpTrait::Neg), diff --git a/fearless_simd_tests/tests/generics.rs b/fearless_simd_tests/tests/generics.rs index 2db33e88..2fd69532 100644 --- a/fearless_simd_tests/tests/generics.rs +++ b/fearless_simd_tests/tests/generics.rs @@ -36,6 +36,11 @@ fn generic_i64_to_f64(x: S::i64s) -> S::f64s { x.to_float() } +// Ensure absolute value is available with only a numeric base trait bound. +fn generic_abs>(value: V) -> V { + value.abs() +} + // Ensure that integer operations exposed through `SimdInt` are available to generic code. fn generic_saturating_add>(lhs: V, rhs: V) -> V { lhs.saturating_add(rhs) diff --git a/fearless_simd_tests/tests/harness/ops/abs.rs b/fearless_simd_tests/tests/harness/ops/abs.rs index 50d3e713..88327f39 100644 --- a/fearless_simd_tests/tests/harness/ops/abs.rs +++ b/fearless_simd_tests/tests/harness/ops/abs.rs @@ -103,3 +103,535 @@ fn abs_f64x8_special_bit_patterns(simd: S) { assert_eq!(result_bits, expected); } + +#[simd_test] +fn abs_i8x16(simd: S) { + let max = i8::MAX; + let min = i8::MIN; + let a = i8x16::from_slice( + simd, + &[ + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + ], + ); + let expected = [ + min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i8x16(a), expected); +} + +#[simd_test] +fn abs_i8x32(simd: S) { + let max = i8::MAX; + let min = i8::MIN; + let a = i8x32::from_slice( + simd, + &[ + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + ], + ); + let expected = [ + min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, + 42, min, max, max, 0, 1, 1, 42, 42, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i8x32(a), expected); +} + +#[simd_test] +fn abs_i8x64(simd: S) { + let max = i8::MAX; + let min = i8::MIN; + let a = i8x64::from_slice( + simd, + &[ + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + ], + ); + let expected = [ + min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, + 42, min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, + 42, 42, min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i8x64(a), expected); +} + +#[simd_test] +fn abs_i16x8(simd: S) { + let max = i16::MAX; + let min = i16::MIN; + let a = i16x8::from_slice(simd, &[min, min + 1, max, 0, -1, 1, -42, 42]); + let expected = [min, max, max, 0, 1, 1, 42, 42]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i16x8(a), expected); +} + +#[simd_test] +fn abs_i16x16(simd: S) { + let max = i16::MAX; + let min = i16::MIN; + let a = i16x16::from_slice( + simd, + &[ + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + ], + ); + let expected = [ + min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i16x16(a), expected); +} + +#[simd_test] +fn abs_i16x32(simd: S) { + let max = i16::MAX; + let min = i16::MIN; + let a = i16x32::from_slice( + simd, + &[ + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + ], + ); + let expected = [ + min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, + 42, min, max, max, 0, 1, 1, 42, 42, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i16x32(a), expected); +} + +#[simd_test] +fn abs_i32x4(simd: S) { + let max = i32::MAX; + let min = i32::MIN; + let a = i32x4::from_slice(simd, &[min, min + 1, max, 0]); + let expected = [min, max, max, 0]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i32x4(a), expected); + let a = i32x4::from_slice(simd, &[-1, 1, -42, 42]); + let expected = [1, 1, 42, 42]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i32x4(a), expected); +} + +#[simd_test] +fn abs_i32x8(simd: S) { + let max = i32::MAX; + let min = i32::MIN; + let a = i32x8::from_slice(simd, &[min, min + 1, max, 0, -1, 1, -42, 42]); + let expected = [min, max, max, 0, 1, 1, 42, 42]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i32x8(a), expected); +} + +#[simd_test] +fn abs_i32x16(simd: S) { + let max = i32::MAX; + let min = i32::MIN; + let a = i32x16::from_slice( + simd, + &[ + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + min, + min + 1, + max, + 0, + -1, + 1, + -42, + 42, + ], + ); + let expected = [ + min, max, max, 0, 1, 1, 42, 42, min, max, max, 0, 1, 1, 42, 42, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i32x16(a), expected); +} + +#[simd_test] +fn abs_i64x2(simd: S) { + let max = i64::MAX; + let min = i64::MIN; + let a = i64x2::from_slice(simd, &[min, min + 1]); + let expected = [min, max]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x2(a), expected); + let a = i64x2::from_slice(simd, &[max, 0]); + let expected = [max, 0]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x2(a), expected); + let a = i64x2::from_slice(simd, &[-1, 1]); + let expected = [1, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x2(a), expected); + let a = i64x2::from_slice(simd, &[-42, 42]); + let expected = [42, 42]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x2(a), expected); +} + +#[simd_test] +fn abs_i64x4(simd: S) { + let max = i64::MAX; + let min = i64::MIN; + let a = i64x4::from_slice(simd, &[min, min + 1, max, 0]); + let expected = [min, max, max, 0]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x4(a), expected); + let a = i64x4::from_slice(simd, &[-1, 1, -42, 42]); + let expected = [1, 1, 42, 42]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x4(a), expected); +} + +#[simd_test] +fn abs_i64x8(simd: S) { + let max = i64::MAX; + let min = i64::MIN; + let a = i64x8::from_slice(simd, &[min, min + 1, max, 0, -1, 1, -42, 42]); + let expected = [min, max, max, 0, 1, 1, 42, 42]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_i64x8(a), expected); +} + +#[simd_test] +fn abs_u8x16(simd: S) { + let max = u8::MAX; + let high_bit = 1 << (u8::BITS - 1); + let a = u8x16::from_slice( + simd, + &[ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ], + ); + let expected = [ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u8x16(a), expected); +} + +#[simd_test] +fn abs_u8x32(simd: S) { + let max = u8::MAX; + let high_bit = 1 << (u8::BITS - 1); + let a = u8x32::from_slice( + simd, + &[ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, + max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ], + ); + let expected = [ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, + high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u8x32(a), expected); +} + +#[simd_test] +fn abs_u8x64(simd: S) { + let max = u8::MAX; + let high_bit = 1 << (u8::BITS - 1); + let a = u8x64::from_slice( + simd, + &[ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, + max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, + max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, + max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ], + ); + let expected = [ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, + high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, + high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, + high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u8x64(a), expected); +} + +#[simd_test] +fn abs_u16x8(simd: S) { + let max = u16::MAX; + let high_bit = 1 << (u16::BITS - 1); + let a = u16x8::from_slice(simd, &[0, max, high_bit, 1, 0, max, high_bit, 1]); + let expected = [0, max, high_bit, 1, 0, max, high_bit, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u16x8(a), expected); +} + +#[simd_test] +fn abs_u16x16(simd: S) { + let max = u16::MAX; + let high_bit = 1 << (u16::BITS - 1); + let a = u16x16::from_slice( + simd, + &[ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ], + ); + let expected = [ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u16x16(a), expected); +} + +#[simd_test] +fn abs_u16x32(simd: S) { + let max = u16::MAX; + let high_bit = 1 << (u16::BITS - 1); + let a = u16x32::from_slice( + simd, + &[ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, + max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ], + ); + let expected = [ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, + high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u16x32(a), expected); +} + +#[simd_test] +fn abs_u32x4(simd: S) { + let max = u32::MAX; + let high_bit = 1 << (u32::BITS - 1); + let a = u32x4::from_slice(simd, &[0, max, high_bit, 1]); + let expected = [0, max, high_bit, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u32x4(a), expected); +} + +#[simd_test] +fn abs_u32x8(simd: S) { + let max = u32::MAX; + let high_bit = 1 << (u32::BITS - 1); + let a = u32x8::from_slice(simd, &[0, max, high_bit, 1, 0, max, high_bit, 1]); + let expected = [0, max, high_bit, 1, 0, max, high_bit, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u32x8(a), expected); +} + +#[simd_test] +fn abs_u32x16(simd: S) { + let max = u32::MAX; + let high_bit = 1 << (u32::BITS - 1); + let a = u32x16::from_slice( + simd, + &[ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ], + ); + let expected = [ + 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, 0, max, high_bit, 1, + ]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u32x16(a), expected); +} + +#[simd_test] +fn abs_u64x2(simd: S) { + let max = u64::MAX; + let high_bit = 1 << (u64::BITS - 1); + let a = u64x2::from_slice(simd, &[0, max]); + let expected = [0, max]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u64x2(a), expected); + let a = u64x2::from_slice(simd, &[high_bit, 1]); + let expected = [high_bit, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u64x2(a), expected); +} + +#[simd_test] +fn abs_u64x4(simd: S) { + let max = u64::MAX; + let high_bit = 1 << (u64::BITS - 1); + let a = u64x4::from_slice(simd, &[0, max, high_bit, 1]); + let expected = [0, max, high_bit, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u64x4(a), expected); +} + +#[simd_test] +fn abs_u64x8(simd: S) { + let max = u64::MAX; + let high_bit = 1 << (u64::BITS - 1); + let a = u64x8::from_slice(simd, &[0, max, high_bit, 1, 0, max, high_bit, 1]); + let expected = [0, max, high_bit, 1, 0, max, high_bit, 1]; + assert_eq!(*a.abs(), expected); + assert_eq!(*simd.abs_u64x8(a), expected); +}