poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_ifft8_avx_fma.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_ifft8_avx_fma.cRaw
1#include <assert.h>
2#include <immintrin.h>
3#include <stdint.h>
4
5#include "reim_fft_private.h"
6
7__always_inline void reim_invctwiddle_avx_fma(__m256d* ra, __m256d* rb, __m256d* ia, __m256d* ib, const __m256d omre,
8 const __m256d omim) {
9 __m256d rdiff = _mm256_sub_pd(*ra, *rb);
10 __m256d idiff = _mm256_sub_pd(*ia, *ib);
11 *ra = _mm256_add_pd(*ra, *rb);
12 *ia = _mm256_add_pd(*ia, *ib);
13
14 *rb = _mm256_mul_pd(idiff, omim);
15 *rb = _mm256_fmsub_pd(rdiff, omre, *rb);
16
17 *ib = _mm256_mul_pd(rdiff, omim);
18 *ib = _mm256_fmadd_pd(idiff, omre, *ib);
19}
20
21EXPORT void reim_ifft8_avx_fma(double* dre, double* dim, const void* ompv) {
22 const double* omp = (const double*)ompv;
23
24 __m256d ra0 = _mm256_loadu_pd(dre);
25 __m256d ra4 = _mm256_loadu_pd(dre + 4);
26 __m256d ia0 = _mm256_loadu_pd(dim);
27 __m256d ia4 = _mm256_loadu_pd(dim + 4);
28
29 // 1
30 {
31 const __m256d fft8neg2 = _mm256_castsi256_pd(_mm256_set_epi64x(UINT64_C(1) << 63, UINT64_C(1) << 63, 0, 0));
32 __m256d omr = _mm256_loadu_pd(omp); // r0,r1,i0,i1
33 __m256d omiirr = _mm256_permute2f128_pd(omr, omr, 1); // i0,i1,r0,r1
34 __m256d omi = _mm256_xor_pd(omiirr, fft8neg2); // i0,i1,-r0,-r1
35
36 __m256d rb = _mm256_unpackhi_pd(ra0, ra4);
37 __m256d ib = _mm256_unpackhi_pd(ia0, ia4);
38 __m256d ra = _mm256_unpacklo_pd(ra0, ra4);
39 __m256d ia = _mm256_unpacklo_pd(ia0, ia4);
40
41 reim_invctwiddle_avx_fma(&ra, &rb, &ia, &ib, omr, omi);
42
43 ra4 = _mm256_unpackhi_pd(ra, rb);
44 ia4 = _mm256_unpackhi_pd(ia, ib);
45 ra0 = _mm256_unpacklo_pd(ra, rb);
46 ia0 = _mm256_unpacklo_pd(ia, ib);
47 }
48
49 // 2
50 {
51 const __m128d ifft8neg = _mm_castsi128_pd(_mm_set_epi64x(0, UINT64_C(1) << 63));
52 __m128d omri = _mm_loadu_pd(omp + 4); // r,i
53 __m128d ommri = _mm_xor_pd(omri, ifft8neg); // -r,i
54 __m256d omrimri = _mm256_set_m128d(ommri, omri); // r,i,-r,i
55 __m256d omi = _mm256_permute_pd(omrimri, 3); // i,i,-r,-r
56 __m256d omr = _mm256_permute_pd(omrimri, 12); // r,r,i,i
57
58 __m256d rb = _mm256_permute2f128_pd(ra0, ra4, 0x31);
59 __m256d ib = _mm256_permute2f128_pd(ia0, ia4, 0x31);
60 __m256d ra = _mm256_permute2f128_pd(ra0, ra4, 0x20);
61 __m256d ia = _mm256_permute2f128_pd(ia0, ia4, 0x20);
62
63 reim_invctwiddle_avx_fma(&ra, &rb, &ia, &ib, omr, omi);
64
65 ra0 = _mm256_permute2f128_pd(ra, rb, 0x20);
66 ra4 = _mm256_permute2f128_pd(ra, rb, 0x31);
67 ia0 = _mm256_permute2f128_pd(ia, ib, 0x20);
68 ia4 = _mm256_permute2f128_pd(ia, ib, 0x31);
69 }
70
71 // 3
72 {
73 __m128d omri = _mm_loadu_pd(omp + 6); // r,i
74 __m256d omriri = _mm256_set_m128d(omri, omri); // r,i,r,i
75 __m256d omi = _mm256_permute_pd(omriri, 15); // i,i,i,i
76 __m256d omr = _mm256_permute_pd(omriri, 0); // r,r,r,r
77
78 reim_invctwiddle_avx_fma(&ra0, &ra4, &ia0, &ia4, omr, omi);
79 }
80
81 // 4
82 _mm256_storeu_pd(dre, ra0);
83 _mm256_storeu_pd(dre + 4, ra4);
84 _mm256_storeu_pd(dim, ia0);
85 _mm256_storeu_pd(dim + 4, ia4);
86}