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#[derive(Clone, Copy, Debug)]
23#[repr(transparent)]
24#[allow(non_camel_case_types)]
25pub struct cf32x2(v128);
26
27#[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}