poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_conversions_avx.c
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/spqlios/reim/reim_conversions_avx.cRaw
1#include <immintrin.h>
2
3#include "reim_fft_private.h"
4
5void reim_from_znx64_bnd50_fma(const REIM_FROM_ZNX64_PRECOMP* precomp, void* r, const int64_t* x) {
6 static const double EXPO = INT64_C(1) << 52;
7 const int64_t ADD_CST = INT64_C(1) << 51;
8 const double SUB_CST = INT64_C(3) << 51;
9
10 const __m256d SUB_CST_4 = _mm256_set1_pd(SUB_CST);
11 const __m256i ADD_CST_4 = _mm256_set1_epi64x(ADD_CST);
12 const __m256d EXPO_4 = _mm256_set1_pd(EXPO);
13
14 double(*out)[4] = (double(*)[4])r;
15 __m256i* in = (__m256i*)x;
16 __m256i* inend = (__m256i*)(x + (precomp->m << 1));
17 do {
18 // read the next value
19 __m256i a = _mm256_loadu_si256(in);
20 a = _mm256_add_epi64(a, ADD_CST_4);
21 __m256d ad = _mm256_castsi256_pd(a);
22 ad = _mm256_or_pd(ad, EXPO_4);
23 ad = _mm256_sub_pd(ad, SUB_CST_4);
24 // store the next value
25 _mm256_storeu_pd(out[0], ad);
26 ++out;
27 ++in;
28 } while (in < inend);
29}
30
31// version where the output norm can be as big as 2^63
32void reim_to_znx64_avx2_bnd63_fma(const REIM_TO_ZNX64_PRECOMP* precomp, int64_t* r, const void* x) {
33 static const uint64_t SIGN_MASK = 0x8000000000000000UL;
34 static const uint64_t EXPO_MASK = 0x7FF0000000000000UL;
35 static const uint64_t MANTISSA_MASK = 0x000FFFFFFFFFFFFFUL;
36 static const uint64_t MANTISSA_MSB = 0x0010000000000000UL;
37 const double divisor_bits = precomp->divisor * ((double)(INT64_C(1) << 52));
38 const double offset = precomp->divisor / 2.;
39
40 const __m256d SIGN_MASK_4 = _mm256_castsi256_pd(_mm256_set1_epi64x(SIGN_MASK));
41 const __m256i EXPO_MASK_4 = _mm256_set1_epi64x(EXPO_MASK);
42 const __m256i MANTISSA_MASK_4 = _mm256_set1_epi64x(MANTISSA_MASK);
43 const __m256i MANTISSA_MSB_4 = _mm256_set1_epi64x(MANTISSA_MSB);
44 const __m256d offset_4 = _mm256_set1_pd(offset);
45 const __m256i divi_bits_4 = _mm256_castpd_si256(_mm256_set1_pd(divisor_bits));
46
47 double(*in)[4] = (double(*)[4])x;
48 __m256i* out = (__m256i*)r;
49 __m256i* outend = (__m256i*)(r + (precomp->m << 1));
50 do {
51 // read the next value
52 __m256d a = _mm256_loadu_pd(in[0]);
53 // a += sign(a) * m/2
54 __m256d asign = _mm256_and_pd(a, SIGN_MASK_4);
55 a = _mm256_add_pd(a, _mm256_or_pd(asign, offset_4));
56 // sign: either 0 or -1
57 __m256i sign_mask = _mm256_castpd_si256(asign);
58 sign_mask = _mm256_sub_epi64(_mm256_set1_epi64x(0), _mm256_srli_epi64(sign_mask, 63));
59 // compute the exponents
60 __m256i a0exp = _mm256_and_si256(_mm256_castpd_si256(a), EXPO_MASK_4);
61 __m256i a0lsh = _mm256_sub_epi64(a0exp, divi_bits_4);
62 __m256i a0rsh = _mm256_sub_epi64(divi_bits_4, a0exp);
63 a0lsh = _mm256_srli_epi64(a0lsh, 52);
64 a0rsh = _mm256_srli_epi64(a0rsh, 52);
65 // compute the new mantissa
66 __m256i a0pos = _mm256_and_si256(_mm256_castpd_si256(a), MANTISSA_MASK_4);
67 a0pos = _mm256_or_si256(a0pos, MANTISSA_MSB_4);
68 a0lsh = _mm256_sllv_epi64(a0pos, a0lsh);
69 a0rsh = _mm256_srlv_epi64(a0pos, a0rsh);
70 __m256i final = _mm256_or_si256(a0lsh, a0rsh);
71 // negate if the sign was negative
72 final = _mm256_xor_si256(final, sign_mask);
73 final = _mm256_sub_epi64(final, sign_mask);
74 // read the next value
75 _mm256_storeu_si256(out, final);
76 ++out;
77 ++in;
78 } while (out < outend);
79}
80
81// version where the output norm can be as big as 2^50
82void reim_to_znx64_avx2_bnd50_fma(const REIM_TO_ZNX64_PRECOMP* precomp, int64_t* r, const void* x) {
83 static const uint64_t MANTISSA_MASK = 0x000FFFFFFFFFFFFFUL;
84 const int64_t SUB_CST = INT64_C(1) << 51;
85 const double add_cst = precomp->divisor * ((double)(INT64_C(3) << 51));
86
87 const __m256i SUB_CST_4 = _mm256_set1_epi64x(SUB_CST);
88 const __m256d add_cst_4 = _mm256_set1_pd(add_cst);
89 const __m256i MANTISSA_MASK_4 = _mm256_set1_epi64x(MANTISSA_MASK);
90
91 double(*in)[4] = (double(*)[4])x;
92 __m256i* out = (__m256i*)r;
93 __m256i* outend = (__m256i*)(r + (precomp->m << 1));
94 do {
95 // read the next value
96 __m256d a = _mm256_loadu_pd(in[0]);
97 a = _mm256_add_pd(a, add_cst_4);
98 __m256i ai = _mm256_castpd_si256(a);
99 ai = _mm256_and_si256(ai, MANTISSA_MASK_4);
100 ai = _mm256_sub_epi64(ai, SUB_CST_4);
101 // store the next value
102 _mm256_storeu_si256(out, ai);
103 ++out;
104 ++in;
105 } while (out < outend);
106}