1 //! Implements portable horizontal integer vector arithmetic reductions.
3 macro_rules
! impl_reduction_integer_arithmetic
{
4 ([$elem_ty
:ident
; $elem_count
:expr
]: $id
:ident
| $ielem_ty
:ident
7 /// Horizontal wrapping sum of the vector elements.
9 /// The intrinsic performs a tree-reduction of the vector elements.
10 /// That is, for an 8 element vector:
12 /// > ((x0 + x1) + (x2 + x3)) + ((x4 + x5) + (x6 + x7))
14 /// If an operation overflows it returns the mathematical result
15 /// modulo `2^n` where `n` is the number of times it overflows.
17 pub fn wrapping_sum(self) -> $elem_ty
{
18 #[cfg(not(target_arch = "aarch64"))]
20 use crate::llvm
::simd_reduce_add_ordered
;
21 let v
: $ielem_ty
= unsafe { simd_reduce_add_ordered(self.0, 0 as $ielem_ty) }
;
24 #[cfg(target_arch = "aarch64")]
26 // FIXME: broken on AArch64
27 // https://github.com/rust-lang-nursery/packed_simd/issues/15
28 let mut x
= self.extract(0) as $elem_ty
;
29 for i
in 1..$id
::lanes() {
30 x
= x
.wrapping_add(self.extract(i
) as $elem_ty
);
36 /// Horizontal wrapping product of the vector elements.
38 /// The intrinsic performs a tree-reduction of the vector elements.
39 /// That is, for an 8 element vector:
41 /// > ((x0 * x1) * (x2 * x3)) * ((x4 * x5) * (x6 * x7))
43 /// If an operation overflows it returns the mathematical result
44 /// modulo `2^n` where `n` is the number of times it overflows.
46 pub fn wrapping_product(self) -> $elem_ty
{
47 #[cfg(not(target_arch = "aarch64"))]
49 use crate::llvm
::simd_reduce_mul_ordered
;
50 let v
: $ielem_ty
= unsafe { simd_reduce_mul_ordered(self.0, 1 as $ielem_ty) }
;
53 #[cfg(target_arch = "aarch64")]
55 // FIXME: broken on AArch64
56 // https://github.com/rust-lang-nursery/packed_simd/issues/15
57 let mut x
= self.extract(0) as $elem_ty
;
58 for i
in 1..$id
::lanes() {
59 x
= x
.wrapping_mul(self.extract(i
) as $elem_ty
);
66 impl crate::iter
::Sum
for $id
{
68 fn sum
<I
: Iterator
<Item
= $id
>>(iter
: I
) -> $id
{
69 iter
.fold($id
::splat(0), crate::ops
::Add
::add
)
73 impl crate::iter
::Product
for $id
{
75 fn product
<I
: Iterator
<Item
= $id
>>(iter
: I
) -> $id
{
76 iter
.fold($id
::splat(1), crate::ops
::Mul
::mul
)
80 impl<'a
> crate::iter
::Sum
<&'a $id
> for $id
{
82 fn sum
<I
: Iterator
<Item
= &'a $id
>>(iter
: I
) -> $id
{
83 iter
.fold($id
::splat(0), |a
, b
| crate::ops
::Add
::add(a
, *b
))
87 impl<'a
> crate::iter
::Product
<&'a $id
> for $id
{
89 fn product
<I
: Iterator
<Item
= &'a $id
>>(iter
: I
) -> $id
{
90 iter
.fold($id
::splat(1), |a
, b
| crate::ops
::Mul
::mul(a
, *b
))
97 pub mod [<$id _reduction_int_arith
>] {
100 fn alternating(x
: usize) -> $id
{
101 let mut v
= $id
::splat(1 as $elem_ty
);
102 for i
in 0..$id
::lanes() {
104 v
= v
.replace(i
, 2 as $elem_ty
);
110 #[cfg_attr(not(target_arch = "wasm32"), test)]
111 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
113 let v
= $id
::splat(0 as $elem_ty
);
114 assert_eq
!(v
.wrapping_sum(), 0 as $elem_ty
);
115 let v
= $id
::splat(1 as $elem_ty
);
116 assert_eq
!(v
.wrapping_sum(), $id
::lanes() as $elem_ty
);
117 let v
= alternating(2);
118 if $id
::lanes() > 1 {
121 ($id
::lanes() / 2 + $id
::lanes()) as $elem_ty
130 #[cfg_attr(not(target_arch = "wasm32"), test)]
131 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
132 fn wrapping_sum_overflow() {
133 let start
= $elem_ty
::max_value()
134 - ($id
::lanes() as $elem_ty
/ 2);
136 let v
= $id
::splat(start
as $elem_ty
);
137 let vwrapping_sum
= v
.wrapping_sum();
139 let mut wrapping_sum
= start
;
140 for _
in 1..$id
::lanes() {
141 wrapping_sum
= wrapping_sum
.wrapping_add(start
);
143 assert_eq
!(wrapping_sum
, vwrapping_sum
, "v = {:?}", v
);
146 #[cfg_attr(not(target_arch = "wasm32"), test)]
147 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
148 fn wrapping_product() {
149 let v
= $id
::splat(0 as $elem_ty
);
150 assert_eq
!(v
.wrapping_product(), 0 as $elem_ty
);
151 let v
= $id
::splat(1 as $elem_ty
);
152 assert_eq
!(v
.wrapping_product(), 1 as $elem_ty
);
153 let f
= match $id
::lanes() {
159 let v
= alternating(f
);
160 if $id
::lanes() > 1 {
162 v
.wrapping_product(),
163 (2_usize
.pow(($id
::lanes() / f
) as u32)
168 v
.wrapping_product(),
174 #[cfg_attr(not(target_arch = "wasm32"), test)]
175 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
176 fn wrapping_product_overflow() {
177 let start
= $elem_ty
::max_value()
178 - ($id
::lanes() as $elem_ty
/ 2);
180 let v
= $id
::splat(start
as $elem_ty
);
181 let vmul
= v
.wrapping_product();
184 for _
in 1..$id
::lanes() {
185 mul
= mul
.wrapping_mul(start
);
187 assert_eq
!(mul
, vmul
, "v = {:?}", v
);