From ac7181b1fea1b4e3b499fc01cc77bd02e11e724e Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 30 Aug 2026 12:06:45 +0100 Subject: [PATCH 1/8] implement reduce_product --- fearless_simd/src/generated/avx2.rs | 115 ++++++++++ fearless_simd/src/generated/avx512.rs | 115 ++++++++++ fearless_simd/src/generated/fallback.rs | 217 ++++++++++++++----- fearless_simd/src/generated/neon.rs | 118 ++++++++++ fearless_simd/src/generated/simd_trait.rs | 142 ++++++++++++ fearless_simd/src/generated/simd_types.rs | 120 ++++++++++ fearless_simd/src/generated/sse2.rs | 115 ++++++++++ fearless_simd/src/generated/sse4_2.rs | 115 ++++++++++ fearless_simd/src/generated/wasm.rs | 111 ++++++++++ fearless_simd_gen/src/mk_fallback.rs | 41 ++-- fearless_simd_gen/src/mk_neon.rs | 58 +++++ fearless_simd_gen/src/mk_wasm.rs | 109 ++++++++++ fearless_simd_gen/src/mk_x86.rs | 84 ++++++- fearless_simd_gen/src/ops.rs | 12 + fearless_simd_tests/tests/generics.rs | 4 + fearless_simd_tests/tests/harness/ops/mod.rs | 1 + 16 files changed, 1408 insertions(+), 69 deletions(-) diff --git a/fearless_simd/src/generated/avx2.rs b/fearless_simd/src/generated/avx2.rs index 1f2328d8..f04cbf16 100644 --- a/fearless_simd/src/generated/avx2.rs +++ b/fearless_simd/src/generated/avx2.rs @@ -328,6 +328,18 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: f32x4) -> f32 { + let a: __m128 = a.into(); + let adjacent = _mm_mul_ps(a, _mm_shuffle_ps::<0b10_11_00_01>(a, a)); + _mm_cvtss_f32(_mm_mul_ss(adjacent, _mm_movehl_ps(adjacent, adjacent))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -986,6 +998,23 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i8x16) -> i8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { crate::kernel!( #[inline(always)] @@ -1548,6 +1577,23 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: u8x16) -> u8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { crate::kernel!( #[inline(always)] @@ -2198,6 +2244,21 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: i16x8) -> i16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { crate::kernel!( #[inline(always)] @@ -2711,6 +2772,21 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: u16x8) -> u16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { crate::kernel!( #[inline(always)] @@ -3392,6 +3468,15 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + let mul_level_0: [i32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [i32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { crate::kernel!( #[inline(always)] @@ -3882,6 +3967,15 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + let mul_level_0: [u32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [u32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { crate::kernel!( #[inline(always)] @@ -4528,6 +4622,17 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx2, a: f64x2) -> f64 { + let a: __m128d = a.into(); + _mm_cvtsd_f64(_mm_mul_sd(a, _mm_unpackhi_pd(a, a))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5131,6 +5236,11 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let mul_level_0: [i64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { [ i64::max(a[0usize], b[0usize]), @@ -5580,6 +5690,11 @@ impl Simd for Avx2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let mul_level_0: [u64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { [ u64::max(a[0usize], b[0usize]), diff --git a/fearless_simd/src/generated/avx512.rs b/fearless_simd/src/generated/avx512.rs index 348c9fb2..243fed0a 100644 --- a/fearless_simd/src/generated/avx512.rs +++ b/fearless_simd/src/generated/avx512.rs @@ -586,6 +586,18 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f32x4) -> f32 { + let a: __m128 = a.into(); + let adjacent = _mm_mul_ps(a, _mm_shuffle_ps::<0b10_11_00_01>(a, a)); + _mm_cvtss_f32(_mm_mul_ss(adjacent, _mm_movehl_ps(adjacent, adjacent))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -1188,6 +1200,23 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i8x16) -> i8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { crate::kernel!( #[inline(always)] @@ -1736,6 +1765,23 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: u8x16) -> u8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { crate::kernel!( #[inline(always)] @@ -2301,6 +2347,21 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: i16x8) -> i16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { crate::kernel!( #[inline(always)] @@ -2782,6 +2843,21 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: u16x8) -> u16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { crate::kernel!( #[inline(always)] @@ -3365,6 +3441,15 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + let mul_level_0: [i32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [i32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { crate::kernel!( #[inline(always)] @@ -3835,6 +3920,15 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + let mul_level_0: [u32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [u32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { crate::kernel!( #[inline(always)] @@ -4400,6 +4494,17 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Avx512, a: f64x2) -> f64 { + let a: __m128d = a.into(); + _mm_cvtsd_f64(_mm_mul_sd(a, _mm_unpackhi_pd(a, a))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -4936,6 +5041,11 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let mul_level_0: [i64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { crate::kernel!( #[inline(always)] @@ -5371,6 +5481,11 @@ impl Simd for Avx512 { kernel(self, a) } #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let mul_level_0: [u64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { crate::kernel!( #[inline(always)] diff --git a/fearless_simd/src/generated/fallback.rs b/fearless_simd/src/generated/fallback.rs index 3e676607..a9d66d81 100644 --- a/fearless_simd/src/generated/fallback.rs +++ b/fearless_simd/src/generated/fallback.rs @@ -334,9 +334,15 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_f32x4(self, a: f32x4) -> f32 { - let sum_level_0: [f32; 2usize] = [a[0usize] + a[1usize], a[2usize] + a[3usize]]; - let sum_level_1: [f32; 1usize] = [sum_level_0[0usize] + sum_level_0[1usize]]; - sum_level_1[0] + let add_level_0: [f32; 2usize] = [a[0usize] + a[1usize], a[2usize] + a[3usize]]; + let add_level_1: [f32; 1usize] = [add_level_0[0usize] + add_level_0[1usize]]; + add_level_1[0] + } + #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + let mul_level_0: [f32; 2usize] = [a[0usize] * a[1usize], a[2usize] * a[3usize]]; + let mul_level_1: [f32; 1usize] = [mul_level_0[0usize] * mul_level_0[1usize]]; + mul_level_1[0] } #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { @@ -976,7 +982,7 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_i8x16(self, a: i8x16) -> i8 { - let sum_level_0: [i8; 8usize] = [ + let add_level_0: [i8; 8usize] = [ a[0usize].wrapping_add(a[1usize]), a[2usize].wrapping_add(a[3usize]), a[4usize].wrapping_add(a[5usize]), @@ -986,18 +992,43 @@ impl Simd for Fallback { a[12usize].wrapping_add(a[13usize]), a[14usize].wrapping_add(a[15usize]), ]; - let sum_level_1: [i8; 4usize] = [ - sum_level_0[0usize].wrapping_add(sum_level_0[1usize]), - sum_level_0[2usize].wrapping_add(sum_level_0[3usize]), - sum_level_0[4usize].wrapping_add(sum_level_0[5usize]), - sum_level_0[6usize].wrapping_add(sum_level_0[7usize]), + let add_level_1: [i8; 4usize] = [ + add_level_0[0usize].wrapping_add(add_level_0[1usize]), + add_level_0[2usize].wrapping_add(add_level_0[3usize]), + add_level_0[4usize].wrapping_add(add_level_0[5usize]), + add_level_0[6usize].wrapping_add(add_level_0[7usize]), + ]; + let add_level_2: [i8; 2usize] = [ + add_level_1[0usize].wrapping_add(add_level_1[1usize]), + add_level_1[2usize].wrapping_add(add_level_1[3usize]), + ]; + let add_level_3: [i8; 1usize] = [add_level_2[0usize].wrapping_add(add_level_2[1usize])]; + add_level_3[0] + } + #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + let mul_level_0: [i8; 8usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + a[4usize].wrapping_mul(a[5usize]), + a[6usize].wrapping_mul(a[7usize]), + a[8usize].wrapping_mul(a[9usize]), + a[10usize].wrapping_mul(a[11usize]), + a[12usize].wrapping_mul(a[13usize]), + a[14usize].wrapping_mul(a[15usize]), ]; - let sum_level_2: [i8; 2usize] = [ - sum_level_1[0usize].wrapping_add(sum_level_1[1usize]), - sum_level_1[2usize].wrapping_add(sum_level_1[3usize]), + let mul_level_1: [i8; 4usize] = [ + mul_level_0[0usize].wrapping_mul(mul_level_0[1usize]), + mul_level_0[2usize].wrapping_mul(mul_level_0[3usize]), + mul_level_0[4usize].wrapping_mul(mul_level_0[5usize]), + mul_level_0[6usize].wrapping_mul(mul_level_0[7usize]), ]; - let sum_level_3: [i8; 1usize] = [sum_level_2[0usize].wrapping_add(sum_level_2[1usize])]; - sum_level_3[0] + let mul_level_2: [i8; 2usize] = [ + mul_level_1[0usize].wrapping_mul(mul_level_1[1usize]), + mul_level_1[2usize].wrapping_mul(mul_level_1[3usize]), + ]; + let mul_level_3: [i8; 1usize] = [mul_level_2[0usize].wrapping_mul(mul_level_2[1usize])]; + mul_level_3[0] } #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { @@ -1901,7 +1932,7 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_u8x16(self, a: u8x16) -> u8 { - let sum_level_0: [u8; 8usize] = [ + let add_level_0: [u8; 8usize] = [ a[0usize].wrapping_add(a[1usize]), a[2usize].wrapping_add(a[3usize]), a[4usize].wrapping_add(a[5usize]), @@ -1911,18 +1942,43 @@ impl Simd for Fallback { a[12usize].wrapping_add(a[13usize]), a[14usize].wrapping_add(a[15usize]), ]; - let sum_level_1: [u8; 4usize] = [ - sum_level_0[0usize].wrapping_add(sum_level_0[1usize]), - sum_level_0[2usize].wrapping_add(sum_level_0[3usize]), - sum_level_0[4usize].wrapping_add(sum_level_0[5usize]), - sum_level_0[6usize].wrapping_add(sum_level_0[7usize]), + let add_level_1: [u8; 4usize] = [ + add_level_0[0usize].wrapping_add(add_level_0[1usize]), + add_level_0[2usize].wrapping_add(add_level_0[3usize]), + add_level_0[4usize].wrapping_add(add_level_0[5usize]), + add_level_0[6usize].wrapping_add(add_level_0[7usize]), + ]; + let add_level_2: [u8; 2usize] = [ + add_level_1[0usize].wrapping_add(add_level_1[1usize]), + add_level_1[2usize].wrapping_add(add_level_1[3usize]), + ]; + let add_level_3: [u8; 1usize] = [add_level_2[0usize].wrapping_add(add_level_2[1usize])]; + add_level_3[0] + } + #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + let mul_level_0: [u8; 8usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + a[4usize].wrapping_mul(a[5usize]), + a[6usize].wrapping_mul(a[7usize]), + a[8usize].wrapping_mul(a[9usize]), + a[10usize].wrapping_mul(a[11usize]), + a[12usize].wrapping_mul(a[13usize]), + a[14usize].wrapping_mul(a[15usize]), ]; - let sum_level_2: [u8; 2usize] = [ - sum_level_1[0usize].wrapping_add(sum_level_1[1usize]), - sum_level_1[2usize].wrapping_add(sum_level_1[3usize]), + let mul_level_1: [u8; 4usize] = [ + mul_level_0[0usize].wrapping_mul(mul_level_0[1usize]), + mul_level_0[2usize].wrapping_mul(mul_level_0[3usize]), + mul_level_0[4usize].wrapping_mul(mul_level_0[5usize]), + mul_level_0[6usize].wrapping_mul(mul_level_0[7usize]), ]; - let sum_level_3: [u8; 1usize] = [sum_level_2[0usize].wrapping_add(sum_level_2[1usize])]; - sum_level_3[0] + let mul_level_2: [u8; 2usize] = [ + mul_level_1[0usize].wrapping_mul(mul_level_1[1usize]), + mul_level_1[2usize].wrapping_mul(mul_level_1[3usize]), + ]; + let mul_level_3: [u8; 1usize] = [mul_level_2[0usize].wrapping_mul(mul_level_2[1usize])]; + mul_level_3[0] } #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { @@ -2940,18 +2996,33 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_i16x8(self, a: i16x8) -> i16 { - let sum_level_0: [i16; 4usize] = [ + let add_level_0: [i16; 4usize] = [ a[0usize].wrapping_add(a[1usize]), a[2usize].wrapping_add(a[3usize]), a[4usize].wrapping_add(a[5usize]), a[6usize].wrapping_add(a[7usize]), ]; - let sum_level_1: [i16; 2usize] = [ - sum_level_0[0usize].wrapping_add(sum_level_0[1usize]), - sum_level_0[2usize].wrapping_add(sum_level_0[3usize]), + let add_level_1: [i16; 2usize] = [ + add_level_0[0usize].wrapping_add(add_level_0[1usize]), + add_level_0[2usize].wrapping_add(add_level_0[3usize]), ]; - let sum_level_2: [i16; 1usize] = [sum_level_1[0usize].wrapping_add(sum_level_1[1usize])]; - sum_level_2[0] + let add_level_2: [i16; 1usize] = [add_level_1[0usize].wrapping_add(add_level_1[1usize])]; + add_level_2[0] + } + #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + let mul_level_0: [i16; 4usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + a[4usize].wrapping_mul(a[5usize]), + a[6usize].wrapping_mul(a[7usize]), + ]; + let mul_level_1: [i16; 2usize] = [ + mul_level_0[0usize].wrapping_mul(mul_level_0[1usize]), + mul_level_0[2usize].wrapping_mul(mul_level_0[3usize]), + ]; + let mul_level_2: [i16; 1usize] = [mul_level_1[0usize].wrapping_mul(mul_level_1[1usize])]; + mul_level_2[0] } #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { @@ -3522,18 +3593,33 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_u16x8(self, a: u16x8) -> u16 { - let sum_level_0: [u16; 4usize] = [ + let add_level_0: [u16; 4usize] = [ a[0usize].wrapping_add(a[1usize]), a[2usize].wrapping_add(a[3usize]), a[4usize].wrapping_add(a[5usize]), a[6usize].wrapping_add(a[7usize]), ]; - let sum_level_1: [u16; 2usize] = [ - sum_level_0[0usize].wrapping_add(sum_level_0[1usize]), - sum_level_0[2usize].wrapping_add(sum_level_0[3usize]), + let add_level_1: [u16; 2usize] = [ + add_level_0[0usize].wrapping_add(add_level_0[1usize]), + add_level_0[2usize].wrapping_add(add_level_0[3usize]), + ]; + let add_level_2: [u16; 1usize] = [add_level_1[0usize].wrapping_add(add_level_1[1usize])]; + add_level_2[0] + } + #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + let mul_level_0: [u16; 4usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + a[4usize].wrapping_mul(a[5usize]), + a[6usize].wrapping_mul(a[7usize]), + ]; + let mul_level_1: [u16; 2usize] = [ + mul_level_0[0usize].wrapping_mul(mul_level_0[1usize]), + mul_level_0[2usize].wrapping_mul(mul_level_0[3usize]), ]; - let sum_level_2: [u16; 1usize] = [sum_level_1[0usize].wrapping_add(sum_level_1[1usize])]; - sum_level_2[0] + let mul_level_2: [u16; 1usize] = [mul_level_1[0usize].wrapping_mul(mul_level_1[1usize])]; + mul_level_2[0] } #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { @@ -4252,12 +4338,21 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_i32x4(self, a: i32x4) -> i32 { - let sum_level_0: [i32; 2usize] = [ + let add_level_0: [i32; 2usize] = [ a[0usize].wrapping_add(a[1usize]), a[2usize].wrapping_add(a[3usize]), ]; - let sum_level_1: [i32; 1usize] = [sum_level_0[0usize].wrapping_add(sum_level_0[1usize])]; - sum_level_1[0] + let add_level_1: [i32; 1usize] = [add_level_0[0usize].wrapping_add(add_level_0[1usize])]; + add_level_1[0] + } + #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + let mul_level_0: [i32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [i32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] } #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { @@ -4631,12 +4726,21 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_u32x4(self, a: u32x4) -> u32 { - let sum_level_0: [u32; 2usize] = [ + let add_level_0: [u32; 2usize] = [ a[0usize].wrapping_add(a[1usize]), a[2usize].wrapping_add(a[3usize]), ]; - let sum_level_1: [u32; 1usize] = [sum_level_0[0usize].wrapping_add(sum_level_0[1usize])]; - sum_level_1[0] + let add_level_1: [u32; 1usize] = [add_level_0[0usize].wrapping_add(add_level_0[1usize])]; + add_level_1[0] + } + #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + let mul_level_0: [u32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [u32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] } #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { @@ -5081,8 +5185,13 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_f64x2(self, a: f64x2) -> f64 { - let sum_level_0: [f64; 1usize] = [a[0usize] + a[1usize]]; - sum_level_0[0] + let add_level_0: [f64; 1usize] = [a[0usize] + a[1usize]]; + add_level_0[0] + } + #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + let mul_level_0: [f64; 1usize] = [a[0usize] * a[1usize]]; + mul_level_0[0] } #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { @@ -5424,8 +5533,13 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_i64x2(self, a: i64x2) -> i64 { - let sum_level_0: [i64; 1usize] = [a[0usize].wrapping_add(a[1usize])]; - sum_level_0[0] + let add_level_0: [i64; 1usize] = [a[0usize].wrapping_add(a[1usize])]; + add_level_0[0] + } + #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let mul_level_0: [i64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] } #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { @@ -5706,8 +5820,13 @@ impl Simd for Fallback { } #[inline(always)] fn reduce_sum_u64x2(self, a: u64x2) -> u64 { - let sum_level_0: [u64; 1usize] = [a[0usize].wrapping_add(a[1usize])]; - sum_level_0[0] + let add_level_0: [u64; 1usize] = [a[0usize].wrapping_add(a[1usize])]; + add_level_0[0] + } + #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let mul_level_0: [u64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] } #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { diff --git a/fearless_simd/src/generated/neon.rs b/fearless_simd/src/generated/neon.rs index 096cbef2..3c5fd018 100644 --- a/fearless_simd/src/generated/neon.rs +++ b/fearless_simd/src/generated/neon.rs @@ -282,6 +282,19 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: f32x4) -> f32 { + let product: float32x4_t = a.into(); + let product = vmulq_f32(product, vextq_f32::<1>(product, product)); + let product = vmulq_f32(product, vextq_f32::<2>(product, product)); + vgetq_lane_f32::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -755,6 +768,21 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i8x16) -> i8 { + let product: int8x16_t = a.into(); + let product = vmulq_s8(product, vextq_s8::<1>(product, product)); + let product = vmulq_s8(product, vextq_s8::<2>(product, product)); + let product = vmulq_s8(product, vextq_s8::<4>(product, product)); + let product = vmulq_s8(product, vextq_s8::<8>(product, product)); + vgetq_lane_s8::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { crate::kernel!( #[inline(always)] @@ -1148,6 +1176,21 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: u8x16) -> u8 { + let product: uint8x16_t = a.into(); + let product = vmulq_u8(product, vextq_u8::<1>(product, product)); + let product = vmulq_u8(product, vextq_u8::<2>(product, product)); + let product = vmulq_u8(product, vextq_u8::<4>(product, product)); + let product = vmulq_u8(product, vextq_u8::<8>(product, product)); + vgetq_lane_u8::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { crate::kernel!( #[inline(always)] @@ -1688,6 +1731,20 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i16x8) -> i16 { + let product: int16x8_t = a.into(); + let product = vmulq_s16(product, vextq_s16::<1>(product, product)); + let product = vmulq_s16(product, vextq_s16::<2>(product, product)); + let product = vmulq_s16(product, vextq_s16::<4>(product, product)); + vgetq_lane_s16::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { crate::kernel!( #[inline(always)] @@ -2080,6 +2137,20 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: u16x8) -> u16 { + let product: uint16x8_t = a.into(); + let product = vmulq_u16(product, vextq_u16::<1>(product, product)); + let product = vmulq_u16(product, vextq_u16::<2>(product, product)); + let product = vmulq_u16(product, vextq_u16::<4>(product, product)); + vgetq_lane_u16::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { crate::kernel!( #[inline(always)] @@ -2645,6 +2716,19 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: i32x4) -> i32 { + let product: int32x4_t = a.into(); + let product = vmulq_s32(product, vextq_s32::<1>(product, product)); + let product = vmulq_s32(product, vextq_s32::<2>(product, product)); + vgetq_lane_s32::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { crate::kernel!( #[inline(always)] @@ -3047,6 +3131,19 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: u32x4) -> u32 { + let product: uint32x4_t = a.into(); + let product = vmulq_u32(product, vextq_u32::<1>(product, product)); + let product = vmulq_u32(product, vextq_u32::<2>(product, product)); + vgetq_lane_u32::<0>(product) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { crate::kernel!( #[inline(always)] @@ -3605,6 +3702,17 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Neon, a: f64x2) -> f64 { + let a: float64x2_t = a.into(); + vgetq_lane_f64::<0>(a) * vgetq_lane_f64::<1>(a) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -4074,6 +4182,11 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let mul_level_0: [i64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { [ i64::max(a[0usize], b[0usize]), @@ -4450,6 +4563,11 @@ impl Simd for Neon { kernel(self, a) } #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let mul_level_0: [u64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { [ u64::max(a[0usize], b[0usize]), diff --git a/fearless_simd/src/generated/simd_trait.rs b/fearless_simd/src/generated/simd_trait.rs index f1ce7214..bd283ebe 100644 --- a/fearless_simd/src/generated/simd_trait.rs +++ b/fearless_simd/src/generated/simd_trait.rs @@ -271,6 +271,8 @@ pub trait Simd: fn reduce_min_precise_f32x4(self, a: f32x4) -> f32; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f32x4(self, a: f32x4) -> f32; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_f32x4(self, a: f32x4) -> f32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -411,6 +413,8 @@ pub trait Simd: fn reduce_min_i8x16(self, a: i8x16) -> i8; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i8x16(self, a: i8x16) -> i8; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_i8x16(self, a: i8x16) -> i8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -514,6 +518,8 @@ pub trait Simd: fn reduce_min_u8x16(self, a: u8x16) -> u8; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u8x16(self, a: u8x16) -> u8; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_u8x16(self, a: u8x16) -> u8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -661,6 +667,8 @@ pub trait Simd: fn reduce_min_i16x8(self, a: i16x8) -> i16; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i16x8(self, a: i16x8) -> i16; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_i16x8(self, a: i16x8) -> i16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -779,6 +787,8 @@ pub trait Simd: fn reduce_min_u16x8(self, a: u16x8) -> u16; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u16x8(self, a: u16x8) -> u16; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_u16x8(self, a: u16x8) -> u16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -932,6 +942,8 @@ pub trait Simd: fn reduce_min_i32x4(self, a: i32x4) -> i32; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i32x4(self, a: i32x4) -> i32; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_i32x4(self, a: i32x4) -> i32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -1052,6 +1064,8 @@ pub trait Simd: fn reduce_min_u32x4(self, a: u32x4) -> u32; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u32x4(self, a: u32x4) -> u32; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_u32x4(self, a: u32x4) -> u32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -1203,6 +1217,8 @@ pub trait Simd: fn reduce_min_precise_f64x2(self, a: f64x2) -> f64; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f64x2(self, a: f64x2) -> f64; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_f64x2(self, a: f64x2) -> f64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -1347,6 +1363,8 @@ pub trait Simd: fn reduce_min_i64x2(self, a: i64x2) -> i64; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i64x2(self, a: i64x2) -> i64; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_i64x2(self, a: i64x2) -> i64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -1465,6 +1483,8 @@ pub trait Simd: fn reduce_min_u64x2(self, a: u64x2) -> u64; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u64x2(self, a: u64x2) -> u64; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product_u64x2(self, a: u64x2) -> u64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] @@ -1691,6 +1711,12 @@ pub trait Simd: let (a0, a1) = self.split_f32x8(a); self.reduce_sum_f32x4(self.add_f32x4(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_f32x8(self, a: f32x8) -> f32 { + let (a0, a1) = self.split_f32x8(a); + self.reduce_product_f32x4(self.mul_f32x4(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_f32x8(self, a: f32x8, b: f32x8) -> f32x8 { @@ -2086,6 +2112,12 @@ pub trait Simd: let (a0, a1) = self.split_i8x32(a); self.reduce_sum_i8x16(self.add_i8x16(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i8x32(self, a: i8x32) -> i8 { + let (a0, a1) = self.split_i8x32(a); + self.reduce_product_i8x16(self.mul_i8x16(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i8x32(self, a: i8x32, b: i8x32) -> i8x32 { @@ -2359,6 +2391,12 @@ pub trait Simd: let (a0, a1) = self.split_u8x32(a); self.reduce_sum_u8x16(self.add_u8x16(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u8x32(self, a: u8x32) -> u8 { + let (a0, a1) = self.split_u8x32(a); + self.reduce_product_u8x16(self.mul_u8x16(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u8x32(self, a: u8x32, b: u8x32) -> u8x32 { @@ -2738,6 +2776,12 @@ pub trait Simd: let (a0, a1) = self.split_i16x16(a); self.reduce_sum_i16x8(self.add_i16x8(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i16x16(self, a: i16x16) -> i16 { + let (a0, a1) = self.split_i16x16(a); + self.reduce_product_i16x8(self.mul_i16x8(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i16x16(self, a: i16x16, b: i16x16) -> i16x16 { @@ -3043,6 +3087,12 @@ pub trait Simd: let (a0, a1) = self.split_u16x16(a); self.reduce_sum_u16x8(self.add_u16x8(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u16x16(self, a: u16x16) -> u16 { + let (a0, a1) = self.split_u16x16(a); + self.reduce_product_u16x8(self.mul_u16x8(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u16x16(self, a: u16x16, b: u16x16) -> u16x16 { @@ -3445,6 +3495,12 @@ pub trait Simd: let (a0, a1) = self.split_i32x8(a); self.reduce_sum_i32x4(self.add_i32x4(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i32x8(self, a: i32x8) -> i32 { + let (a0, a1) = self.split_i32x8(a); + self.reduce_product_i32x4(self.mul_i32x4(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i32x8(self, a: i32x8, b: i32x8) -> i32x8 { @@ -3752,6 +3808,12 @@ pub trait Simd: let (a0, a1) = self.split_u32x8(a); self.reduce_sum_u32x4(self.add_u32x4(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u32x8(self, a: u32x8) -> u32 { + let (a0, a1) = self.split_u32x8(a); + self.reduce_product_u32x4(self.mul_u32x4(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u32x8(self, a: u32x8, b: u32x8) -> u32x8 { @@ -4148,6 +4210,12 @@ pub trait Simd: let (a0, a1) = self.split_f64x4(a); self.reduce_sum_f64x2(self.add_f64x2(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_f64x4(self, a: f64x4) -> f64 { + let (a0, a1) = self.split_f64x4(a); + self.reduce_product_f64x2(self.mul_f64x2(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_f64x4(self, a: f64x4, b: f64x4) -> f64x4 { @@ -4562,6 +4630,12 @@ pub trait Simd: let (a0, a1) = self.split_i64x4(a); self.reduce_sum_i64x2(self.add_i64x2(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i64x4(self, a: i64x4) -> i64 { + let (a0, a1) = self.split_i64x4(a); + self.reduce_product_i64x2(self.mul_i64x2(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i64x4(self, a: i64x4, b: i64x4) -> i64x4 { @@ -4861,6 +4935,12 @@ pub trait Simd: let (a0, a1) = self.split_u64x4(a); self.reduce_sum_u64x2(self.add_u64x2(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u64x4(self, a: u64x4) -> u64 { + let (a0, a1) = self.split_u64x4(a); + self.reduce_product_u64x2(self.mul_u64x2(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u64x4(self, a: u64x4, b: u64x4) -> u64x4 { @@ -5253,6 +5333,12 @@ pub trait Simd: let (a0, a1) = self.split_f32x16(a); self.reduce_sum_f32x8(self.add_f32x8(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_f32x16(self, a: f32x16) -> f32 { + let (a0, a1) = self.split_f32x16(a); + self.reduce_product_f32x8(self.mul_f32x8(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_f32x16(self, a: f32x16, b: f32x16) -> f32x16 { @@ -5656,6 +5742,12 @@ pub trait Simd: let (a0, a1) = self.split_i8x64(a); self.reduce_sum_i8x32(self.add_i8x32(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i8x64(self, a: i8x64) -> i8 { + let (a0, a1) = self.split_i8x64(a); + self.reduce_product_i8x32(self.mul_i8x32(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i8x64(self, a: i8x64, b: i8x64) -> i8x64 { @@ -5927,6 +6019,12 @@ pub trait Simd: let (a0, a1) = self.split_u8x64(a); self.reduce_sum_u8x32(self.add_u8x32(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u8x64(self, a: u8x64) -> u8 { + let (a0, a1) = self.split_u8x64(a); + self.reduce_product_u8x32(self.mul_u8x32(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u8x64(self, a: u8x64, b: u8x64) -> u8x64 { @@ -6302,6 +6400,12 @@ pub trait Simd: let (a0, a1) = self.split_i16x32(a); self.reduce_sum_i16x16(self.add_i16x16(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i16x32(self, a: i16x32) -> i16 { + let (a0, a1) = self.split_i16x32(a); + self.reduce_product_i16x16(self.mul_i16x16(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i16x32(self, a: i16x32, b: i16x32) -> i16x32 { @@ -6611,6 +6715,12 @@ pub trait Simd: let (a0, a1) = self.split_u16x32(a); self.reduce_sum_u16x16(self.add_u16x16(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u16x32(self, a: u16x32) -> u16 { + let (a0, a1) = self.split_u16x32(a); + self.reduce_product_u16x16(self.mul_u16x16(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u16x32(self, a: u16x32, b: u16x32) -> u16x32 { @@ -7022,6 +7132,12 @@ pub trait Simd: let (a0, a1) = self.split_i32x16(a); self.reduce_sum_i32x8(self.add_i32x8(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i32x16(self, a: i32x16) -> i32 { + let (a0, a1) = self.split_i32x16(a); + self.reduce_product_i32x8(self.mul_i32x8(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i32x16(self, a: i32x16, b: i32x16) -> i32x16 { @@ -7331,6 +7447,12 @@ pub trait Simd: let (a0, a1) = self.split_u32x16(a); self.reduce_sum_u32x8(self.add_u32x8(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u32x16(self, a: u32x16) -> u32 { + let (a0, a1) = self.split_u32x16(a); + self.reduce_product_u32x8(self.mul_u32x8(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u32x16(self, a: u32x16, b: u32x16) -> u32x16 { @@ -7723,6 +7845,12 @@ pub trait Simd: let (a0, a1) = self.split_f64x8(a); self.reduce_sum_f64x4(self.add_f64x4(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_f64x8(self, a: f64x8) -> f64 { + let (a0, a1) = self.split_f64x8(a); + self.reduce_product_f64x4(self.mul_f64x4(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_f64x8(self, a: f64x8, b: f64x8) -> f64x8 { @@ -8135,6 +8263,12 @@ pub trait Simd: let (a0, a1) = self.split_i64x8(a); self.reduce_sum_i64x4(self.add_i64x4(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_i64x8(self, a: i64x8) -> i64 { + let (a0, a1) = self.split_i64x8(a); + self.reduce_product_i64x4(self.mul_i64x4(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_i64x8(self, a: i64x8, b: i64x8) -> i64x8 { @@ -8432,6 +8566,12 @@ pub trait Simd: let (a0, a1) = self.split_u64x8(a); self.reduce_sum_u64x4(self.add_u64x4(a0, a1)) } + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[inline(always)] + fn reduce_product_u64x8(self, a: u64x8) -> u64 { + let (a0, a1) = self.split_u64x8(a); + self.reduce_product_u64x4(self.mul_u64x4(a0, a1)) + } #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] #[inline(always)] fn max_u64x8(self, a: u64x8, b: u64x8) -> u64x8 { @@ -9257,6 +9397,8 @@ pub trait SimdBase: fn reduce_min_precise(self) -> Self::Element; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum(self) -> Self::Element; + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + fn reduce_product(self) -> Self::Element; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max(self, rhs: impl SimdInto) -> Self; #[doc = "Return the element-wise minimum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `min_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] diff --git a/fearless_simd/src/generated/simd_types.rs b/fearless_simd/src/generated/simd_types.rs index 3c69e51a..603449f5 100644 --- a/fearless_simd/src/generated/simd_types.rs +++ b/fearless_simd/src/generated/simd_types.rs @@ -179,6 +179,10 @@ impl SimdBase for f32x4 { self.simd.reduce_sum_f32x4(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_f32x4(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_f32x4(self, rhs.simd_into(self.simd)) } @@ -529,6 +533,10 @@ impl SimdBase for i8x16 { self.simd.reduce_sum_i8x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i8x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i8x16(self, rhs.simd_into(self.simd)) } @@ -817,6 +825,10 @@ impl SimdBase for u8x16 { self.simd.reduce_sum_u8x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u8x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u8x16(self, rhs.simd_into(self.simd)) } @@ -1195,6 +1207,10 @@ impl SimdBase for i16x8 { self.simd.reduce_sum_i16x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i16x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i16x8(self, rhs.simd_into(self.simd)) } @@ -1490,6 +1506,10 @@ impl SimdBase for u16x8 { self.simd.reduce_sum_u16x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u16x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u16x8(self, rhs.simd_into(self.simd)) } @@ -1871,6 +1891,10 @@ impl SimdBase for i32x4 { self.simd.reduce_sum_i32x4(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i32x4(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i32x4(self, rhs.simd_into(self.simd)) } @@ -2166,6 +2190,10 @@ impl SimdBase for u32x4 { self.simd.reduce_sum_u32x4(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u32x4(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u32x4(self, rhs.simd_into(self.simd)) } @@ -2559,6 +2587,10 @@ impl SimdBase for f64x2 { self.simd.reduce_sum_f64x2(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_f64x2(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_f64x2(self, rhs.simd_into(self.simd)) } @@ -2897,6 +2929,10 @@ impl SimdBase for i64x2 { self.simd.reduce_sum_i64x2(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i64x2(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i64x2(self, rhs.simd_into(self.simd)) } @@ -3185,6 +3221,10 @@ impl SimdBase for u64x2 { self.simd.reduce_sum_u64x2(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u64x2(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u64x2(self, rhs.simd_into(self.simd)) } @@ -3583,6 +3623,10 @@ impl SimdBase for f32x8 { self.simd.reduce_sum_f32x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_f32x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_f32x8(self, rhs.simd_into(self.simd)) } @@ -3944,6 +3988,10 @@ impl SimdBase for i8x32 { self.simd.reduce_sum_i8x32(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i8x32(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i8x32(self, rhs.simd_into(self.simd)) } @@ -4243,6 +4291,10 @@ impl SimdBase for u8x32 { self.simd.reduce_sum_u8x32(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u8x32(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u8x32(self, rhs.simd_into(self.simd)) } @@ -4624,6 +4676,10 @@ impl SimdBase for i16x16 { self.simd.reduce_sum_i16x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i16x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i16x16(self, rhs.simd_into(self.simd)) } @@ -4923,6 +4979,10 @@ impl SimdBase for u16x16 { self.simd.reduce_sum_u16x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u16x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u16x16(self, rhs.simd_into(self.simd)) } @@ -5312,6 +5372,10 @@ impl SimdBase for i32x8 { self.simd.reduce_sum_i32x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i32x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i32x8(self, rhs.simd_into(self.simd)) } @@ -5614,6 +5678,10 @@ impl SimdBase for u32x8 { self.simd.reduce_sum_u32x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u32x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u32x8(self, rhs.simd_into(self.simd)) } @@ -6002,6 +6070,10 @@ impl SimdBase for f64x4 { self.simd.reduce_sum_f64x4(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_f64x4(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_f64x4(self, rhs.simd_into(self.simd)) } @@ -6335,6 +6407,10 @@ impl SimdBase for i64x4 { self.simd.reduce_sum_i64x4(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i64x4(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i64x4(self, rhs.simd_into(self.simd)) } @@ -6618,6 +6694,10 @@ impl SimdBase for u64x4 { self.simd.reduce_sum_u64x4(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u64x4(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u64x4(self, rhs.simd_into(self.simd)) } @@ -7020,6 +7100,10 @@ impl SimdBase for f32x16 { self.simd.reduce_sum_f32x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_f32x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_f32x16(self, rhs.simd_into(self.simd)) } @@ -7408,6 +7492,10 @@ impl SimdBase for i8x64 { self.simd.reduce_sum_i8x64(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i8x64(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i8x64(self, rhs.simd_into(self.simd)) } @@ -7733,6 +7821,10 @@ impl SimdBase for u8x64 { self.simd.reduce_sum_u8x64(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u8x64(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u8x64(self, rhs.simd_into(self.simd)) } @@ -8124,6 +8216,10 @@ impl SimdBase for i16x32 { self.simd.reduce_sum_i16x32(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i16x32(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i16x32(self, rhs.simd_into(self.simd)) } @@ -8433,6 +8529,10 @@ impl SimdBase for u16x32 { self.simd.reduce_sum_u16x32(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u16x32(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u16x32(self, rhs.simd_into(self.simd)) } @@ -8824,6 +8924,10 @@ impl SimdBase for i32x16 { self.simd.reduce_sum_i32x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i32x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i32x16(self, rhs.simd_into(self.simd)) } @@ -9129,6 +9233,10 @@ impl SimdBase for u32x16 { self.simd.reduce_sum_u32x16(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u32x16(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u32x16(self, rhs.simd_into(self.simd)) } @@ -9524,6 +9632,10 @@ impl SimdBase for f64x8 { self.simd.reduce_sum_f64x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_f64x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_f64x8(self, rhs.simd_into(self.simd)) } @@ -9863,6 +9975,10 @@ impl SimdBase for i64x8 { self.simd.reduce_sum_i64x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_i64x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_i64x8(self, rhs.simd_into(self.simd)) } @@ -10152,6 +10268,10 @@ impl SimdBase for u64x8 { self.simd.reduce_sum_u64x8(self) } #[inline(always)] + fn reduce_product(self) -> Self::Element { + self.simd.reduce_product_u64x8(self) + } + #[inline(always)] fn max(self, rhs: impl SimdInto) -> Self { self.simd.max_u64x8(self, rhs.simd_into(self.simd)) } diff --git a/fearless_simd/src/generated/sse2.rs b/fearless_simd/src/generated/sse2.rs index ed0c46c2..a4c0ab1c 100644 --- a/fearless_simd/src/generated/sse2.rs +++ b/fearless_simd/src/generated/sse2.rs @@ -434,6 +434,18 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: f32x4) -> f32 { + let a: __m128 = a.into(); + let adjacent = _mm_mul_ps(a, _mm_shuffle_ps::<0b10_11_00_01>(a, a)); + _mm_cvtss_f32(_mm_mul_ss(adjacent, _mm_movehl_ps(adjacent, adjacent))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -1143,6 +1155,23 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: i8x16) -> i8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { crate::kernel!( #[inline(always)] @@ -1839,6 +1868,23 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: u8x16) -> u8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { crate::kernel!( #[inline(always)] @@ -2557,6 +2603,21 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: i16x8) -> i16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { crate::kernel!( #[inline(always)] @@ -3127,6 +3188,21 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: u16x8) -> u16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { crate::kernel!( #[inline(always)] @@ -3837,6 +3913,15 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + let mul_level_0: [i32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [i32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { crate::kernel!( #[inline(always)] @@ -4386,6 +4471,15 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + let mul_level_0: [u32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [u32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { crate::kernel!( #[inline(always)] @@ -5068,6 +5162,17 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse2, a: f64x2) -> f64 { + let a: __m128d = a.into(); + _mm_cvtsd_f64(_mm_mul_sd(a, _mm_unpackhi_pd(a, a))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5570,6 +5675,11 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let mul_level_0: [i64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { [ i64::max(a[0usize], b[0usize]), @@ -5990,6 +6100,11 @@ impl Simd for Sse2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let mul_level_0: [u64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { [ u64::max(a[0usize], b[0usize]), diff --git a/fearless_simd/src/generated/sse4_2.rs b/fearless_simd/src/generated/sse4_2.rs index 21870c53..bc3f62f7 100644 --- a/fearless_simd/src/generated/sse4_2.rs +++ b/fearless_simd/src/generated/sse4_2.rs @@ -402,6 +402,18 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: f32x4) -> f32 { + let a: __m128 = a.into(); + let adjacent = _mm_mul_ps(a, _mm_shuffle_ps::<0b10_11_00_01>(a, a)); + _mm_cvtss_f32(_mm_mul_ss(adjacent, _mm_movehl_ps(adjacent, adjacent))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { crate::kernel!( #[inline(always)] @@ -1136,6 +1148,23 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: i8x16) -> i8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { crate::kernel!( #[inline(always)] @@ -1703,6 +1732,23 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: u8x16) -> u8 { + let value: __m128i = a.into(); + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { crate::kernel!( #[inline(always)] @@ -2355,6 +2401,21 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: i16x8) -> i16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { crate::kernel!( #[inline(always)] @@ -2869,6 +2930,21 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: u16x8) -> u16 { + let product: __m128i = a.into(); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + ); + kernel(self, a) + } + #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { crate::kernel!( #[inline(always)] @@ -3548,6 +3624,15 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + let mul_level_0: [i32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [i32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { crate::kernel!( #[inline(always)] @@ -4035,6 +4120,15 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + let mul_level_0: [u32; 2usize] = [ + a[0usize].wrapping_mul(a[1usize]), + a[2usize].wrapping_mul(a[3usize]), + ]; + let mul_level_1: [u32; 1usize] = [mul_level_0[0usize].wrapping_mul(mul_level_0[1usize])]; + mul_level_1[0] + } + #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { crate::kernel!( #[inline(always)] @@ -4675,6 +4769,17 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + crate::kernel!( + #[inline(always)] + fn kernel(token: Sse4_2, a: f64x2) -> f64 { + let a: __m128d = a.into(); + _mm_cvtsd_f64(_mm_mul_sd(a, _mm_unpackhi_pd(a, a))) + } + ); + kernel(self, a) + } + #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { crate::kernel!( #[inline(always)] @@ -5294,6 +5399,11 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let mul_level_0: [i64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { [ i64::max(a[0usize], b[0usize]), @@ -5746,6 +5856,11 @@ impl Simd for Sse4_2 { kernel(self, a) } #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let mul_level_0: [u64; 1usize] = [a[0usize].wrapping_mul(a[1usize])]; + mul_level_0[0] + } + #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { [ u64::max(a[0usize], b[0usize]), diff --git a/fearless_simd/src/generated/wasm.rs b/fearless_simd/src/generated/wasm.rs index ba07c50e..fd19072f 100644 --- a/fearless_simd/src/generated/wasm.rs +++ b/fearless_simd/src/generated/wasm.rs @@ -307,6 +307,13 @@ impl Simd for WasmSimd128 { f32x4_extract_lane::<0>(result) } #[inline(always)] + fn reduce_product_f32x4(self, a: f32x4) -> f32 { + let a: v128 = a.into(); + let adjacent = f32x4_mul(a, i32x4_shuffle::<1, 0, 3, 2>(a, a)); + let result = f32x4_mul(adjacent, i32x4_shuffle::<2, 3, 2, 3>(adjacent, adjacent)); + f32x4_extract_lane::<0>(result) + } + #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { #[cfg(target_feature = "relaxed-simd")] { @@ -730,6 +737,26 @@ impl Simd for WasmSimd128 { i8x16_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_i8x16(self, a: i8x16) -> i8 { + let a: v128 = a.into(); + let even = i8x16_shuffle::<0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14>(a, a); + let odd = i8x16_shuffle::<1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15>(a, a); + let product = i16x8_extmul_low_i8x16(even, odd); + let product = i16x8_mul( + product, + i16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), + ); + let product = i16x8_mul( + product, + i16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), + ); + let product = i16x8_mul( + product, + i16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), + ); + i16x8_extract_lane::<0>(product) as i8 + } + #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { i8x16_max(a.into(), b.into()).simd_into(self) } @@ -1112,6 +1139,26 @@ impl Simd for WasmSimd128 { u8x16_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_u8x16(self, a: u8x16) -> u8 { + let a: v128 = a.into(); + let even = i8x16_shuffle::<0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14>(a, a); + let odd = i8x16_shuffle::<1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15>(a, a); + let product = u16x8_extmul_low_u8x16(even, odd); + let product = u16x8_mul( + product, + u16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), + ); + let product = u16x8_mul( + product, + u16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), + ); + let product = u16x8_mul( + product, + u16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), + ); + u16x8_extract_lane::<0>(product) as u8 + } + #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { u8x16_max(a.into(), b.into()).simd_into(self) } @@ -1501,6 +1548,23 @@ impl Simd for WasmSimd128 { i16x8_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_i16x8(self, a: i16x8) -> i16 { + let product: v128 = a.into(); + let product = i16x8_mul( + product, + i16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), + ); + let product = i16x8_mul( + product, + i16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), + ); + let product = i16x8_mul( + product, + i16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), + ); + i16x8_extract_lane::<0>(product) + } + #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { i16x8_max(a.into(), b.into()).simd_into(self) } @@ -1777,6 +1841,23 @@ impl Simd for WasmSimd128 { u16x8_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_u16x8(self, a: u16x8) -> u16 { + let product: v128 = a.into(); + let product = u16x8_mul( + product, + u16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), + ); + let product = u16x8_mul( + product, + u16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), + ); + let product = u16x8_mul( + product, + u16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), + ); + u16x8_extract_lane::<0>(product) + } + #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { u16x8_max(a.into(), b.into()).simd_into(self) } @@ -2130,6 +2211,13 @@ impl Simd for WasmSimd128 { i32x4_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_i32x4(self, a: i32x4) -> i32 { + let product: v128 = a.into(); + let product = i32x4_mul(product, i32x4_shuffle::<2, 3, 0, 1>(product, product)); + let product = i32x4_mul(product, i32x4_shuffle::<1, 2, 3, 0>(product, product)); + i32x4_extract_lane::<0>(product) + } + #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { i32x4_max(a.into(), b.into()).simd_into(self) } @@ -2392,6 +2480,13 @@ impl Simd for WasmSimd128 { u32x4_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_u32x4(self, a: u32x4) -> u32 { + let product: v128 = a.into(); + let product = u32x4_mul(product, u32x4_shuffle::<2, 3, 0, 1>(product, product)); + let product = u32x4_mul(product, u32x4_shuffle::<1, 2, 3, 0>(product, product)); + u32x4_extract_lane::<0>(product) + } + #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { u32x4_max(a.into(), b.into()).simd_into(self) } @@ -2732,6 +2827,12 @@ impl Simd for WasmSimd128 { f64x2_extract_lane::<0>(result) } #[inline(always)] + fn reduce_product_f64x2(self, a: f64x2) -> f64 { + let a: v128 = a.into(); + let result = f64x2_mul(a, i64x2_shuffle::<1, 1>(a, a)); + f64x2_extract_lane::<0>(result) + } + #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { #[cfg(target_feature = "relaxed-simd")] { @@ -3054,6 +3155,11 @@ impl Simd for WasmSimd128 { i64x2_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_i64x2(self, a: i64x2) -> i64 { + let a: v128 = a.into(); + i64x2_extract_lane::<0>(a).wrapping_mul(i64x2_extract_lane::<1>(a)) + } + #[inline(always)] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2 { [ i64::max(a[0usize], b[0usize]), @@ -3311,6 +3417,11 @@ impl Simd for WasmSimd128 { u64x2_extract_lane::<0>(sum) } #[inline(always)] + fn reduce_product_u64x2(self, a: u64x2) -> u64 { + let a: v128 = a.into(); + u64x2_extract_lane::<0>(a).wrapping_mul(u64x2_extract_lane::<1>(a)) + } + #[inline(always)] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2 { [ u64::max(a[0usize], b[0usize]), diff --git a/fearless_simd_gen/src/mk_fallback.rs b/fearless_simd_gen/src/mk_fallback.rs index d4d88412..6bd17ce7 100644 --- a/fearless_simd_gen/src/mk_fallback.rs +++ b/fearless_simd_gen/src/mk_fallback.rs @@ -291,8 +291,8 @@ impl Level for Fallback { } } OpSig::Reduce { lane_op } => { - if lane_op == "add" { - fallback_reduce_sum(method_sig, vec_ty) + if matches!(lane_op, "add" | "mul") { + fallback_reduce_arithmetic(method_sig, vec_ty, lane_op) } else { fallback_reduce_min_max(method_sig, vec_ty, lane_op) } @@ -833,14 +833,19 @@ fn fallback_reduce_min_max( } } -/// Build an adjacent balanced reduction one horizontal level at a time. -fn fallback_reduce_sum(method_sig: TokenStream, vec_ty: &VecType) -> TokenStream { +/// Build an adjacent balanced arithmetic reduction one horizontal level at a time. +fn fallback_reduce_arithmetic( + method_sig: TokenStream, + vec_ty: &VecType, + lane_op: &str, +) -> TokenStream { // The structure directly mirrors the SIMD constructions for two reasons: // 1. We promise the same output across all platforms, which means - // we have to perform additions in the same SIMD-friendly order, - // because floating-point addition is not associative. + // we have to perform arithmetic in the same SIMD-friendly order, + // because floating-point arithmetic is not associative. // 2. Expressing individual stages as arrays allows for autovectorization // on platforms we don't have explicit intrinsics for. + assert!(matches!(lane_op, "add" | "mul")); assert_eq!( vec_ty.n_bits(), 128, @@ -854,19 +859,29 @@ fn fallback_reduce_sum(method_sig: TokenStream, vec_ty: &VecType) -> TokenStream let mut level = 0; while previous_len > 1 { - let name = format_ident!("sum_level_{level}"); + let name = format_ident!("{lane_op}_level_{level}"); let next_len = previous_len / 2; - let additions = (0..next_len).map(|index| { + let operations = (0..next_len).map(|index| { let left_index = index * 2; let right_index = left_index + 1; - if vec_ty.scalar == ScalarType::Float { - quote! { #previous[#left_index] + #previous[#right_index] } - } else { - quote! { #previous[#left_index].wrapping_add(#previous[#right_index]) } + match (lane_op, vec_ty.scalar) { + ("add", ScalarType::Float) => { + quote! { #previous[#left_index] + #previous[#right_index] } + } + ("mul", ScalarType::Float) => { + quote! { #previous[#left_index] * #previous[#right_index] } + } + ("add", ScalarType::Int | ScalarType::Unsigned) => { + quote! { #previous[#left_index].wrapping_add(#previous[#right_index]) } + } + ("mul", ScalarType::Int | ScalarType::Unsigned) => { + quote! { #previous[#left_index].wrapping_mul(#previous[#right_index]) } + } + _ => unreachable!("arithmetic reductions only operate on numeric vectors"), } }); statements.push(quote! { - let #name: [#scalar; #next_len] = [#(#additions),*]; + let #name: [#scalar; #next_len] = [#(#operations),*]; }); previous = quote! { #name }; previous_len = next_len; diff --git a/fearless_simd_gen/src/mk_neon.rs b/fearless_simd_gen/src/mk_neon.rs index 21b5cde5..12f0f7a5 100644 --- a/fearless_simd_gen/src/mk_neon.rs +++ b/fearless_simd_gen/src/mk_neon.rs @@ -64,6 +64,59 @@ impl Neon { } } +/// Build the 128-bit leaf of the fixed balanced product tree. +fn neon_reduce_product(vec_ty: &VecType) -> TokenStream { + assert_eq!( + vec_ty.n_bits(), + 128, + "wide reductions must use the generic 128-bit-grained implementation" + ); + + match (vec_ty.scalar, vec_ty.scalar_bits) { + (ScalarType::Float, 64) => quote! { + let a: float64x2_t = a.into(); + vgetq_lane_f64::<0>(a) * vgetq_lane_f64::<1>(a) + }, + (ScalarType::Float, 32) | (ScalarType::Int | ScalarType::Unsigned, 8 | 16 | 32) => { + let native_ty = match (vec_ty.scalar, vec_ty.scalar_bits) { + (ScalarType::Float, 32) => quote! { float32x4_t }, + (ScalarType::Int, 8) => quote! { int8x16_t }, + (ScalarType::Int, 16) => quote! { int16x8_t }, + (ScalarType::Int, 32) => quote! { int32x4_t }, + (ScalarType::Unsigned, 8) => quote! { uint8x16_t }, + (ScalarType::Unsigned, 16) => quote! { uint16x8_t }, + (ScalarType::Unsigned, 32) => quote! { uint32x4_t }, + _ => unreachable!(), + }; + let mul = simple_intrinsic("vmul", vec_ty); + let extract = split_intrinsic("vget", "lane", vec_ty); + let rotate = simple_intrinsic("vext", vec_ty); + let mut stages = Vec::new(); + let mut offset = 1; + while offset < vec_ty.len { + let offset_literal = Literal::i32_unsuffixed(i32::try_from(offset).unwrap()); + stages.push(quote! { + let product = #mul( + product, + #rotate::<#offset_literal>(product, product), + ); + }); + offset *= 2; + } + + quote! { + let product: #native_ty = a.into(); + #(#stages)* + #extract::<0>(product) + } + } + (ScalarType::Int | ScalarType::Unsigned, 64) => { + unreachable!("64-bit integer products must use the fallback implementation") + } + _ => unreachable!("reduce_product only operates on numeric vectors"), + } +} + fn neon_multi_vector_ty(vec_ty: &VecType, count: u16) -> Ident { let scalar = match vec_ty.scalar { ScalarType::Float => "float", @@ -221,6 +274,11 @@ impl Level for Neon { return fallback_method(op, vec_ty); } + if lane_op == "mul" { + let reduce = neon_reduce_product(vec_ty); + return self.kernel_method(op, vec_ty, |_| reduce); + } + let intrinsic = match lane_op { "add" => "vaddv", "min" => "vminv", diff --git a/fearless_simd_gen/src/mk_wasm.rs b/fearless_simd_gen/src/mk_wasm.rs index 21052fc1..7f3c44df 100644 --- a/fearless_simd_gen/src/mk_wasm.rs +++ b/fearless_simd_gen/src/mk_wasm.rs @@ -219,6 +219,113 @@ fn reduce_sum(method_sig: TokenStream, vec_ty: &VecType) -> TokenStream { } } +fn reduce_product(method_sig: TokenStream, vec_ty: &VecType) -> TokenStream { + assert_eq!( + vec_ty.n_bits(), + 128, + "wide reductions must use the generic 128-bit-grained implementation" + ); + + let body = match (vec_ty.scalar, vec_ty.scalar_bits) { + (ScalarType::Float, 32) => quote! { + let a: v128 = a.into(); + let adjacent = f32x4_mul(a, i32x4_shuffle::<1, 0, 3, 2>(a, a)); + let result = f32x4_mul( + adjacent, + i32x4_shuffle::<2, 3, 2, 3>(adjacent, adjacent), + ); + f32x4_extract_lane::<0>(result) + }, + (ScalarType::Float, 64) => quote! { + let a: v128 = a.into(); + let result = f64x2_mul(a, i64x2_shuffle::<1, 1>(a, a)); + f64x2_extract_lane::<0>(result) + }, + (ScalarType::Int | ScalarType::Unsigned, 8) => { + // WASM has no packed 8-bit multiply. Form all eight adjacent pair products + // directly in 16-bit lanes, then finish the reduction with native i16x8 + // multiplies. Keeping the intermediate low 16 bits is sufficient because the + // final result is reduced modulo 2^8. + let widened_ty = VecType::new(vec_ty.scalar, 16, 8); + let extmul = match vec_ty.scalar { + ScalarType::Int => quote! { i16x8_extmul_low_i8x16 }, + ScalarType::Unsigned => quote! { u16x8_extmul_low_u8x16 }, + _ => unreachable!(), + }; + let mul = simple_intrinsic("mul", &widened_ty); + let shuffle = simple_intrinsic("shuffle", &widened_ty); + let extract = simple_intrinsic("extract_lane", &widened_ty); + let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits); + let mut stages = Vec::new(); + let mut offset = widened_ty.len / 2; + while offset > 0 { + let indices = (0..widened_ty.len) + .map(|index| Literal::usize_unsuffixed((index + offset) % widened_ty.len)); + stages.push(quote! { + let product = #mul( + product, + #shuffle::<#(#indices),*>(product, product), + ); + }); + offset /= 2; + } + + quote! { + let a: v128 = a.into(); + let even = i8x16_shuffle::< + 0, 2, 4, 6, 8, 10, 12, 14, + 0, 2, 4, 6, 8, 10, 12, 14, + >(a, a); + let odd = i8x16_shuffle::< + 1, 3, 5, 7, 9, 11, 13, 15, + 1, 3, 5, 7, 9, 11, 13, 15, + >(a, a); + let product = #extmul(even, odd); + #(#stages)* + #extract::<0>(product) as #scalar + } + } + (ScalarType::Int | ScalarType::Unsigned, 16 | 32) => { + let mul = simple_intrinsic("mul", vec_ty); + let shuffle = simple_intrinsic("shuffle", vec_ty); + let extract = simple_intrinsic("extract_lane", vec_ty); + let mut stages = Vec::new(); + let mut offset = vec_ty.len / 2; + while offset > 0 { + let indices = (0..vec_ty.len) + .map(|index| Literal::usize_unsuffixed((index + offset) % vec_ty.len)); + stages.push(quote! { + let product = #mul( + product, + #shuffle::<#(#indices),*>(product, product), + ); + }); + offset /= 2; + } + + quote! { + let product: v128 = a.into(); + #(#stages)* + #extract::<0>(product) + } + } + (ScalarType::Int | ScalarType::Unsigned, 64) => { + let extract = simple_intrinsic("extract_lane", vec_ty); + quote! { + let a: v128 = a.into(); + #extract::<0>(a).wrapping_mul(#extract::<1>(a)) + } + } + _ => unreachable!("reduce_product only operates on numeric vectors"), + }; + + quote! { + #method_sig { + #body + } + } +} + impl Level for WasmSimd128 { fn name(&self) -> &'static str { "WasmSimd128" @@ -344,6 +451,8 @@ impl Level for WasmSimd128 { OpSig::Reduce { lane_op } => { if lane_op == "add" { reduce_sum(method_sig, vec_ty) + } else if lane_op == "mul" { + reduce_product(method_sig, vec_ty) } else if vec_ty.scalar_bits == 64 && matches!(vec_ty.scalar, ScalarType::Int | ScalarType::Unsigned) { diff --git a/fearless_simd_gen/src/mk_x86.rs b/fearless_simd_gen/src/mk_x86.rs index 1bc6838a..fd43bd30 100644 --- a/fearless_simd_gen/src/mk_x86.rs +++ b/fearless_simd_gen/src/mk_x86.rs @@ -318,13 +318,11 @@ impl Level for X86 { OpSig::Splat => self.handle_splat(op, vec_ty), OpSig::Compare => self.handle_compare(op, method, vec_ty), OpSig::Unary => self.handle_unary(op, method_sig, method, vec_ty), - OpSig::Reduce { lane_op } => { - if lane_op == "add" { - self.handle_reduce_sum(op, vec_ty) - } else { - self.handle_reduce_min_max(op, vec_ty, lane_op) - } - } + OpSig::Reduce { lane_op } => match lane_op { + "add" => self.handle_reduce_sum(op, vec_ty), + "mul" => self.handle_reduce_product(op, vec_ty), + _ => self.handle_reduce_min_max(op, vec_ty, lane_op), + }, OpSig::Widen { target_ty } => self.handle_widen(op, vec_ty, target_ty), OpSig::Narrow { target_ty, mode } => self.handle_narrow(op, vec_ty, target_ty, mode), OpSig::Binary => self.handle_binary(op, method, vec_ty), @@ -1338,6 +1336,78 @@ impl X86 { } } + pub(crate) fn handle_reduce_product(&self, op: Op, vec_ty: &VecType) -> TokenStream { + assert_eq!( + vec_ty.n_bits(), + 128, + "wide reductions must use the generic 128-bit-grained implementation" + ); + + match (vec_ty.scalar, vec_ty.scalar_bits) { + (ScalarType::Float, 32) => self.kernel_method(op, vec_ty, |_| { + quote! { + // _mm_hadd_ps has no multiplication equivalent, so explicitly multiply + // adjacent lanes before combining the two pair products. + let a: __m128 = a.into(); + let adjacent = _mm_mul_ps(a, _mm_shuffle_ps::<0b10_11_00_01>(a, a)); + _mm_cvtss_f32(_mm_mul_ss(adjacent, _mm_movehl_ps(adjacent, adjacent))) + } + }), + (ScalarType::Float, 64) => self.kernel_method(op, vec_ty, |_| { + quote! { + let a: __m128d = a.into(); + _mm_cvtsd_f64(_mm_mul_sd(a, _mm_unpackhi_pd(a, a))) + } + }), + (ScalarType::Int | ScalarType::Unsigned, 8) => { + let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits); + let len = vec_ty.len; + self.kernel_method(op, vec_ty, |_| { + quote! { + let value: __m128i = a.into(); + // Multiplication modulo 2^8 is sign-independent. Multiplying each + // packed i16 lane by its high byte puts the adjacent byte product in + // the low byte. Any high-byte terms cannot affect the final low byte + // through the remaining i16 multiplications. + let high = _mm_srli_epi16::<8>(value); + let product = _mm_mullo_epi16(value, high); + let product = + _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = + _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = + _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [#scalar; #len] = + crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + }) + } + (ScalarType::Int | ScalarType::Unsigned, 16) => { + let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits); + let len = vec_ty.len; + self.kernel_method(op, vec_ty, |_| { + quote! { + let product: __m128i = a.into(); + let product = + _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); + let product = + _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + let product = + _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let lanes: [#scalar; #len] = + crate::transmute::checked_transmute_copy(&product); + lanes[0] + } + }) + } + // A scalar balanced leaf is both shorter and avoids depending on packed i32/i64 + // multiplication support that is absent from the lower x86 feature levels. + (ScalarType::Int | ScalarType::Unsigned, 32 | 64) => fallback_method(op, vec_ty), + _ => unreachable!("reduce_product only operates on numeric vectors"), + } + } + pub(crate) fn handle_splat(&self, op: Op, vec_ty: &VecType) -> TokenStream { if *self == Self::Avx512 && vec_ty.scalar == ScalarType::Mask { let lane_mask = avx512_mask_lane_bits(vec_ty); diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index 9ee913ee..79e51ec0 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -649,6 +649,18 @@ const COMMON_BASE_OPS: &[Op] = &[ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ Because floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different.", ), + Op::new( + "reduce_product", + OpKind::BaseTraitMethod, + OpSig::Reduce { lane_op: "mul" }, + "Return the product of all elements in the vector. Integer multiplication wraps.\n\n\ + # Floating-point behavior\n\n\ + Floating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\n\ + Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\n\ + For a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\n\ + This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ + Because floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector.", + ), Op::new( "max", OpKind::BaseTraitMethod, diff --git a/fearless_simd_tests/tests/generics.rs b/fearless_simd_tests/tests/generics.rs index c1f3b72c..5a22f2a9 100644 --- a/fearless_simd_tests/tests/generics.rs +++ b/fearless_simd_tests/tests/generics.rs @@ -85,6 +85,10 @@ fn generic_reduce_sum>(vector: V) -> V::Element { vector.reduce_sum() } +fn generic_reduce_product>(vector: V) -> V::Element { + vector.reduce_product() +} + // Ensure that a generic vector's 128-bit block is its own block fn generic_block_splat>(block: V::Block) -> V::Block { V::Block::block_splat(block) diff --git a/fearless_simd_tests/tests/harness/ops/mod.rs b/fearless_simd_tests/tests/harness/ops/mod.rs index 90acb6a9..c82bbe43 100644 --- a/fearless_simd_tests/tests/harness/ops/mod.rs +++ b/fearless_simd_tests/tests/harness/ops/mod.rs @@ -61,6 +61,7 @@ mod reduce_max; mod reduce_max_precise; mod reduce_min; mod reduce_min_precise; +mod reduce_product; mod reduce_sum; mod reverse; mod rotate_elements_left; From 0a28d38069bf8b99c6449c4bef9b551e9ebe6751 Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 30 Aug 2026 12:50:47 +0100 Subject: [PATCH 2/8] Add tests for reduce_product --- .../tests/harness/ops/reduce_product.rs | 990 ++++++++++++++++++ 1 file changed, 990 insertions(+) create mode 100644 fearless_simd_tests/tests/harness/ops/reduce_product.rs diff --git a/fearless_simd_tests/tests/harness/ops/reduce_product.rs b/fearless_simd_tests/tests/harness/ops/reduce_product.rs new file mode 100644 index 00000000..e8f0d0b3 --- /dev/null +++ b/fearless_simd_tests/tests/harness/ops/reduce_product.rs @@ -0,0 +1,990 @@ +// Copyright 2026 the Fearless_SIMD Authors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use fearless_simd::*; +use fearless_simd_dev_macros::simd_test; + +// Floating-point products use a fixed balanced tree. The large and small +// values below make other plausible reduction orders produce infinity, zero, +// or NaN instead of the expected finite result. + +#[simd_test] +fn reduce_product_f32x4(simd: S) { + assert_eq!( + f32x4::from_slice(simd, &[1.0, 2.0, 3.0, 4.0]).reduce_product(), + 24.0 + ); + + let large = 1.0e30_f32; + let small = 1.0e-30_f32; + assert_eq!( + f32x4::from_slice(simd, &[large, small, large, small]).reduce_product(), + 1.0 + ); + assert!( + f32x4::from_slice(simd, &[large, large, small, small]) + .reduce_product() + .is_nan() + ); + + assert_eq!( + f32x4::from_slice(simd, &[-0.0, 1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + (-0.0_f32).to_bits() + ); + assert_eq!( + f32x4::from_slice(simd, &[-0.0, -1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + 0.0_f32.to_bits() + ); + assert_eq!( + f32x4::from_slice(simd, &[f32::INFINITY, 2.0, 1.0, 1.0]).reduce_product(), + f32::INFINITY + ); + assert_eq!( + f32x4::from_slice(simd, &[f32::MIN_POSITIVE, 0.5, 1.0, 1.0]).reduce_product(), + f32::MIN_POSITIVE * 0.5 + ); + + let nan = f32::NAN; + assert!( + f32x4::from_slice(simd, &[1.0, 1.0, 1.0, nan]) + .reduce_product() + .is_nan() + ); +} + +#[simd_test] +fn reduce_product_f64x2(simd: S) { + assert_eq!(f64x2::from_slice(simd, &[2.0, 3.0]).reduce_product(), 6.0); + + let large = 1.0e300_f64; + let small = 1.0e-300_f64; + assert_eq!( + f64x2::from_slice(simd, &[large, small]).reduce_product(), + 1.0 + ); + + assert_eq!( + f64x2::from_slice(simd, &[-0.0, 1.0]) + .reduce_product() + .to_bits(), + (-0.0_f64).to_bits() + ); + assert_eq!( + f64x2::from_slice(simd, &[-0.0, -1.0]) + .reduce_product() + .to_bits(), + 0.0_f64.to_bits() + ); + assert_eq!( + f64x2::from_slice(simd, &[f64::INFINITY, 2.0]).reduce_product(), + f64::INFINITY + ); + assert!( + f64x2::from_slice(simd, &[f64::INFINITY, 0.0]) + .reduce_product() + .is_nan() + ); + assert_eq!( + f64x2::from_slice(simd, &[f64::MIN_POSITIVE, 0.5]).reduce_product(), + f64::MIN_POSITIVE * 0.5 + ); + + let nan = f64::NAN; + assert!( + f64x2::from_slice(simd, &[1.0, nan]) + .reduce_product() + .is_nan() + ); +} + +#[simd_test] +fn reduce_product_f32x8(simd: S) { + assert_eq!( + f32x8::from_slice(simd, &[2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]).reduce_product(), + 6.0 + ); + + let large = 1.0e30_f32; + let small = 1.0e-30_f32; + assert_eq!( + f32x8::from_slice( + simd, + &[large, large, large, large, small, small, small, small], + ) + .reduce_product(), + 1.0 + ); + assert!( + f32x8::from_slice( + simd, + &[large, large, small, small, large, large, small, small], + ) + .reduce_product() + .is_nan() + ); + + assert_eq!( + f32x8::from_slice(simd, &[-0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + (-0.0_f32).to_bits() + ); + assert_eq!( + f32x8::from_slice(simd, &[-0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + 0.0_f32.to_bits() + ); + assert_eq!( + f32x8::from_slice(simd, &[f32::INFINITY, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],) + .reduce_product(), + f32::INFINITY + ); + + let nan = f32::NAN; + assert!( + f32x8::from_slice(simd, &[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, nan]) + .reduce_product() + .is_nan() + ); +} + +#[simd_test] +fn reduce_product_f64x4(simd: S) { + assert_eq!( + f64x4::from_slice(simd, &[2.0, 3.0, 1.0, 1.0]).reduce_product(), + 6.0 + ); + + let large = 1.0e300_f64; + let small = 1.0e-300_f64; + assert_eq!( + f64x4::from_slice(simd, &[large, large, small, small]).reduce_product(), + 1.0 + ); + assert!( + f64x4::from_slice(simd, &[large, small, large, small]) + .reduce_product() + .is_nan() + ); + + assert_eq!( + f64x4::from_slice(simd, &[-0.0, 1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + (-0.0_f64).to_bits() + ); + assert_eq!( + f64x4::from_slice(simd, &[-0.0, -1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + 0.0_f64.to_bits() + ); + assert_eq!( + f64x4::from_slice(simd, &[f64::INFINITY, 2.0, 1.0, 1.0]).reduce_product(), + f64::INFINITY + ); + + let nan = f64::NAN; + assert!( + f64x4::from_slice(simd, &[1.0, 1.0, 1.0, nan]) + .reduce_product() + .is_nan() + ); +} + +#[simd_test] +fn reduce_product_f32x16(simd: S) { + assert_eq!( + f32x16::from_slice( + simd, + &[ + 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + ], + ) + .reduce_product(), + 6.0 + ); + + let large = 1.0e30_f32; + let small = 1.0e-30_f32; + assert_eq!( + f32x16::from_slice( + simd, + &[ + large, large, large, large, large, large, large, large, small, small, small, small, + small, small, small, small, + ], + ) + .reduce_product(), + 1.0 + ); + assert!( + f32x16::from_slice( + simd, + &[ + large, large, small, small, large, large, small, small, large, large, small, small, + large, large, small, small, + ], + ) + .reduce_product() + .is_nan() + ); + + assert_eq!( + f32x16::from_slice( + simd, + &[ + -0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + ], + ) + .reduce_product() + .to_bits(), + (-0.0_f32).to_bits() + ); + assert_eq!( + f32x16::from_slice( + simd, + &[ + -0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + ], + ) + .reduce_product() + .to_bits(), + 0.0_f32.to_bits() + ); + + let nan = f32::NAN; + assert!( + f32x16::from_slice( + simd, + &[ + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, nan, + ], + ) + .reduce_product() + .is_nan() + ); +} + +#[simd_test] +fn reduce_product_f64x8(simd: S) { + assert_eq!( + f64x8::from_slice(simd, &[2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]).reduce_product(), + 6.0 + ); + + let large = 1.0e300_f64; + let small = 1.0e-300_f64; + assert_eq!( + f64x8::from_slice( + simd, + &[large, large, large, large, small, small, small, small], + ) + .reduce_product(), + 1.0 + ); + assert!( + f64x8::from_slice( + simd, + &[large, large, small, small, large, large, small, small], + ) + .reduce_product() + .is_nan() + ); + + assert_eq!( + f64x8::from_slice(simd, &[-0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + (-0.0_f64).to_bits() + ); + assert_eq!( + f64x8::from_slice(simd, &[-0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + .reduce_product() + .to_bits(), + 0.0_f64.to_bits() + ); + assert_eq!( + f64x8::from_slice(simd, &[f64::INFINITY, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],) + .reduce_product(), + f64::INFINITY + ); + + let nan = f64::NAN; + assert!( + f64x8::from_slice(simd, &[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, nan]) + .reduce_product() + .is_nan() + ); +} + +#[simd_test] +fn reduce_product_i8x16(simd: S) { + let mut ordinary = [1; 16]; + ordinary[0] = 2; + ordinary[1] = 3; + assert_eq!(i8x16::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut multiple_pairs = [1; 16]; + multiple_pairs[0] = 2; + multiple_pairs[1] = 3; + multiple_pairs[2] = 4; + multiple_pairs[3] = 5; + assert_eq!( + i8x16::from_slice(simd, &multiple_pairs).reduce_product(), + 120 + ); + + let mut both_halves = [1; 16]; + both_halves[0] = 2; + both_halves[1] = 3; + both_halves[8] = 4; + both_halves[9] = 5; + assert_eq!(i8x16::from_slice(simd, &both_halves).reduce_product(), 120); + + let mut reversed_high_bits = [1; 16]; + reversed_high_bits[8] = -1; + reversed_high_bits[9] = i8::MIN; + assert_eq!( + i8x16::from_slice(simd, &reversed_high_bits).reduce_product(), + i8::MIN + ); + + let mut negative = [1; 16]; + negative[0] = -2; + negative[1] = 3; + assert_eq!(i8x16::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 16]; + even_negative[0] = -2; + even_negative[1] = -3; + assert_eq!(i8x16::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 16]; + zero[7] = 0; + assert_eq!(i8x16::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 16]; + overflow[0] = i8::MAX; + overflow[1] = 2; + assert_eq!(i8x16::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 16]; + underflow[0] = i8::MIN; + underflow[1] = -1; + assert_eq!( + i8x16::from_slice(simd, &underflow).reduce_product(), + i8::MIN + ); +} + +#[simd_test] +fn reduce_product_u8x16(simd: S) { + let mut ordinary = [1; 16]; + ordinary[0] = 2; + ordinary[1] = 3; + assert_eq!(u8x16::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut multiple_pairs = [1; 16]; + multiple_pairs[0] = 2; + multiple_pairs[1] = 3; + multiple_pairs[2] = 4; + multiple_pairs[3] = 5; + assert_eq!( + u8x16::from_slice(simd, &multiple_pairs).reduce_product(), + 120 + ); + + let mut both_halves = [1; 16]; + both_halves[0] = 2; + both_halves[1] = 3; + both_halves[8] = 4; + both_halves[9] = 5; + assert_eq!(u8x16::from_slice(simd, &both_halves).reduce_product(), 120); + + let mut upper_high_bits = [1; 16]; + upper_high_bits[8] = u8::MAX; + upper_high_bits[9] = 128; + assert_eq!( + u8x16::from_slice(simd, &upper_high_bits).reduce_product(), + 128 + ); + + let mut zero = [1; 16]; + zero[7] = 0; + assert_eq!(u8x16::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 16]; + overflow[0] = u8::MAX; + overflow[1] = 2; + assert_eq!( + u8x16::from_slice(simd, &overflow).reduce_product(), + u8::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i16x8(simd: S) { + let mut ordinary = [1; 8]; + ordinary[0] = 2; + ordinary[1] = 3; + assert_eq!(i16x8::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut both_halves = [1; 8]; + both_halves[0] = 2; + both_halves[1] = 3; + both_halves[4] = 4; + both_halves[5] = 5; + assert_eq!(i16x8::from_slice(simd, &both_halves).reduce_product(), 120); + + let mut negative = [1; 8]; + negative[0] = -2; + negative[1] = 3; + assert_eq!(i16x8::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 8]; + even_negative[0] = -2; + even_negative[1] = -3; + assert_eq!(i16x8::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 8]; + zero[3] = 0; + assert_eq!(i16x8::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 8]; + overflow[0] = i16::MAX; + overflow[1] = 2; + assert_eq!(i16x8::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 8]; + underflow[0] = i16::MIN; + underflow[1] = -1; + assert_eq!( + i16x8::from_slice(simd, &underflow).reduce_product(), + i16::MIN + ); +} + +#[simd_test] +fn reduce_product_u16x8(simd: S) { + let mut ordinary = [1; 8]; + ordinary[0] = 2; + ordinary[1] = 3; + assert_eq!(u16x8::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut both_halves = [1; 8]; + both_halves[0] = 2; + both_halves[1] = 3; + both_halves[4] = 4; + both_halves[5] = 5; + assert_eq!(u16x8::from_slice(simd, &both_halves).reduce_product(), 120); + + let mut zero = [1; 8]; + zero[3] = 0; + assert_eq!(u16x8::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 8]; + overflow[0] = u16::MAX; + overflow[1] = 2; + assert_eq!( + u16x8::from_slice(simd, &overflow).reduce_product(), + u16::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i32x4(simd: S) { + let ordinary = [2, 3, 1, 1]; + assert_eq!(i32x4::from_slice(simd, &ordinary).reduce_product(), 6); + + let all_lanes = [2, 3, 5, 7]; + assert_eq!(i32x4::from_slice(simd, &all_lanes).reduce_product(), 210); + + let negative = [-2, 3, 1, 1]; + assert_eq!(i32x4::from_slice(simd, &negative).reduce_product(), -6); + + let even_negative = [-2, -3, 1, 1]; + assert_eq!(i32x4::from_slice(simd, &even_negative).reduce_product(), 6); + + let zero = [1, 1, 0, 1]; + assert_eq!(i32x4::from_slice(simd, &zero).reduce_product(), 0); + + let overflow = [i32::MAX, 2, 1, 1]; + assert_eq!(i32x4::from_slice(simd, &overflow).reduce_product(), -2); + + let underflow = [i32::MIN, -1, 1, 1]; + assert_eq!( + i32x4::from_slice(simd, &underflow).reduce_product(), + i32::MIN + ); +} + +#[simd_test] +fn reduce_product_u32x4(simd: S) { + let ordinary = [2, 3, 1, 1]; + assert_eq!(u32x4::from_slice(simd, &ordinary).reduce_product(), 6); + + let all_lanes = [2, 3, 5, 7]; + assert_eq!(u32x4::from_slice(simd, &all_lanes).reduce_product(), 210); + + let zero = [1, 1, 0, 1]; + assert_eq!(u32x4::from_slice(simd, &zero).reduce_product(), 0); + + let overflow = [u32::MAX, 2, 1, 1]; + assert_eq!( + u32x4::from_slice(simd, &overflow).reduce_product(), + u32::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i64x2(simd: S) { + assert_eq!(i64x2::from_slice(simd, &[2, 3]).reduce_product(), 6); + assert_eq!(i64x2::from_slice(simd, &[-2, 3]).reduce_product(), -6); + assert_eq!(i64x2::from_slice(simd, &[-2, -3]).reduce_product(), 6); + assert_eq!(i64x2::from_slice(simd, &[0, 3]).reduce_product(), 0); + assert_eq!(i64x2::from_slice(simd, &[i64::MAX, 2]).reduce_product(), -2); + assert_eq!( + i64x2::from_slice(simd, &[i64::MIN, -1]).reduce_product(), + i64::MIN + ); +} + +#[simd_test] +fn reduce_product_u64x2(simd: S) { + assert_eq!(u64x2::from_slice(simd, &[2, 3]).reduce_product(), 6); + assert_eq!(u64x2::from_slice(simd, &[0, 3]).reduce_product(), 0); + assert_eq!( + u64x2::from_slice(simd, &[u64::MAX, 2]).reduce_product(), + u64::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i8x32(simd: S) { + let mut ordinary = [1; 32]; + ordinary[0] = 2; + ordinary[16] = 3; + assert_eq!(i8x32::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 32]; + negative[0] = -2; + negative[16] = 3; + assert_eq!(i8x32::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 32]; + even_negative[0] = -2; + even_negative[16] = -3; + assert_eq!(i8x32::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 32]; + zero[15] = 0; + assert_eq!(i8x32::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 32]; + overflow[0] = i8::MAX; + overflow[16] = 2; + assert_eq!(i8x32::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 32]; + underflow[0] = i8::MIN; + underflow[16] = -1; + assert_eq!( + i8x32::from_slice(simd, &underflow).reduce_product(), + i8::MIN + ); +} + +#[simd_test] +fn reduce_product_u8x32(simd: S) { + let mut ordinary = [1; 32]; + ordinary[0] = 2; + ordinary[16] = 3; + assert_eq!(u8x32::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 32]; + zero[15] = 0; + assert_eq!(u8x32::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 32]; + overflow[0] = u8::MAX; + overflow[16] = 2; + assert_eq!( + u8x32::from_slice(simd, &overflow).reduce_product(), + u8::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i16x16(simd: S) { + let mut ordinary = [1; 16]; + ordinary[0] = 2; + ordinary[8] = 3; + assert_eq!(i16x16::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 16]; + negative[0] = -2; + negative[8] = 3; + assert_eq!(i16x16::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 16]; + even_negative[0] = -2; + even_negative[8] = -3; + assert_eq!(i16x16::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 16]; + zero[7] = 0; + assert_eq!(i16x16::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 16]; + overflow[0] = i16::MAX; + overflow[8] = 2; + assert_eq!(i16x16::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 16]; + underflow[0] = i16::MIN; + underflow[8] = -1; + assert_eq!( + i16x16::from_slice(simd, &underflow).reduce_product(), + i16::MIN + ); +} + +#[simd_test] +fn reduce_product_u16x16(simd: S) { + let mut ordinary = [1; 16]; + ordinary[0] = 2; + ordinary[8] = 3; + assert_eq!(u16x16::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 16]; + zero[7] = 0; + assert_eq!(u16x16::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 16]; + overflow[0] = u16::MAX; + overflow[8] = 2; + assert_eq!( + u16x16::from_slice(simd, &overflow).reduce_product(), + u16::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i32x8(simd: S) { + let mut ordinary = [1; 8]; + ordinary[0] = 2; + ordinary[4] = 3; + assert_eq!(i32x8::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 8]; + negative[0] = -2; + negative[4] = 3; + assert_eq!(i32x8::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 8]; + even_negative[0] = -2; + even_negative[4] = -3; + assert_eq!(i32x8::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 8]; + zero[3] = 0; + assert_eq!(i32x8::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 8]; + overflow[0] = i32::MAX; + overflow[4] = 2; + assert_eq!(i32x8::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 8]; + underflow[0] = i32::MIN; + underflow[4] = -1; + assert_eq!( + i32x8::from_slice(simd, &underflow).reduce_product(), + i32::MIN + ); +} + +#[simd_test] +fn reduce_product_u32x8(simd: S) { + let mut ordinary = [1; 8]; + ordinary[0] = 2; + ordinary[4] = 3; + assert_eq!(u32x8::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 8]; + zero[3] = 0; + assert_eq!(u32x8::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 8]; + overflow[0] = u32::MAX; + overflow[4] = 2; + assert_eq!( + u32x8::from_slice(simd, &overflow).reduce_product(), + u32::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i64x4(simd: S) { + let ordinary = [2, 1, 3, 1]; + assert_eq!(i64x4::from_slice(simd, &ordinary).reduce_product(), 6); + + let negative = [-2, 1, 3, 1]; + assert_eq!(i64x4::from_slice(simd, &negative).reduce_product(), -6); + + let even_negative = [-2, 1, -3, 1]; + assert_eq!(i64x4::from_slice(simd, &even_negative).reduce_product(), 6); + + let zero = [1, 0, 1, 1]; + assert_eq!(i64x4::from_slice(simd, &zero).reduce_product(), 0); + + let overflow = [i64::MAX, 1, 2, 1]; + assert_eq!(i64x4::from_slice(simd, &overflow).reduce_product(), -2); + + let underflow = [i64::MIN, 1, -1, 1]; + assert_eq!( + i64x4::from_slice(simd, &underflow).reduce_product(), + i64::MIN + ); +} + +#[simd_test] +fn reduce_product_u64x4(simd: S) { + let ordinary = [2, 1, 3, 1]; + assert_eq!(u64x4::from_slice(simd, &ordinary).reduce_product(), 6); + + let zero = [1, 0, 1, 1]; + assert_eq!(u64x4::from_slice(simd, &zero).reduce_product(), 0); + + let overflow = [u64::MAX, 1, 2, 1]; + assert_eq!( + u64x4::from_slice(simd, &overflow).reduce_product(), + u64::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i8x64(simd: S) { + let mut ordinary = [1; 64]; + ordinary[0] = 2; + ordinary[32] = 3; + assert_eq!(i8x64::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 64]; + negative[0] = -2; + negative[32] = 3; + assert_eq!(i8x64::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 64]; + even_negative[0] = -2; + even_negative[32] = -3; + assert_eq!(i8x64::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 64]; + zero[31] = 0; + assert_eq!(i8x64::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 64]; + overflow[0] = i8::MAX; + overflow[32] = 2; + assert_eq!(i8x64::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 64]; + underflow[0] = i8::MIN; + underflow[32] = -1; + assert_eq!( + i8x64::from_slice(simd, &underflow).reduce_product(), + i8::MIN + ); +} + +#[simd_test] +fn reduce_product_u8x64(simd: S) { + let mut ordinary = [1; 64]; + ordinary[0] = 2; + ordinary[32] = 3; + assert_eq!(u8x64::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 64]; + zero[31] = 0; + assert_eq!(u8x64::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 64]; + overflow[0] = u8::MAX; + overflow[32] = 2; + assert_eq!( + u8x64::from_slice(simd, &overflow).reduce_product(), + u8::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i16x32(simd: S) { + let mut ordinary = [1; 32]; + ordinary[0] = 2; + ordinary[16] = 3; + assert_eq!(i16x32::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 32]; + negative[0] = -2; + negative[16] = 3; + assert_eq!(i16x32::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 32]; + even_negative[0] = -2; + even_negative[16] = -3; + assert_eq!(i16x32::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 32]; + zero[15] = 0; + assert_eq!(i16x32::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 32]; + overflow[0] = i16::MAX; + overflow[16] = 2; + assert_eq!(i16x32::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 32]; + underflow[0] = i16::MIN; + underflow[16] = -1; + assert_eq!( + i16x32::from_slice(simd, &underflow).reduce_product(), + i16::MIN + ); +} + +#[simd_test] +fn reduce_product_u16x32(simd: S) { + let mut ordinary = [1; 32]; + ordinary[0] = 2; + ordinary[16] = 3; + assert_eq!(u16x32::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 32]; + zero[15] = 0; + assert_eq!(u16x32::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 32]; + overflow[0] = u16::MAX; + overflow[16] = 2; + assert_eq!( + u16x32::from_slice(simd, &overflow).reduce_product(), + u16::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i32x16(simd: S) { + let mut ordinary = [1; 16]; + ordinary[0] = 2; + ordinary[8] = 3; + assert_eq!(i32x16::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 16]; + negative[0] = -2; + negative[8] = 3; + assert_eq!(i32x16::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 16]; + even_negative[0] = -2; + even_negative[8] = -3; + assert_eq!(i32x16::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 16]; + zero[7] = 0; + assert_eq!(i32x16::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 16]; + overflow[0] = i32::MAX; + overflow[8] = 2; + assert_eq!(i32x16::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 16]; + underflow[0] = i32::MIN; + underflow[8] = -1; + assert_eq!( + i32x16::from_slice(simd, &underflow).reduce_product(), + i32::MIN + ); +} + +#[simd_test] +fn reduce_product_u32x16(simd: S) { + let mut ordinary = [1; 16]; + ordinary[0] = 2; + ordinary[8] = 3; + assert_eq!(u32x16::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 16]; + zero[7] = 0; + assert_eq!(u32x16::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 16]; + overflow[0] = u32::MAX; + overflow[8] = 2; + assert_eq!( + u32x16::from_slice(simd, &overflow).reduce_product(), + u32::MAX - 1 + ); +} + +#[simd_test] +fn reduce_product_i64x8(simd: S) { + let mut ordinary = [1; 8]; + ordinary[0] = 2; + ordinary[4] = 3; + assert_eq!(i64x8::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut negative = [1; 8]; + negative[0] = -2; + negative[4] = 3; + assert_eq!(i64x8::from_slice(simd, &negative).reduce_product(), -6); + + let mut even_negative = [1; 8]; + even_negative[0] = -2; + even_negative[4] = -3; + assert_eq!(i64x8::from_slice(simd, &even_negative).reduce_product(), 6); + + let mut zero = [1; 8]; + zero[3] = 0; + assert_eq!(i64x8::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 8]; + overflow[0] = i64::MAX; + overflow[4] = 2; + assert_eq!(i64x8::from_slice(simd, &overflow).reduce_product(), -2); + + let mut underflow = [1; 8]; + underflow[0] = i64::MIN; + underflow[4] = -1; + assert_eq!( + i64x8::from_slice(simd, &underflow).reduce_product(), + i64::MIN + ); +} + +#[simd_test] +fn reduce_product_u64x8(simd: S) { + let mut ordinary = [1; 8]; + ordinary[0] = 2; + ordinary[4] = 3; + assert_eq!(u64x8::from_slice(simd, &ordinary).reduce_product(), 6); + + let mut zero = [1; 8]; + zero[3] = 0; + assert_eq!(u64x8::from_slice(simd, &zero).reduce_product(), 0); + + let mut overflow = [1; 8]; + overflow[0] = u64::MAX; + overflow[4] = 2; + assert_eq!( + u64x8::from_slice(simd, &overflow).reduce_product(), + u64::MAX - 1 + ); +} From 1542be3bb1b99c62223f7f0d3ebb0822219b5658 Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 30 Aug 2026 12:51:12 +0100 Subject: [PATCH 3/8] Optimize WASM implementation of reduce_product --- fearless_simd/src/generated/wasm.rs | 98 ++++++++--------------------- fearless_simd_gen/src/mk_wasm.rs | 89 +++++++++----------------- 2 files changed, 55 insertions(+), 132 deletions(-) diff --git a/fearless_simd/src/generated/wasm.rs b/fearless_simd/src/generated/wasm.rs index fd19072f..377577c3 100644 --- a/fearless_simd/src/generated/wasm.rs +++ b/fearless_simd/src/generated/wasm.rs @@ -309,9 +309,8 @@ impl Simd for WasmSimd128 { #[inline(always)] fn reduce_product_f32x4(self, a: f32x4) -> f32 { let a: v128 = a.into(); - let adjacent = f32x4_mul(a, i32x4_shuffle::<1, 0, 3, 2>(a, a)); - let result = f32x4_mul(adjacent, i32x4_shuffle::<2, 3, 2, 3>(adjacent, adjacent)); - f32x4_extract_lane::<0>(result) + let adjacent = f32x4_mul(a, u64x2_shr(a, 32)); + f32x4_extract_lane::<0>(adjacent) * f32x4_extract_lane::<2>(adjacent) } #[inline(always)] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4 { @@ -739,22 +738,10 @@ impl Simd for WasmSimd128 { #[inline(always)] fn reduce_product_i8x16(self, a: i8x16) -> i8 { let a: v128 = a.into(); - let even = i8x16_shuffle::<0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14>(a, a); - let odd = i8x16_shuffle::<1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15>(a, a); - let product = i16x8_extmul_low_i8x16(even, odd); - let product = i16x8_mul( - product, - i16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), - ); - let product = i16x8_mul( - product, - i16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), - ); - let product = i16x8_mul( - product, - i16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), - ); - i16x8_extract_lane::<0>(product) as i8 + let product = i16x8_mul(a, u16x8_shr(a, 8)); + let product = i16x8_mul(product, u64x2_shr(product, 32)); + let product = i16x8_mul(product, u32x4_shr(product, 16)); + i16x8_extract_lane::<0>(product).wrapping_mul(i16x8_extract_lane::<4>(product)) as i8 } #[inline(always)] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16 { @@ -1141,22 +1128,10 @@ impl Simd for WasmSimd128 { #[inline(always)] fn reduce_product_u8x16(self, a: u8x16) -> u8 { let a: v128 = a.into(); - let even = i8x16_shuffle::<0, 2, 4, 6, 8, 10, 12, 14, 0, 2, 4, 6, 8, 10, 12, 14>(a, a); - let odd = i8x16_shuffle::<1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15>(a, a); - let product = u16x8_extmul_low_u8x16(even, odd); - let product = u16x8_mul( - product, - u16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), - ); - let product = u16x8_mul( - product, - u16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), - ); - let product = u16x8_mul( - product, - u16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), - ); - u16x8_extract_lane::<0>(product) as u8 + let product = u16x8_mul(a, u16x8_shr(a, 8)); + let product = u16x8_mul(product, u64x2_shr(product, 32)); + let product = u16x8_mul(product, u32x4_shr(product, 16)); + u16x8_extract_lane::<0>(product).wrapping_mul(u16x8_extract_lane::<4>(product)) as u8 } #[inline(always)] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16 { @@ -1549,20 +1524,10 @@ impl Simd for WasmSimd128 { } #[inline(always)] fn reduce_product_i16x8(self, a: i16x8) -> i16 { - let product: v128 = a.into(); - let product = i16x8_mul( - product, - i16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), - ); - let product = i16x8_mul( - product, - i16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), - ); - let product = i16x8_mul( - product, - i16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), - ); - i16x8_extract_lane::<0>(product) + let a: v128 = a.into(); + let product = i16x8_mul(a, u64x2_shr(a, 32)); + let product = i16x8_mul(product, u32x4_shr(product, 16)); + i16x8_extract_lane::<0>(product).wrapping_mul(i16x8_extract_lane::<4>(product)) } #[inline(always)] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8 { @@ -1842,20 +1807,10 @@ impl Simd for WasmSimd128 { } #[inline(always)] fn reduce_product_u16x8(self, a: u16x8) -> u16 { - let product: v128 = a.into(); - let product = u16x8_mul( - product, - u16x8_shuffle::<4, 5, 6, 7, 0, 1, 2, 3>(product, product), - ); - let product = u16x8_mul( - product, - u16x8_shuffle::<2, 3, 4, 5, 6, 7, 0, 1>(product, product), - ); - let product = u16x8_mul( - product, - u16x8_shuffle::<1, 2, 3, 4, 5, 6, 7, 0>(product, product), - ); - u16x8_extract_lane::<0>(product) + let a: v128 = a.into(); + let product = u16x8_mul(a, u64x2_shr(a, 32)); + let product = u16x8_mul(product, u32x4_shr(product, 16)); + u16x8_extract_lane::<0>(product).wrapping_mul(u16x8_extract_lane::<4>(product)) } #[inline(always)] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8 { @@ -2212,10 +2167,9 @@ impl Simd for WasmSimd128 { } #[inline(always)] fn reduce_product_i32x4(self, a: i32x4) -> i32 { - let product: v128 = a.into(); - let product = i32x4_mul(product, i32x4_shuffle::<2, 3, 0, 1>(product, product)); - let product = i32x4_mul(product, i32x4_shuffle::<1, 2, 3, 0>(product, product)); - i32x4_extract_lane::<0>(product) + let a: v128 = a.into(); + let product = i32x4_mul(a, u64x2_shr(a, 32)); + i32x4_extract_lane::<0>(product).wrapping_mul(i32x4_extract_lane::<2>(product)) } #[inline(always)] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4 { @@ -2481,10 +2435,9 @@ impl Simd for WasmSimd128 { } #[inline(always)] fn reduce_product_u32x4(self, a: u32x4) -> u32 { - let product: v128 = a.into(); - let product = u32x4_mul(product, u32x4_shuffle::<2, 3, 0, 1>(product, product)); - let product = u32x4_mul(product, u32x4_shuffle::<1, 2, 3, 0>(product, product)); - u32x4_extract_lane::<0>(product) + let a: v128 = a.into(); + let product = u32x4_mul(a, u64x2_shr(a, 32)); + u32x4_extract_lane::<0>(product).wrapping_mul(u32x4_extract_lane::<2>(product)) } #[inline(always)] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4 { @@ -2829,8 +2782,7 @@ impl Simd for WasmSimd128 { #[inline(always)] fn reduce_product_f64x2(self, a: f64x2) -> f64 { let a: v128 = a.into(); - let result = f64x2_mul(a, i64x2_shuffle::<1, 1>(a, a)); - f64x2_extract_lane::<0>(result) + f64x2_extract_lane::<0>(a) * f64x2_extract_lane::<1>(a) } #[inline(always)] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2 { diff --git a/fearless_simd_gen/src/mk_wasm.rs b/fearless_simd_gen/src/mk_wasm.rs index 7f3c44df..21ce3180 100644 --- a/fearless_simd_gen/src/mk_wasm.rs +++ b/fearless_simd_gen/src/mk_wasm.rs @@ -229,84 +229,55 @@ fn reduce_product(method_sig: TokenStream, vec_ty: &VecType) -> TokenStream { let body = match (vec_ty.scalar, vec_ty.scalar_bits) { (ScalarType::Float, 32) => quote! { let a: v128 = a.into(); - let adjacent = f32x4_mul(a, i32x4_shuffle::<1, 0, 3, 2>(a, a)); - let result = f32x4_mul( - adjacent, - i32x4_shuffle::<2, 3, 2, 3>(adjacent, adjacent), - ); - f32x4_extract_lane::<0>(result) + // Shifting each 64-bit half places lanes 1 and 3 in lanes 0 and 2, + // respectively. Only those two products feed the result, preserving + // the promised adjacent balanced tree exactly. The multiplications by + // zero in the unused lanes have no observable status flags in WASM. + let adjacent = f32x4_mul(a, u64x2_shr(a, 32)); + f32x4_extract_lane::<0>(adjacent) * f32x4_extract_lane::<2>(adjacent) }, (ScalarType::Float, 64) => quote! { let a: v128 = a.into(); - let result = f64x2_mul(a, i64x2_shuffle::<1, 1>(a, a)); - f64x2_extract_lane::<0>(result) + f64x2_extract_lane::<0>(a) * f64x2_extract_lane::<1>(a) }, (ScalarType::Int | ScalarType::Unsigned, 8) => { - // WASM has no packed 8-bit multiply. Form all eight adjacent pair products - // directly in 16-bit lanes, then finish the reduction with native i16x8 - // multiplies. Keeping the intermediate low 16 bits is sufficient because the - // final result is reduced modulo 2^8. + // WASM has no packed 8-bit multiply. Reinterpret each adjacent byte pair as + // the 16-bit value `even + 256 * odd`, shift out `odd`, and multiply. The low + // byte is `even * odd` modulo 2^8; pollution in the high byte cannot affect + // the final low byte through subsequent multiplications. let widened_ty = VecType::new(vec_ty.scalar, 16, 8); - let extmul = match vec_ty.scalar { - ScalarType::Int => quote! { i16x8_extmul_low_i8x16 }, - ScalarType::Unsigned => quote! { u16x8_extmul_low_u8x16 }, - _ => unreachable!(), - }; let mul = simple_intrinsic("mul", &widened_ty); - let shuffle = simple_intrinsic("shuffle", &widened_ty); let extract = simple_intrinsic("extract_lane", &widened_ty); let scalar = vec_ty.scalar.rust(vec_ty.scalar_bits); - let mut stages = Vec::new(); - let mut offset = widened_ty.len / 2; - while offset > 0 { - let indices = (0..widened_ty.len) - .map(|index| Literal::usize_unsuffixed((index + offset) % widened_ty.len)); - stages.push(quote! { - let product = #mul( - product, - #shuffle::<#(#indices),*>(product, product), - ); - }); - offset /= 2; - } quote! { let a: v128 = a.into(); - let even = i8x16_shuffle::< - 0, 2, 4, 6, 8, 10, 12, 14, - 0, 2, 4, 6, 8, 10, 12, 14, - >(a, a); - let odd = i8x16_shuffle::< - 1, 3, 5, 7, 9, 11, 13, 15, - 1, 3, 5, 7, 9, 11, 13, 15, - >(a, a); - let product = #extmul(even, odd); - #(#stages)* - #extract::<0>(product) as #scalar + let product = #mul(a, u16x8_shr(a, 8)); + let product = #mul(product, u64x2_shr(product, 32)); + let product = #mul(product, u32x4_shr(product, 16)); + #extract::<0>(product) + .wrapping_mul(#extract::<4>(product)) as #scalar } } - (ScalarType::Int | ScalarType::Unsigned, 16 | 32) => { + (ScalarType::Int | ScalarType::Unsigned, 16) => { let mul = simple_intrinsic("mul", vec_ty); - let shuffle = simple_intrinsic("shuffle", vec_ty); let extract = simple_intrinsic("extract_lane", vec_ty); - let mut stages = Vec::new(); - let mut offset = vec_ty.len / 2; - while offset > 0 { - let indices = (0..vec_ty.len) - .map(|index| Literal::usize_unsuffixed((index + offset) % vec_ty.len)); - stages.push(quote! { - let product = #mul( - product, - #shuffle::<#(#indices),*>(product, product), - ); - }); - offset /= 2; + + quote! { + let a: v128 = a.into(); + let product = #mul(a, u64x2_shr(a, 32)); + let product = #mul(product, u32x4_shr(product, 16)); + #extract::<0>(product).wrapping_mul(#extract::<4>(product)) } + } + (ScalarType::Int | ScalarType::Unsigned, 32) => { + let mul = simple_intrinsic("mul", vec_ty); + let extract = simple_intrinsic("extract_lane", vec_ty); quote! { - let product: v128 = a.into(); - #(#stages)* - #extract::<0>(product) + let a: v128 = a.into(); + let product = #mul(a, u64x2_shr(a, 32)); + #extract::<0>(product).wrapping_mul(#extract::<2>(product)) } } (ScalarType::Int | ScalarType::Unsigned, 64) => { From f7a62ac6e724b65169c23e41640f0a9eec674144 Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 30 Aug 2026 13:01:26 +0100 Subject: [PATCH 4/8] Specialize u8/i8/u16/i16 paths for up to 15% boost for 8-bit and up to 33% boost for 16-bit --- fearless_simd/src/generated/avx2.rs | 36 +++++++++------- fearless_simd/src/generated/avx512.rs | 36 +++++++++------- fearless_simd/src/generated/sse2.rs | 36 +++++++++------- fearless_simd/src/generated/sse4_2.rs | 36 +++++++++------- fearless_simd_gen/src/mk_x86.rs | 43 ++++++++++++------- .../tests/harness/ops/reduce_product.rs | 28 ++++++++++++ 6 files changed, 135 insertions(+), 80 deletions(-) diff --git a/fearless_simd/src/generated/avx2.rs b/fearless_simd/src/generated/avx2.rs index f04cbf16..20484fe5 100644 --- a/fearless_simd/src/generated/avx2.rs +++ b/fearless_simd/src/generated/avx2.rs @@ -1003,11 +1003,13 @@ impl Simd for Avx2 { #[inline(always)] fn kernel(token: Avx2, a: i8x16) -> i8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -1582,11 +1584,13 @@ impl Simd for Avx2 { #[inline(always)] fn kernel(token: Avx2, a: u8x16) -> u8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2249,9 +2253,9 @@ impl Simd for Avx2 { #[inline(always)] fn kernel(token: Avx2, a: i16x8) -> i16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2777,9 +2781,9 @@ impl Simd for Avx2 { #[inline(always)] fn kernel(token: Avx2, a: u16x8) -> u16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } diff --git a/fearless_simd/src/generated/avx512.rs b/fearless_simd/src/generated/avx512.rs index 243fed0a..5beda57c 100644 --- a/fearless_simd/src/generated/avx512.rs +++ b/fearless_simd/src/generated/avx512.rs @@ -1205,11 +1205,13 @@ impl Simd for Avx512 { #[inline(always)] fn kernel(token: Avx512, a: i8x16) -> i8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -1770,11 +1772,13 @@ impl Simd for Avx512 { #[inline(always)] fn kernel(token: Avx512, a: u8x16) -> u8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2352,9 +2356,9 @@ impl Simd for Avx512 { #[inline(always)] fn kernel(token: Avx512, a: i16x8) -> i16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2848,9 +2852,9 @@ impl Simd for Avx512 { #[inline(always)] fn kernel(token: Avx512, a: u16x8) -> u16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } diff --git a/fearless_simd/src/generated/sse2.rs b/fearless_simd/src/generated/sse2.rs index a4c0ab1c..ebcadaf3 100644 --- a/fearless_simd/src/generated/sse2.rs +++ b/fearless_simd/src/generated/sse2.rs @@ -1160,11 +1160,13 @@ impl Simd for Sse2 { #[inline(always)] fn kernel(token: Sse2, a: i8x16) -> i8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -1873,11 +1875,13 @@ impl Simd for Sse2 { #[inline(always)] fn kernel(token: Sse2, a: u8x16) -> u8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2608,9 +2612,9 @@ impl Simd for Sse2 { #[inline(always)] fn kernel(token: Sse2, a: i16x8) -> i16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -3193,9 +3197,9 @@ impl Simd for Sse2 { #[inline(always)] fn kernel(token: Sse2, a: u16x8) -> u16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } diff --git a/fearless_simd/src/generated/sse4_2.rs b/fearless_simd/src/generated/sse4_2.rs index bc3f62f7..0155a281 100644 --- a/fearless_simd/src/generated/sse4_2.rs +++ b/fearless_simd/src/generated/sse4_2.rs @@ -1153,11 +1153,13 @@ impl Simd for Sse4_2 { #[inline(always)] fn kernel(token: Sse4_2, a: i8x16) -> i8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -1737,11 +1739,13 @@ impl Simd for Sse4_2 { #[inline(always)] fn kernel(token: Sse4_2, a: u8x16) -> u8 { let value: __m128i = a.into(); - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u8; 16usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2406,9 +2410,9 @@ impl Simd for Sse4_2 { #[inline(always)] fn kernel(token: Sse4_2, a: i16x8) -> i16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [i16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } @@ -2935,9 +2939,9 @@ impl Simd for Sse4_2 { #[inline(always)] fn kernel(token: Sse4_2, a: u16x8) -> u16 { let product: __m128i = a.into(); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b11_10_11_10>(product)); + let product = _mm_mullo_epi16(product, _mm_shuffle_epi32::<0b01_01_01_01>(product)); + let product = _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [u16; 8usize] = crate::transmute::checked_transmute_copy(&product); lanes[0] } diff --git a/fearless_simd_gen/src/mk_x86.rs b/fearless_simd_gen/src/mk_x86.rs index fd43bd30..078a0926 100644 --- a/fearless_simd_gen/src/mk_x86.rs +++ b/fearless_simd_gen/src/mk_x86.rs @@ -1365,18 +1365,25 @@ impl X86 { self.kernel_method(op, vec_ty, |_| { quote! { let value: __m128i = a.into(); - // Multiplication modulo 2^8 is sign-independent. Multiplying each - // packed i16 lane by its high byte puts the adjacent byte product in - // the low byte. Any high-byte terms cannot affect the final low byte - // through the remaining i16 multiplications. - let high = _mm_srli_epi16::<8>(value); - let product = _mm_mullo_epi16(value, high); - let product = - _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = - _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); + // Multiplication modulo 2^8 is sign-independent. Unpacking each byte + // with itself makes an i16 lane whose low byte is still the original + // value. Multiply corresponding lanes from the low and high halves, + // then use a balanced pshufd tree. Pollution in the high byte cannot + // affect the final low byte through the remaining i16 multiplications. + let product = _mm_mullo_epi16( + _mm_unpacklo_epi8(value, value), + _mm_unpackhi_epi8(value, value), + ); + let product = _mm_mullo_epi16( + product, + _mm_shuffle_epi32::<0b11_10_11_10>(product), + ); + let product = _mm_mullo_epi16( + product, + _mm_shuffle_epi32::<0b01_01_01_01>(product), + ); let product = - _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [#scalar; #len] = crate::transmute::checked_transmute_copy(&product); lanes[0] @@ -1389,12 +1396,16 @@ impl X86 { self.kernel_method(op, vec_ty, |_| { quote! { let product: __m128i = a.into(); + let product = _mm_mullo_epi16( + product, + _mm_shuffle_epi32::<0b11_10_11_10>(product), + ); + let product = _mm_mullo_epi16( + product, + _mm_shuffle_epi32::<0b01_01_01_01>(product), + ); let product = - _mm_mullo_epi16(product, _mm_srli_si128::<8>(product)); - let product = - _mm_mullo_epi16(product, _mm_srli_si128::<4>(product)); - let product = - _mm_mullo_epi16(product, _mm_srli_si128::<2>(product)); + _mm_mullo_epi16(product, _mm_srli_epi32::<16>(product)); let lanes: [#scalar; #len] = crate::transmute::checked_transmute_copy(&product); lanes[0] diff --git a/fearless_simd_tests/tests/harness/ops/reduce_product.rs b/fearless_simd_tests/tests/harness/ops/reduce_product.rs index e8f0d0b3..45fa109d 100644 --- a/fearless_simd_tests/tests/harness/ops/reduce_product.rs +++ b/fearless_simd_tests/tests/harness/ops/reduce_product.rs @@ -347,6 +347,13 @@ fn reduce_product_i8x16(simd: S) { both_halves[9] = 5; assert_eq!(i8x16::from_slice(simd, &both_halves).reduce_product(), 120); + let mut all_stages = [1; 16]; + all_stages[12] = 2; + all_stages[13] = 3; + all_stages[14] = 4; + all_stages[15] = 5; + assert_eq!(i8x16::from_slice(simd, &all_stages).reduce_product(), 120); + let mut reversed_high_bits = [1; 16]; reversed_high_bits[8] = -1; reversed_high_bits[9] = i8::MIN; @@ -407,6 +414,13 @@ fn reduce_product_u8x16(simd: S) { both_halves[9] = 5; assert_eq!(u8x16::from_slice(simd, &both_halves).reduce_product(), 120); + let mut all_stages = [1; 16]; + all_stages[12] = 2; + all_stages[13] = 3; + all_stages[14] = 4; + all_stages[15] = 5; + assert_eq!(u8x16::from_slice(simd, &all_stages).reduce_product(), 120); + let mut upper_high_bits = [1; 16]; upper_high_bits[8] = u8::MAX; upper_high_bits[9] = 128; @@ -442,6 +456,13 @@ fn reduce_product_i16x8(simd: S) { both_halves[5] = 5; assert_eq!(i16x8::from_slice(simd, &both_halves).reduce_product(), 120); + let mut all_stages = [1; 8]; + all_stages[2] = 2; + all_stages[3] = 3; + all_stages[6] = 4; + all_stages[7] = 5; + assert_eq!(i16x8::from_slice(simd, &all_stages).reduce_product(), 120); + let mut negative = [1; 8]; negative[0] = -2; negative[1] = 3; @@ -484,6 +505,13 @@ fn reduce_product_u16x8(simd: S) { both_halves[5] = 5; assert_eq!(u16x8::from_slice(simd, &both_halves).reduce_product(), 120); + let mut all_stages = [1; 8]; + all_stages[2] = 2; + all_stages[3] = 3; + all_stages[6] = 4; + all_stages[7] = 5; + assert_eq!(u16x8::from_slice(simd, &all_stages).reduce_product(), 120); + let mut zero = [1; 8]; zero[3] = 0; assert_eq!(u16x8::from_slice(simd, &zero).reduce_product(), 0); From ae458988a17da7a8de3480035f4362577ba62ccf Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 30 Aug 2026 13:17:41 +0100 Subject: [PATCH 5/8] Polish the docs a bit --- fearless_simd/src/generated/simd_trait.rs | 124 +++++++++++----------- fearless_simd_gen/src/ops.rs | 11 +- 2 files changed, 68 insertions(+), 67 deletions(-) diff --git a/fearless_simd/src/generated/simd_trait.rs b/fearless_simd/src/generated/simd_trait.rs index bd283ebe..aff11296 100644 --- a/fearless_simd/src/generated/simd_trait.rs +++ b/fearless_simd/src/generated/simd_trait.rs @@ -269,9 +269,9 @@ pub trait Simd: fn reduce_max_precise_f32x4(self, a: f32x4) -> f32; #[doc = "Return the minimum element in the vector, ignoring quiet NaNs.\n\nFor integer vectors, this operation is the same as `reduce_min`.\n\nFor floating-point vectors, quiet NaNs are ignored. If there is at least one numeric lane, this returns the true minimum of the numeric lanes. If all lanes are quiet NaNs, this returns NaN, with an unspecified payload and sign.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned.\n\nIf any lane is a *signaling* NaN, the result is fully non-deterministic: it may be NaN or a numeric lane and is not guaranteed to be the true minimum.\nSignaling NaN values are not produced by floating-point math operations, only from manual initialization with specific bit patterns. You probably don't need to worry about them."] fn reduce_min_precise_f32x4(self, a: f32x4) -> f32; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f32x4(self, a: f32x4) -> f32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_f32x4(self, a: f32x4) -> f32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4; @@ -411,9 +411,9 @@ pub trait Simd: fn reduce_max_i8x16(self, a: i8x16) -> i8; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i8x16(self, a: i8x16) -> i8; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i8x16(self, a: i8x16) -> i8; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i8x16(self, a: i8x16) -> i8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16; @@ -516,9 +516,9 @@ pub trait Simd: fn reduce_max_u8x16(self, a: u8x16) -> u8; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u8x16(self, a: u8x16) -> u8; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u8x16(self, a: u8x16) -> u8; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u8x16(self, a: u8x16) -> u8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16; @@ -665,9 +665,9 @@ pub trait Simd: fn reduce_max_i16x8(self, a: i16x8) -> i16; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i16x8(self, a: i16x8) -> i16; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i16x8(self, a: i16x8) -> i16; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i16x8(self, a: i16x8) -> i16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8; @@ -785,9 +785,9 @@ pub trait Simd: fn reduce_max_u16x8(self, a: u16x8) -> u16; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u16x8(self, a: u16x8) -> u16; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u16x8(self, a: u16x8) -> u16; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u16x8(self, a: u16x8) -> u16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8; @@ -940,9 +940,9 @@ pub trait Simd: fn reduce_max_i32x4(self, a: i32x4) -> i32; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i32x4(self, a: i32x4) -> i32; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i32x4(self, a: i32x4) -> i32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i32x4(self, a: i32x4) -> i32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4; @@ -1062,9 +1062,9 @@ pub trait Simd: fn reduce_max_u32x4(self, a: u32x4) -> u32; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u32x4(self, a: u32x4) -> u32; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u32x4(self, a: u32x4) -> u32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u32x4(self, a: u32x4) -> u32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4; @@ -1215,9 +1215,9 @@ pub trait Simd: fn reduce_max_precise_f64x2(self, a: f64x2) -> f64; #[doc = "Return the minimum element in the vector, ignoring quiet NaNs.\n\nFor integer vectors, this operation is the same as `reduce_min`.\n\nFor floating-point vectors, quiet NaNs are ignored. If there is at least one numeric lane, this returns the true minimum of the numeric lanes. If all lanes are quiet NaNs, this returns NaN, with an unspecified payload and sign.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned.\n\nIf any lane is a *signaling* NaN, the result is fully non-deterministic: it may be NaN or a numeric lane and is not guaranteed to be the true minimum.\nSignaling NaN values are not produced by floating-point math operations, only from manual initialization with specific bit patterns. You probably don't need to worry about them."] fn reduce_min_precise_f64x2(self, a: f64x2) -> f64; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f64x2(self, a: f64x2) -> f64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_f64x2(self, a: f64x2) -> f64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2; @@ -1361,9 +1361,9 @@ pub trait Simd: fn reduce_max_i64x2(self, a: i64x2) -> i64; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i64x2(self, a: i64x2) -> i64; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i64x2(self, a: i64x2) -> i64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i64x2(self, a: i64x2) -> i64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2; @@ -1481,9 +1481,9 @@ pub trait Simd: fn reduce_max_u64x2(self, a: u64x2) -> u64; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u64x2(self, a: u64x2) -> u64; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u64x2(self, a: u64x2) -> u64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u64x2(self, a: u64x2) -> u64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2; @@ -1705,13 +1705,13 @@ pub trait Simd: let (a0, a1) = self.split_f32x8(a); self.reduce_min_precise_f32x4(self.min_precise_f32x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f32x8(self, a: f32x8) -> f32 { let (a0, a1) = self.split_f32x8(a); self.reduce_sum_f32x4(self.add_f32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f32x8(self, a: f32x8) -> f32 { let (a0, a1) = self.split_f32x8(a); @@ -2106,13 +2106,13 @@ pub trait Simd: let (a0, a1) = self.split_i8x32(a); self.reduce_min_i8x16(self.min_i8x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i8x32(self, a: i8x32) -> i8 { let (a0, a1) = self.split_i8x32(a); self.reduce_sum_i8x16(self.add_i8x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i8x32(self, a: i8x32) -> i8 { let (a0, a1) = self.split_i8x32(a); @@ -2385,13 +2385,13 @@ pub trait Simd: let (a0, a1) = self.split_u8x32(a); self.reduce_min_u8x16(self.min_u8x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u8x32(self, a: u8x32) -> u8 { let (a0, a1) = self.split_u8x32(a); self.reduce_sum_u8x16(self.add_u8x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u8x32(self, a: u8x32) -> u8 { let (a0, a1) = self.split_u8x32(a); @@ -2770,13 +2770,13 @@ pub trait Simd: let (a0, a1) = self.split_i16x16(a); self.reduce_min_i16x8(self.min_i16x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i16x16(self, a: i16x16) -> i16 { let (a0, a1) = self.split_i16x16(a); self.reduce_sum_i16x8(self.add_i16x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i16x16(self, a: i16x16) -> i16 { let (a0, a1) = self.split_i16x16(a); @@ -3081,13 +3081,13 @@ pub trait Simd: let (a0, a1) = self.split_u16x16(a); self.reduce_min_u16x8(self.min_u16x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u16x16(self, a: u16x16) -> u16 { let (a0, a1) = self.split_u16x16(a); self.reduce_sum_u16x8(self.add_u16x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u16x16(self, a: u16x16) -> u16 { let (a0, a1) = self.split_u16x16(a); @@ -3489,13 +3489,13 @@ pub trait Simd: let (a0, a1) = self.split_i32x8(a); self.reduce_min_i32x4(self.min_i32x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i32x8(self, a: i32x8) -> i32 { let (a0, a1) = self.split_i32x8(a); self.reduce_sum_i32x4(self.add_i32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i32x8(self, a: i32x8) -> i32 { let (a0, a1) = self.split_i32x8(a); @@ -3802,13 +3802,13 @@ pub trait Simd: let (a0, a1) = self.split_u32x8(a); self.reduce_min_u32x4(self.min_u32x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u32x8(self, a: u32x8) -> u32 { let (a0, a1) = self.split_u32x8(a); self.reduce_sum_u32x4(self.add_u32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u32x8(self, a: u32x8) -> u32 { let (a0, a1) = self.split_u32x8(a); @@ -4204,13 +4204,13 @@ pub trait Simd: let (a0, a1) = self.split_f64x4(a); self.reduce_min_precise_f64x2(self.min_precise_f64x2(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f64x4(self, a: f64x4) -> f64 { let (a0, a1) = self.split_f64x4(a); self.reduce_sum_f64x2(self.add_f64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f64x4(self, a: f64x4) -> f64 { let (a0, a1) = self.split_f64x4(a); @@ -4624,13 +4624,13 @@ pub trait Simd: let (a0, a1) = self.split_i64x4(a); self.reduce_min_i64x2(self.min_i64x2(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i64x4(self, a: i64x4) -> i64 { let (a0, a1) = self.split_i64x4(a); self.reduce_sum_i64x2(self.add_i64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i64x4(self, a: i64x4) -> i64 { let (a0, a1) = self.split_i64x4(a); @@ -4929,13 +4929,13 @@ pub trait Simd: let (a0, a1) = self.split_u64x4(a); self.reduce_min_u64x2(self.min_u64x2(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u64x4(self, a: u64x4) -> u64 { let (a0, a1) = self.split_u64x4(a); self.reduce_sum_u64x2(self.add_u64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u64x4(self, a: u64x4) -> u64 { let (a0, a1) = self.split_u64x4(a); @@ -5327,13 +5327,13 @@ pub trait Simd: let (a0, a1) = self.split_f32x16(a); self.reduce_min_precise_f32x8(self.min_precise_f32x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f32x16(self, a: f32x16) -> f32 { let (a0, a1) = self.split_f32x16(a); self.reduce_sum_f32x8(self.add_f32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f32x16(self, a: f32x16) -> f32 { let (a0, a1) = self.split_f32x16(a); @@ -5736,13 +5736,13 @@ pub trait Simd: let (a0, a1) = self.split_i8x64(a); self.reduce_min_i8x32(self.min_i8x32(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i8x64(self, a: i8x64) -> i8 { let (a0, a1) = self.split_i8x64(a); self.reduce_sum_i8x32(self.add_i8x32(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i8x64(self, a: i8x64) -> i8 { let (a0, a1) = self.split_i8x64(a); @@ -6013,13 +6013,13 @@ pub trait Simd: let (a0, a1) = self.split_u8x64(a); self.reduce_min_u8x32(self.min_u8x32(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u8x64(self, a: u8x64) -> u8 { let (a0, a1) = self.split_u8x64(a); self.reduce_sum_u8x32(self.add_u8x32(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u8x64(self, a: u8x64) -> u8 { let (a0, a1) = self.split_u8x64(a); @@ -6394,13 +6394,13 @@ pub trait Simd: let (a0, a1) = self.split_i16x32(a); self.reduce_min_i16x16(self.min_i16x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i16x32(self, a: i16x32) -> i16 { let (a0, a1) = self.split_i16x32(a); self.reduce_sum_i16x16(self.add_i16x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i16x32(self, a: i16x32) -> i16 { let (a0, a1) = self.split_i16x32(a); @@ -6709,13 +6709,13 @@ pub trait Simd: let (a0, a1) = self.split_u16x32(a); self.reduce_min_u16x16(self.min_u16x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u16x32(self, a: u16x32) -> u16 { let (a0, a1) = self.split_u16x32(a); self.reduce_sum_u16x16(self.add_u16x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u16x32(self, a: u16x32) -> u16 { let (a0, a1) = self.split_u16x32(a); @@ -7126,13 +7126,13 @@ pub trait Simd: let (a0, a1) = self.split_i32x16(a); self.reduce_min_i32x8(self.min_i32x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i32x16(self, a: i32x16) -> i32 { let (a0, a1) = self.split_i32x16(a); self.reduce_sum_i32x8(self.add_i32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i32x16(self, a: i32x16) -> i32 { let (a0, a1) = self.split_i32x16(a); @@ -7441,13 +7441,13 @@ pub trait Simd: let (a0, a1) = self.split_u32x16(a); self.reduce_min_u32x8(self.min_u32x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u32x16(self, a: u32x16) -> u32 { let (a0, a1) = self.split_u32x16(a); self.reduce_sum_u32x8(self.add_u32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u32x16(self, a: u32x16) -> u32 { let (a0, a1) = self.split_u32x16(a); @@ -7839,13 +7839,13 @@ pub trait Simd: let (a0, a1) = self.split_f64x8(a); self.reduce_min_precise_f64x4(self.min_precise_f64x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f64x8(self, a: f64x8) -> f64 { let (a0, a1) = self.split_f64x8(a); self.reduce_sum_f64x4(self.add_f64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f64x8(self, a: f64x8) -> f64 { let (a0, a1) = self.split_f64x8(a); @@ -8257,13 +8257,13 @@ pub trait Simd: let (a0, a1) = self.split_i64x8(a); self.reduce_min_i64x4(self.min_i64x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i64x8(self, a: i64x8) -> i64 { let (a0, a1) = self.split_i64x8(a); self.reduce_sum_i64x4(self.add_i64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i64x8(self, a: i64x8) -> i64 { let (a0, a1) = self.split_i64x8(a); @@ -8560,13 +8560,13 @@ pub trait Simd: let (a0, a1) = self.split_u64x8(a); self.reduce_min_u64x4(self.min_u64x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u64x8(self, a: u64x8) -> u64 { let (a0, a1) = self.split_u64x8(a); self.reduce_sum_u64x4(self.add_u64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u64x8(self, a: u64x8) -> u64 { let (a0, a1) = self.split_u64x8(a); @@ -9395,9 +9395,9 @@ pub trait SimdBase: fn reduce_max_precise(self) -> Self::Element; #[doc = "Return the minimum element in the vector, ignoring quiet NaNs.\n\nFor integer vectors, this operation is the same as `reduce_min`.\n\nFor floating-point vectors, quiet NaNs are ignored. If there is at least one numeric lane, this returns the true minimum of the numeric lanes. If all lanes are quiet NaNs, this returns NaN, with an unspecified payload and sign.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned.\n\nIf any lane is a *signaling* NaN, the result is fully non-deterministic: it may be NaN or a numeric lane and is not guaranteed to be the true minimum.\nSignaling NaN values are not produced by floating-point math operations, only from manual initialization with specific bit patterns. You probably don't need to worry about them."] fn reduce_min_precise(self) -> Self::Element; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum(self) -> Self::Element; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFloating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product(self) -> Self::Element; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max(self, rhs: impl SimdInto) -> Self; diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index 79e51ec0..066cc65d 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -645,9 +645,9 @@ const COMMON_BASE_OPS: &[Op] = &[ "Return the sum of all elements in the vector. Integer addition wraps.\n\n\ # Floating-point accuracy\n\n\ For an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\n\ - For a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except for NaNs, the exact bit patterns are unspecified.\n\n\ + For a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\n\ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ - Because floating-point addition is not associative, separately reducing two 128-bit vectors and then adding the results can differ from reducing their combined 256-bit vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different.", + Because floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different.", ), Op::new( "reduce_product", @@ -655,10 +655,11 @@ const COMMON_BASE_OPS: &[Op] = &[ OpSig::Reduce { lane_op: "mul" }, "Return the product of all elements in the vector. Integer multiplication wraps.\n\n\ # Floating-point behavior\n\n\ - Floating-point multiplication uses a fixed balanced tree with `log2(N)` dependency depth for an input vector with N lanes. This improves latency, but not the general relative-error bound: every multiplication in the tree can round.\n\n\ - Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\n\ - For a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\n\ + For a vector with N elements, this operation performs N roundings. + For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\n\ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ + The result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n + Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\n\ Because floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector.", ), Op::new( From cb674ee6072425566707bebd71210461bef09bec Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Sun, 30 Aug 2026 13:27:57 +0100 Subject: [PATCH 6/8] Fix build after fiddling with docs --- fearless_simd/src/generated/simd_trait.rs | 124 +++++++++++----------- fearless_simd_gen/src/ops.rs | 8 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/fearless_simd/src/generated/simd_trait.rs b/fearless_simd/src/generated/simd_trait.rs index aff11296..b90aed42 100644 --- a/fearless_simd/src/generated/simd_trait.rs +++ b/fearless_simd/src/generated/simd_trait.rs @@ -269,9 +269,9 @@ pub trait Simd: fn reduce_max_precise_f32x4(self, a: f32x4) -> f32; #[doc = "Return the minimum element in the vector, ignoring quiet NaNs.\n\nFor integer vectors, this operation is the same as `reduce_min`.\n\nFor floating-point vectors, quiet NaNs are ignored. If there is at least one numeric lane, this returns the true minimum of the numeric lanes. If all lanes are quiet NaNs, this returns NaN, with an unspecified payload and sign.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned.\n\nIf any lane is a *signaling* NaN, the result is fully non-deterministic: it may be NaN or a numeric lane and is not guaranteed to be the true minimum.\nSignaling NaN values are not produced by floating-point math operations, only from manual initialization with specific bit patterns. You probably don't need to worry about them."] fn reduce_min_precise_f32x4(self, a: f32x4) -> f32; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f32x4(self, a: f32x4) -> f32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_f32x4(self, a: f32x4) -> f32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4; @@ -411,9 +411,9 @@ pub trait Simd: fn reduce_max_i8x16(self, a: i8x16) -> i8; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i8x16(self, a: i8x16) -> i8; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i8x16(self, a: i8x16) -> i8; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i8x16(self, a: i8x16) -> i8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16; @@ -516,9 +516,9 @@ pub trait Simd: fn reduce_max_u8x16(self, a: u8x16) -> u8; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u8x16(self, a: u8x16) -> u8; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u8x16(self, a: u8x16) -> u8; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u8x16(self, a: u8x16) -> u8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16; @@ -665,9 +665,9 @@ pub trait Simd: fn reduce_max_i16x8(self, a: i16x8) -> i16; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i16x8(self, a: i16x8) -> i16; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i16x8(self, a: i16x8) -> i16; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i16x8(self, a: i16x8) -> i16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8; @@ -785,9 +785,9 @@ pub trait Simd: fn reduce_max_u16x8(self, a: u16x8) -> u16; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u16x8(self, a: u16x8) -> u16; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u16x8(self, a: u16x8) -> u16; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u16x8(self, a: u16x8) -> u16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8; @@ -940,9 +940,9 @@ pub trait Simd: fn reduce_max_i32x4(self, a: i32x4) -> i32; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i32x4(self, a: i32x4) -> i32; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i32x4(self, a: i32x4) -> i32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i32x4(self, a: i32x4) -> i32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4; @@ -1062,9 +1062,9 @@ pub trait Simd: fn reduce_max_u32x4(self, a: u32x4) -> u32; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u32x4(self, a: u32x4) -> u32; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u32x4(self, a: u32x4) -> u32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u32x4(self, a: u32x4) -> u32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4; @@ -1215,9 +1215,9 @@ pub trait Simd: fn reduce_max_precise_f64x2(self, a: f64x2) -> f64; #[doc = "Return the minimum element in the vector, ignoring quiet NaNs.\n\nFor integer vectors, this operation is the same as `reduce_min`.\n\nFor floating-point vectors, quiet NaNs are ignored. If there is at least one numeric lane, this returns the true minimum of the numeric lanes. If all lanes are quiet NaNs, this returns NaN, with an unspecified payload and sign.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned.\n\nIf any lane is a *signaling* NaN, the result is fully non-deterministic: it may be NaN or a numeric lane and is not guaranteed to be the true minimum.\nSignaling NaN values are not produced by floating-point math operations, only from manual initialization with specific bit patterns. You probably don't need to worry about them."] fn reduce_min_precise_f64x2(self, a: f64x2) -> f64; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f64x2(self, a: f64x2) -> f64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_f64x2(self, a: f64x2) -> f64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2; @@ -1361,9 +1361,9 @@ pub trait Simd: fn reduce_max_i64x2(self, a: i64x2) -> i64; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_i64x2(self, a: i64x2) -> i64; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i64x2(self, a: i64x2) -> i64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i64x2(self, a: i64x2) -> i64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2; @@ -1481,9 +1481,9 @@ pub trait Simd: fn reduce_max_u64x2(self, a: u64x2) -> u64; #[doc = "Return the minimum element in the vector. Integer vectors always return the exact minimum.\n\nFor floating-point vectors with no NaNs, this returns the true minimum. If any lane is NaN, the entire result is implementation-defined: it may be NaN or a numeric lane that is not the true minimum. See `reduce_min_precise` for a version that ignores quiet NaNs.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned."] fn reduce_min_u64x2(self, a: u64x2) -> u64; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u64x2(self, a: u64x2) -> u64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u64x2(self, a: u64x2) -> u64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2; @@ -1705,13 +1705,13 @@ pub trait Simd: let (a0, a1) = self.split_f32x8(a); self.reduce_min_precise_f32x4(self.min_precise_f32x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f32x8(self, a: f32x8) -> f32 { let (a0, a1) = self.split_f32x8(a); self.reduce_sum_f32x4(self.add_f32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f32x8(self, a: f32x8) -> f32 { let (a0, a1) = self.split_f32x8(a); @@ -2106,13 +2106,13 @@ pub trait Simd: let (a0, a1) = self.split_i8x32(a); self.reduce_min_i8x16(self.min_i8x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i8x32(self, a: i8x32) -> i8 { let (a0, a1) = self.split_i8x32(a); self.reduce_sum_i8x16(self.add_i8x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i8x32(self, a: i8x32) -> i8 { let (a0, a1) = self.split_i8x32(a); @@ -2385,13 +2385,13 @@ pub trait Simd: let (a0, a1) = self.split_u8x32(a); self.reduce_min_u8x16(self.min_u8x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u8x32(self, a: u8x32) -> u8 { let (a0, a1) = self.split_u8x32(a); self.reduce_sum_u8x16(self.add_u8x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u8x32(self, a: u8x32) -> u8 { let (a0, a1) = self.split_u8x32(a); @@ -2770,13 +2770,13 @@ pub trait Simd: let (a0, a1) = self.split_i16x16(a); self.reduce_min_i16x8(self.min_i16x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i16x16(self, a: i16x16) -> i16 { let (a0, a1) = self.split_i16x16(a); self.reduce_sum_i16x8(self.add_i16x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i16x16(self, a: i16x16) -> i16 { let (a0, a1) = self.split_i16x16(a); @@ -3081,13 +3081,13 @@ pub trait Simd: let (a0, a1) = self.split_u16x16(a); self.reduce_min_u16x8(self.min_u16x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u16x16(self, a: u16x16) -> u16 { let (a0, a1) = self.split_u16x16(a); self.reduce_sum_u16x8(self.add_u16x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u16x16(self, a: u16x16) -> u16 { let (a0, a1) = self.split_u16x16(a); @@ -3489,13 +3489,13 @@ pub trait Simd: let (a0, a1) = self.split_i32x8(a); self.reduce_min_i32x4(self.min_i32x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i32x8(self, a: i32x8) -> i32 { let (a0, a1) = self.split_i32x8(a); self.reduce_sum_i32x4(self.add_i32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i32x8(self, a: i32x8) -> i32 { let (a0, a1) = self.split_i32x8(a); @@ -3802,13 +3802,13 @@ pub trait Simd: let (a0, a1) = self.split_u32x8(a); self.reduce_min_u32x4(self.min_u32x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u32x8(self, a: u32x8) -> u32 { let (a0, a1) = self.split_u32x8(a); self.reduce_sum_u32x4(self.add_u32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u32x8(self, a: u32x8) -> u32 { let (a0, a1) = self.split_u32x8(a); @@ -4204,13 +4204,13 @@ pub trait Simd: let (a0, a1) = self.split_f64x4(a); self.reduce_min_precise_f64x2(self.min_precise_f64x2(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f64x4(self, a: f64x4) -> f64 { let (a0, a1) = self.split_f64x4(a); self.reduce_sum_f64x2(self.add_f64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f64x4(self, a: f64x4) -> f64 { let (a0, a1) = self.split_f64x4(a); @@ -4624,13 +4624,13 @@ pub trait Simd: let (a0, a1) = self.split_i64x4(a); self.reduce_min_i64x2(self.min_i64x2(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i64x4(self, a: i64x4) -> i64 { let (a0, a1) = self.split_i64x4(a); self.reduce_sum_i64x2(self.add_i64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i64x4(self, a: i64x4) -> i64 { let (a0, a1) = self.split_i64x4(a); @@ -4929,13 +4929,13 @@ pub trait Simd: let (a0, a1) = self.split_u64x4(a); self.reduce_min_u64x2(self.min_u64x2(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u64x4(self, a: u64x4) -> u64 { let (a0, a1) = self.split_u64x4(a); self.reduce_sum_u64x2(self.add_u64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u64x4(self, a: u64x4) -> u64 { let (a0, a1) = self.split_u64x4(a); @@ -5327,13 +5327,13 @@ pub trait Simd: let (a0, a1) = self.split_f32x16(a); self.reduce_min_precise_f32x8(self.min_precise_f32x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f32x16(self, a: f32x16) -> f32 { let (a0, a1) = self.split_f32x16(a); self.reduce_sum_f32x8(self.add_f32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f32x16(self, a: f32x16) -> f32 { let (a0, a1) = self.split_f32x16(a); @@ -5736,13 +5736,13 @@ pub trait Simd: let (a0, a1) = self.split_i8x64(a); self.reduce_min_i8x32(self.min_i8x32(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i8x64(self, a: i8x64) -> i8 { let (a0, a1) = self.split_i8x64(a); self.reduce_sum_i8x32(self.add_i8x32(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i8x64(self, a: i8x64) -> i8 { let (a0, a1) = self.split_i8x64(a); @@ -6013,13 +6013,13 @@ pub trait Simd: let (a0, a1) = self.split_u8x64(a); self.reduce_min_u8x32(self.min_u8x32(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u8x64(self, a: u8x64) -> u8 { let (a0, a1) = self.split_u8x64(a); self.reduce_sum_u8x32(self.add_u8x32(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u8x64(self, a: u8x64) -> u8 { let (a0, a1) = self.split_u8x64(a); @@ -6394,13 +6394,13 @@ pub trait Simd: let (a0, a1) = self.split_i16x32(a); self.reduce_min_i16x16(self.min_i16x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i16x32(self, a: i16x32) -> i16 { let (a0, a1) = self.split_i16x32(a); self.reduce_sum_i16x16(self.add_i16x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i16x32(self, a: i16x32) -> i16 { let (a0, a1) = self.split_i16x32(a); @@ -6709,13 +6709,13 @@ pub trait Simd: let (a0, a1) = self.split_u16x32(a); self.reduce_min_u16x16(self.min_u16x16(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u16x32(self, a: u16x32) -> u16 { let (a0, a1) = self.split_u16x32(a); self.reduce_sum_u16x16(self.add_u16x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u16x32(self, a: u16x32) -> u16 { let (a0, a1) = self.split_u16x32(a); @@ -7126,13 +7126,13 @@ pub trait Simd: let (a0, a1) = self.split_i32x16(a); self.reduce_min_i32x8(self.min_i32x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i32x16(self, a: i32x16) -> i32 { let (a0, a1) = self.split_i32x16(a); self.reduce_sum_i32x8(self.add_i32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i32x16(self, a: i32x16) -> i32 { let (a0, a1) = self.split_i32x16(a); @@ -7441,13 +7441,13 @@ pub trait Simd: let (a0, a1) = self.split_u32x16(a); self.reduce_min_u32x8(self.min_u32x8(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u32x16(self, a: u32x16) -> u32 { let (a0, a1) = self.split_u32x16(a); self.reduce_sum_u32x8(self.add_u32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u32x16(self, a: u32x16) -> u32 { let (a0, a1) = self.split_u32x16(a); @@ -7839,13 +7839,13 @@ pub trait Simd: let (a0, a1) = self.split_f64x8(a); self.reduce_min_precise_f64x4(self.min_precise_f64x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_f64x8(self, a: f64x8) -> f64 { let (a0, a1) = self.split_f64x8(a); self.reduce_sum_f64x4(self.add_f64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f64x8(self, a: f64x8) -> f64 { let (a0, a1) = self.split_f64x8(a); @@ -8257,13 +8257,13 @@ pub trait Simd: let (a0, a1) = self.split_i64x8(a); self.reduce_min_i64x4(self.min_i64x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_i64x8(self, a: i64x8) -> i64 { let (a0, a1) = self.split_i64x8(a); self.reduce_sum_i64x4(self.add_i64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i64x8(self, a: i64x8) -> i64 { let (a0, a1) = self.split_i64x8(a); @@ -8560,13 +8560,13 @@ pub trait Simd: let (a0, a1) = self.split_u64x8(a); self.reduce_min_u64x4(self.min_u64x4(a0, a1)) } - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] #[inline(always)] fn reduce_sum_u64x8(self, a: u64x8) -> u64 { let (a0, a1) = self.split_u64x8(a); self.reduce_sum_u64x4(self.add_u64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u64x8(self, a: u64x8) -> u64 { let (a0, a1) = self.split_u64x8(a); @@ -9395,9 +9395,9 @@ pub trait SimdBase: fn reduce_max_precise(self) -> Self::Element; #[doc = "Return the minimum element in the vector, ignoring quiet NaNs.\n\nFor integer vectors, this operation is the same as `reduce_min`.\n\nFor floating-point vectors, quiet NaNs are ignored. If there is at least one numeric lane, this returns the true minimum of the numeric lanes. If all lanes are quiet NaNs, this returns NaN, with an unspecified payload and sign.\n\nIf the floating-point vector contains both positive zero and negative zero, either sign of zero may be returned.\n\nIf any lane is a *signaling* NaN, the result is fully non-deterministic: it may be NaN or a numeric lane and is not guaranteed to be the true minimum.\nSignaling NaN values are not produced by floating-point math operations, only from manual initialization with specific bit patterns. You probably don't need to worry about them."] fn reduce_min_precise(self) -> Self::Element; - #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] + #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum(self) -> Self::Element; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\nThis fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\n Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product(self) -> Self::Element; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max(self, rhs: impl SimdInto) -> Self; diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index 066cc65d..d5697d86 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -645,7 +645,7 @@ const COMMON_BASE_OPS: &[Op] = &[ "Return the sum of all elements in the vector. Integer addition wraps.\n\n\ # Floating-point accuracy\n\n\ For an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\n\ - For a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\n\ + For a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. \ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ Because floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different.", ), @@ -655,10 +655,10 @@ const COMMON_BASE_OPS: &[Op] = &[ OpSig::Reduce { lane_op: "mul" }, "Return the product of all elements in the vector. Integer multiplication wraps.\n\n\ # Floating-point behavior\n\n\ - For a vector with N elements, this operation performs N roundings. - For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified.\n\n\ + For a vector with N elements, this operation performs N roundings.\n\n\ + For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. \ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ - The result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n + The result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\ Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\n\ Because floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector.", ), From 2f6d79e7c8d6271720e0023789a664453ac9dc9c Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Thu, 3 Sep 2026 21:21:12 +0100 Subject: [PATCH 7/8] Fix the documented number of roundings --- fearless_simd/src/generated/simd_trait.rs | 62 +++++++++++------------ fearless_simd_gen/src/ops.rs | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/fearless_simd/src/generated/simd_trait.rs b/fearless_simd/src/generated/simd_trait.rs index b90aed42..cd6c820d 100644 --- a/fearless_simd/src/generated/simd_trait.rs +++ b/fearless_simd/src/generated/simd_trait.rs @@ -271,7 +271,7 @@ pub trait Simd: fn reduce_min_precise_f32x4(self, a: f32x4) -> f32; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f32x4(self, a: f32x4) -> f32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_f32x4(self, a: f32x4) -> f32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f32x4(self, a: f32x4, b: f32x4) -> f32x4; @@ -413,7 +413,7 @@ pub trait Simd: fn reduce_min_i8x16(self, a: i8x16) -> i8; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i8x16(self, a: i8x16) -> i8; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i8x16(self, a: i8x16) -> i8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i8x16(self, a: i8x16, b: i8x16) -> i8x16; @@ -518,7 +518,7 @@ pub trait Simd: fn reduce_min_u8x16(self, a: u8x16) -> u8; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u8x16(self, a: u8x16) -> u8; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u8x16(self, a: u8x16) -> u8; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u8x16(self, a: u8x16, b: u8x16) -> u8x16; @@ -667,7 +667,7 @@ pub trait Simd: fn reduce_min_i16x8(self, a: i16x8) -> i16; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i16x8(self, a: i16x8) -> i16; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i16x8(self, a: i16x8) -> i16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i16x8(self, a: i16x8, b: i16x8) -> i16x8; @@ -787,7 +787,7 @@ pub trait Simd: fn reduce_min_u16x8(self, a: u16x8) -> u16; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u16x8(self, a: u16x8) -> u16; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u16x8(self, a: u16x8) -> u16; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u16x8(self, a: u16x8, b: u16x8) -> u16x8; @@ -942,7 +942,7 @@ pub trait Simd: fn reduce_min_i32x4(self, a: i32x4) -> i32; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i32x4(self, a: i32x4) -> i32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i32x4(self, a: i32x4) -> i32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i32x4(self, a: i32x4, b: i32x4) -> i32x4; @@ -1064,7 +1064,7 @@ pub trait Simd: fn reduce_min_u32x4(self, a: u32x4) -> u32; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u32x4(self, a: u32x4) -> u32; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u32x4(self, a: u32x4) -> u32; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u32x4(self, a: u32x4, b: u32x4) -> u32x4; @@ -1217,7 +1217,7 @@ pub trait Simd: fn reduce_min_precise_f64x2(self, a: f64x2) -> f64; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_f64x2(self, a: f64x2) -> f64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_f64x2(self, a: f64x2) -> f64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_f64x2(self, a: f64x2, b: f64x2) -> f64x2; @@ -1363,7 +1363,7 @@ pub trait Simd: fn reduce_min_i64x2(self, a: i64x2) -> i64; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_i64x2(self, a: i64x2) -> i64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_i64x2(self, a: i64x2) -> i64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_i64x2(self, a: i64x2, b: i64x2) -> i64x2; @@ -1483,7 +1483,7 @@ pub trait Simd: fn reduce_min_u64x2(self, a: u64x2) -> u64; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum_u64x2(self, a: u64x2) -> u64; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product_u64x2(self, a: u64x2) -> u64; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max_u64x2(self, a: u64x2, b: u64x2) -> u64x2; @@ -1711,7 +1711,7 @@ pub trait Simd: let (a0, a1) = self.split_f32x8(a); self.reduce_sum_f32x4(self.add_f32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f32x8(self, a: f32x8) -> f32 { let (a0, a1) = self.split_f32x8(a); @@ -2112,7 +2112,7 @@ pub trait Simd: let (a0, a1) = self.split_i8x32(a); self.reduce_sum_i8x16(self.add_i8x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i8x32(self, a: i8x32) -> i8 { let (a0, a1) = self.split_i8x32(a); @@ -2391,7 +2391,7 @@ pub trait Simd: let (a0, a1) = self.split_u8x32(a); self.reduce_sum_u8x16(self.add_u8x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u8x32(self, a: u8x32) -> u8 { let (a0, a1) = self.split_u8x32(a); @@ -2776,7 +2776,7 @@ pub trait Simd: let (a0, a1) = self.split_i16x16(a); self.reduce_sum_i16x8(self.add_i16x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i16x16(self, a: i16x16) -> i16 { let (a0, a1) = self.split_i16x16(a); @@ -3087,7 +3087,7 @@ pub trait Simd: let (a0, a1) = self.split_u16x16(a); self.reduce_sum_u16x8(self.add_u16x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u16x16(self, a: u16x16) -> u16 { let (a0, a1) = self.split_u16x16(a); @@ -3495,7 +3495,7 @@ pub trait Simd: let (a0, a1) = self.split_i32x8(a); self.reduce_sum_i32x4(self.add_i32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i32x8(self, a: i32x8) -> i32 { let (a0, a1) = self.split_i32x8(a); @@ -3808,7 +3808,7 @@ pub trait Simd: let (a0, a1) = self.split_u32x8(a); self.reduce_sum_u32x4(self.add_u32x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u32x8(self, a: u32x8) -> u32 { let (a0, a1) = self.split_u32x8(a); @@ -4210,7 +4210,7 @@ pub trait Simd: let (a0, a1) = self.split_f64x4(a); self.reduce_sum_f64x2(self.add_f64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f64x4(self, a: f64x4) -> f64 { let (a0, a1) = self.split_f64x4(a); @@ -4630,7 +4630,7 @@ pub trait Simd: let (a0, a1) = self.split_i64x4(a); self.reduce_sum_i64x2(self.add_i64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i64x4(self, a: i64x4) -> i64 { let (a0, a1) = self.split_i64x4(a); @@ -4935,7 +4935,7 @@ pub trait Simd: let (a0, a1) = self.split_u64x4(a); self.reduce_sum_u64x2(self.add_u64x2(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u64x4(self, a: u64x4) -> u64 { let (a0, a1) = self.split_u64x4(a); @@ -5333,7 +5333,7 @@ pub trait Simd: let (a0, a1) = self.split_f32x16(a); self.reduce_sum_f32x8(self.add_f32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f32x16(self, a: f32x16) -> f32 { let (a0, a1) = self.split_f32x16(a); @@ -5742,7 +5742,7 @@ pub trait Simd: let (a0, a1) = self.split_i8x64(a); self.reduce_sum_i8x32(self.add_i8x32(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i8x64(self, a: i8x64) -> i8 { let (a0, a1) = self.split_i8x64(a); @@ -6019,7 +6019,7 @@ pub trait Simd: let (a0, a1) = self.split_u8x64(a); self.reduce_sum_u8x32(self.add_u8x32(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u8x64(self, a: u8x64) -> u8 { let (a0, a1) = self.split_u8x64(a); @@ -6400,7 +6400,7 @@ pub trait Simd: let (a0, a1) = self.split_i16x32(a); self.reduce_sum_i16x16(self.add_i16x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i16x32(self, a: i16x32) -> i16 { let (a0, a1) = self.split_i16x32(a); @@ -6715,7 +6715,7 @@ pub trait Simd: let (a0, a1) = self.split_u16x32(a); self.reduce_sum_u16x16(self.add_u16x16(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u16x32(self, a: u16x32) -> u16 { let (a0, a1) = self.split_u16x32(a); @@ -7132,7 +7132,7 @@ pub trait Simd: let (a0, a1) = self.split_i32x16(a); self.reduce_sum_i32x8(self.add_i32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i32x16(self, a: i32x16) -> i32 { let (a0, a1) = self.split_i32x16(a); @@ -7447,7 +7447,7 @@ pub trait Simd: let (a0, a1) = self.split_u32x16(a); self.reduce_sum_u32x8(self.add_u32x8(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u32x16(self, a: u32x16) -> u32 { let (a0, a1) = self.split_u32x16(a); @@ -7845,7 +7845,7 @@ pub trait Simd: let (a0, a1) = self.split_f64x8(a); self.reduce_sum_f64x4(self.add_f64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_f64x8(self, a: f64x8) -> f64 { let (a0, a1) = self.split_f64x8(a); @@ -8263,7 +8263,7 @@ pub trait Simd: let (a0, a1) = self.split_i64x8(a); self.reduce_sum_i64x4(self.add_i64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_i64x8(self, a: i64x8) -> i64 { let (a0, a1) = self.split_i64x8(a); @@ -8566,7 +8566,7 @@ pub trait Simd: let (a0, a1) = self.split_u64x8(a); self.reduce_sum_u64x4(self.add_u64x4(a0, a1)) } - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] #[inline(always)] fn reduce_product_u64x8(self, a: u64x8) -> u64 { let (a0, a1) = self.split_u64x8(a); @@ -9397,7 +9397,7 @@ pub trait SimdBase: fn reduce_min_precise(self) -> Self::Element; #[doc = "Return the sum of all elements in the vector. Integer addition wraps.\n\n# Floating-point accuracy\n\nFor an input vector with N lanes, any lane's contribution may be rounded at most `log2(N)` times.\n\nFor a fixed vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nBecause floating-point addition is not associative, separately reducing smaller vectors and then adding their results can differ from reducing their combined wider vector. See [Taming Floating-Point Sums](https://orlp.net/blog/taming-float-sums/) for more information and for other summation algorithms, including exact summation without accumulated rounding error. In that article's terms, our method has the precision properties of pairwise summation, although the exact pairing of values is different."] fn reduce_sum(self) -> Self::Element; - #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] + #[doc = "Return the product of all elements in the vector. Integer multiplication wraps.\n\n# Floating-point behavior\n\nFor a vector with N elements, this operation performs N-1 roundings.\n\nFor a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\nThe result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\nIntermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\nBecause floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector."] fn reduce_product(self) -> Self::Element; #[doc = "Return the element-wise maximum of two vectors.\n\nFor floating-point vectors, if either operand is NaN, the result for that lane is implementation-defined-- it could be either the first or second operand. See `max_precise` for a version that returns the non-NaN operand if only one is NaN.\n\nIf one floating-point operand is positive zero and the other is negative zero, the result is also implementation-defined, and it could be either one."] fn max(self, rhs: impl SimdInto) -> Self; diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index d5697d86..41c780ee 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -655,7 +655,7 @@ const COMMON_BASE_OPS: &[Op] = &[ OpSig::Reduce { lane_op: "mul" }, "Return the product of all elements in the vector. Integer multiplication wraps.\n\n\ # Floating-point behavior\n\n\ - For a vector with N elements, this operation performs N roundings.\n\n\ + For a vector with N elements, this operation performs N-1 roundings.\n\n\ For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. \ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ The result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\ From 0bf528a0fea01f4d9832e0c4e3755f3edf60868e Mon Sep 17 00:00:00 2001 From: "Sergey \"Shnatsel\" Davidoff" Date: Thu, 3 Sep 2026 21:22:11 +0100 Subject: [PATCH 8/8] Fix doc string error, thank you Laurenz --- fearless_simd_gen/src/ops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fearless_simd_gen/src/ops.rs b/fearless_simd_gen/src/ops.rs index 41c780ee..ee4f144e 100644 --- a/fearless_simd_gen/src/ops.rs +++ b/fearless_simd_gen/src/ops.rs @@ -658,7 +658,7 @@ const COMMON_BASE_OPS: &[Op] = &[ For a vector with N elements, this operation performs N-1 roundings.\n\n\ For a given vector type and lane count, this operation produces the same result on all platforms and backends down to the bit pattern, except that when the result is NaN, its exact bit pattern is unspecified. \ This fixed-width guarantee does not make code using native-width associated types such as `S::f32s` independent of the selected SIMD level, because their lane counts can differ.\n\n\ - The result of this operation is **not** bit-exact to scalar sum of the elements because it multiplies elements in a different (but fixed) order.\n\n\ + The result of this operation is **not** bit-exact to scalar product of the elements because it multiplies elements in a different (but fixed) order.\n\n\ Intermediate operations can overflow, underflow, or multiply infinity by zero to produce NaN even when the exact real-number product is representable.\n\n\ Because floating-point multiplication is not associative, separately reducing smaller vectors and then multiplying their results can differ from reducing their combined wider vector.", ),