generic_simd/arch/wasm/
complex.rs

1use core::arch::wasm32::*;
2
3use crate::{
4    arch::{generic, wasm::*, Token},
5    scalar::Scalar,
6    shim::{Shim2, Shim4, Shim8, ShimToken},
7    vector::{width, Native, Vector},
8};
9use num_complex::Complex;
10
11impl Native<Simd128> for Complex<f32> {
12    type Width = width::W2;
13}
14
15impl Native<Simd128> for Complex<f64> {
16    type Width = width::W1;
17}
18
19/// A simd128 vector of `Complex<f32>`s.
20///
21/// Requires feature `"complex"`.
22#[derive(Clone, Copy, Debug)]
23#[repr(transparent)]
24#[allow(non_camel_case_types)]
25pub struct cf32x2(v128);
26
27/// A simd128 vector of `Complex<f64>`s.
28///
29/// Requires feature `"complex"`.
30#[derive(Clone, Copy, Debug)]
31#[repr(transparent)]
32#[allow(non_camel_case_types)]
33pub struct cf64x1(v128);
34
35impl Scalar<Simd128, width::W1> for Complex<f32> {
36    type Vector = ShimToken<generic::cf32x1, Self, Simd128>;
37}
38
39impl Scalar<Simd128, width::W2> for Complex<f32> {
40    type Vector = cf32x2;
41}
42
43impl Scalar<Simd128, width::W4> for Complex<f32> {
44    type Vector = Shim2<cf32x2, Complex<f32>>;
45}
46
47impl Scalar<Simd128, width::W8> for Complex<f32> {
48    type Vector = Shim4<cf32x2, Complex<f32>>;
49}
50
51impl Scalar<Simd128, width::W1> for Complex<f64> {
52    type Vector = cf64x1;
53}
54
55impl Scalar<Simd128, width::W2> for Complex<f64> {
56    type Vector = Shim2<cf64x1, Complex<f64>>;
57}
58
59impl Scalar<Simd128, width::W4> for Complex<f64> {
60    type Vector = Shim4<cf64x1, Complex<f64>>;
61}
62
63impl Scalar<Simd128, width::W8> for Complex<f64> {
64    type Vector = Shim8<cf64x1, Complex<f64>>;
65}
66
67as_slice! { cf32x2 }
68as_slice! { cf64x1 }
69
70unsafe impl Vector for cf32x2 {
71    type Scalar = Complex<f32>;
72    type Token = Simd128;
73    type Width = width::W2;
74    type Underlying = v128;
75
76    #[inline]
77    fn zeroed(_: Self::Token) -> Self {
78        Self(unsafe { f32x4_splat(0.) })
79    }
80
81    #[inline]
82    fn splat(_: Self::Token, value: Self::Scalar) -> Self {
83        Self(unsafe { f32x4_const(value.re, value.im, value.re, value.im) })
84    }
85}
86
87unsafe impl Vector for cf64x1 {
88    type Scalar = Complex<f64>;
89    type Token = Simd128;
90    type Width = width::W1;
91    type Underlying = v128;
92
93    #[inline]
94    fn zeroed(_: Self::Token) -> Self {
95        Self(unsafe { f64x2_splat(0.) })
96    }
97
98    #[inline]
99    fn splat(_: Self::Token, value: Self::Scalar) -> Self {
100        Self(unsafe { f64x2_const(value.re, value.im) })
101    }
102}
103
104arithmetic_ops! {
105    feature: Simd128::new_unchecked(),
106    for cf32x2:
107        add -> (f32x4_add),
108        sub -> (f32x4_sub),
109        mul -> (cf32x2_mul),
110        div -> (cf32x2_div)
111}
112
113arithmetic_ops! {
114    feature: Simd128::new_unchecked(),
115    for cf64x1:
116        add -> (f64x2_add),
117        sub -> (f64x2_sub),
118        mul -> (cf64x1_mul),
119        div -> (cf64x1_div)
120}
121
122#[target_feature(enable = "simd128")]
123#[inline]
124unsafe fn f32x4_ldup(x: v128) -> v128 {
125    v32x4_shuffle::<0, 0, 2, 2>(x, x)
126}
127
128#[target_feature(enable = "simd128")]
129#[inline]
130unsafe fn f32x4_hdup(x: v128) -> v128 {
131    v32x4_shuffle::<1, 1, 3, 3>(x, x)
132}
133
134#[target_feature(enable = "simd128")]
135#[inline]
136unsafe fn f64x2_ldup(x: v128) -> v128 {
137    v64x2_shuffle::<0, 0>(x, x)
138}
139
140#[target_feature(enable = "simd128")]
141#[inline]
142unsafe fn f64x2_hdup(x: v128) -> v128 {
143    v64x2_shuffle::<1, 1>(x, x)
144}
145
146#[target_feature(enable = "simd128")]
147#[inline]
148unsafe fn f32x4_addsub(a: v128, b: v128) -> v128 {
149    let add = f32x4_add(a, b);
150    let sub = f32x4_sub(a, b);
151    v32x4_shuffle::<0, 5, 2, 7>(sub, add)
152}
153
154#[target_feature(enable = "simd128")]
155#[inline]
156unsafe fn f64x2_addsub(a: v128, b: v128) -> v128 {
157    let add = f64x2_add(a, b);
158    let sub = f64x2_sub(a, b);
159    v64x2_shuffle::<0, 3>(sub, add)
160}
161
162#[target_feature(enable = "simd128")]
163#[inline]
164unsafe fn cf32x2_mul(a: v128, b: v128) -> v128 {
165    let re = f32x4_ldup(a);
166    let im = f32x4_hdup(a);
167    let sh = v32x4_shuffle::<1, 0, 3, 2>(b, b);
168    f32x4_addsub(f32x4_mul(re, b), f32x4_mul(im, sh))
169}
170
171#[target_feature(enable = "simd128")]
172#[inline]
173unsafe fn cf64x1_mul(a: v128, b: v128) -> v128 {
174    let re = f64x2_ldup(a);
175    let im = f64x2_hdup(a);
176    let sh = v64x2_shuffle::<1, 0>(b, b);
177    f64x2_addsub(f64x2_mul(re, b), f64x2_mul(im, sh))
178}
179
180#[target_feature(enable = "simd128")]
181#[inline]
182unsafe fn cf32x2_div(a: v128, b: v128) -> v128 {
183    let b_re = f32x4_ldup(b);
184    let b_im = f32x4_hdup(b);
185    let a_flip = v32x4_shuffle::<1, 0, 3, 2>(a, a);
186    let norm_sqr = f32x4_add(f32x4_mul(b_re, b_re), f32x4_mul(b_im, b_im));
187    f32x4_div(
188        f32x4_addsub(f32x4_mul(a, b_re), f32x4_neg(f32x4_mul(a_flip, b_im))),
189        norm_sqr,
190    )
191}
192
193#[target_feature(enable = "simd128")]
194#[inline]
195unsafe fn cf64x1_div(a: v128, b: v128) -> v128 {
196    let b_re = f64x2_ldup(b);
197    let b_im = f64x2_hdup(b);
198    let a_flip = v64x2_shuffle::<1, 0>(a, a);
199    let norm_sqr = f64x2_add(f64x2_mul(b_re, b_re), f64x2_mul(b_im, b_im));
200    f64x2_div(
201        f64x2_addsub(f64x2_mul(a, b_re), f64x2_neg(f64x2_mul(a_flip, b_im))),
202        norm_sqr,
203    )
204}
205
206impl core::ops::Neg for cf32x2 {
207    type Output = Self;
208
209    #[inline]
210    fn neg(self) -> Self {
211        Self(unsafe { f32x4_neg(self.0) })
212    }
213}
214
215impl core::ops::Neg for cf64x1 {
216    type Output = Self;
217
218    #[inline]
219    fn neg(self) -> Self {
220        Self(unsafe { f64x2_neg(self.0) })
221    }
222}