AmpGen 2.1
Loading...
Searching...
No Matches
avx512d_types.h
Go to the documentation of this file.
1#ifndef AMPGEN_AVXd_TYPES
2#define AMPGEN_AVXd_TYPES 1
3
4#include <immintrin.h>
5#include <array>
6#include <iostream>
7#include <complex>
8#include <omp.h>
9#include <cmath>
10
11namespace AmpGen {
12 namespace AVX512d {
13#define stl_fallback(x) \
14 inline real_v x(const real_v &v) { \
15 auto a = v.to_array(); \
16 return real_v(std::x(a[0]), std::x(a[1]), std::x(a[2]), std::x(a[3]), std::x(a[4]), std::x(a[5]), std::x(a[6]), std::x(a[7])); \
17 }
18
19 struct real_v {
20 __m512d data;
21 static constexpr unsigned size = 8;
22 typedef double scalar_type;
23 real_v() = default;
24 real_v(__m512d data) : data(data) {}
25 real_v(const double &f) : data(_mm512_set1_pd(f)) {}
26 real_v(const double &x0, const double &x1, const double &x2, const double &x3, const double &x4, const double &x5, const double &x6, const double &x7) {
27 double tmp[8] = {x0, x1, x2, x3, x4, x5, x6, x7};
28 data = _mm512_loadu_pd(tmp);
29 }
30 real_v(const double *f) : data(_mm512_loadu_pd(f)) {}
31 void store(double *ptr) const { _mm512_storeu_pd(ptr, data); }
32 std::array<double, 8> to_array() const {
33 std::array<double, 8> b;
34 store(&b[0]);
35 return b;
36 }
37 double at(const unsigned i) const { return to_array()[i]; }
38 operator __m512d() const { return data; }
39 };
40
41 inline real_v operator+(const real_v &lhs, const real_v &rhs) { return _mm512_add_pd(lhs, rhs); }
42 inline real_v operator-(const real_v &lhs, const real_v &rhs) { return _mm512_sub_pd(lhs, rhs); }
43 inline real_v operator*(const real_v &lhs, const real_v &rhs) { return _mm512_mul_pd(lhs, rhs); }
44 inline real_v operator/(const real_v &lhs, const real_v &rhs) { return _mm512_div_pd(lhs, rhs); }
45 inline real_v operator-(const real_v &x) { return -1.f * x; }
46 inline real_v operator&(const real_v &lhs, const real_v &rhs) { return _mm512_and_pd(lhs, rhs); }
47 inline real_v operator|(const real_v &lhs, const real_v &rhs) { return _mm512_or_pd(lhs, rhs); }
48 inline real_v operator^(const real_v &lhs, const real_v &rhs) { return _mm512_xor_pd(lhs, rhs); }
49 inline real_v operator+=(real_v &lhs, const real_v &rhs) {
50 lhs = lhs + rhs;
51 return lhs;
52 }
53 inline real_v operator-=(real_v &lhs, const real_v &rhs) {
54 lhs = lhs - rhs;
55 return lhs;
56 }
57 inline real_v operator*=(real_v &lhs, const real_v &rhs) {
58 lhs = lhs * rhs;
59 return lhs;
60 }
61 inline real_v operator/=(real_v &lhs, const real_v &rhs) {
62 lhs = lhs / rhs;
63 return lhs;
64 }
65 inline real_v operator&&(const real_v &lhs, const real_v &rhs) { return _mm512_and_pd(lhs, rhs); }
66 inline real_v operator||(const real_v &lhs, const real_v &rhs) { return _mm512_or_pd(lhs, rhs); }
67 inline real_v operator!(const real_v &x) { return x ^ _mm512_castsi512_pd(_mm512_set1_epi32(-1)); }
68 inline __mmask8 operator<(const real_v &lhs, const real_v &rhs) { return _mm512_cmp_pd_mask(lhs, rhs, _CMP_LT_OS); }
69 inline __mmask8 operator>(const real_v &lhs, const real_v &rhs) { return _mm512_cmp_pd_mask(lhs, rhs, _CMP_GT_OS); }
70 inline __mmask8 operator==(const real_v &lhs, const real_v &rhs) { return _mm512_cmp_pd_mask(lhs, rhs, _CMP_EQ_OS); }
71 inline real_v sqrt(const real_v &v) { return _mm512_sqrt_pd(v); }
72 inline real_v abs(const real_v &v) { return _mm512_andnot_pd(_mm512_set1_pd(-0.), v); }
73 // inline real_v sin( const real_v& v ) { return sin512_pd(v) ; }
74 // inline real_v cos( const real_v& v ) { return cos512_pd(v) ; }
75 // inline real_v tan( const real_v& v ) { real_v s; real_v c; sincos512_pd(v, (__m512*)&s, (__m512*)&c) ; return s/c; }
76 // inline real_v exp( const real_v& v ) { return exp512_ps(v) ; }
77 inline real_v select(const __mmask8 &mask, const real_v &a, const real_v &b) { return _mm512_mask_mov_pd(b, mask, a); }
78 inline real_v select(const bool &mask, const real_v &a, const real_v &b) { return mask ? a : b; }
79 inline real_v sign(const real_v &v) { return select(v > 0., +1., -1.); }
80 inline real_v atan2(const real_v &y, const real_v &x) {
81 std::array<double, 8> bx{x.to_array()}, by{y.to_array()};
82 return real_v(std::atan2(by[0], bx[0]), std::atan2(by[1], bx[1]), std::atan2(by[2], bx[2]), std::atan2(by[3], bx[3]), std::atan2(by[4], bx[4]),
83 std::atan2(by[5], bx[5]), std::atan2(by[6], bx[6]), std::atan2(by[7], bx[7]));
84 }
85 inline __m512i double_to_int(const real_v &x) {
86 auto xr = _mm512_roundscale_pd(x, _MM_FROUND_TO_ZERO);
87 // based on: https://stackoverflow.com/questions/41144668/how-to-efficiently-perform-double-int64-conversions-with-sse-avx
88 return _mm512_sub_epi64(_mm512_castpd_si512(_mm512_add_pd(xr, _mm512_set1_pd(0x0018000000000000))),
89 _mm512_castpd_si512(_mm512_set1_pd(0x0018000000000000)));
90 }
91 inline real_v gather(const double *base_addr, const real_v &offsets) { return _mm512_i64gather_pd(double_to_int(offsets), base_addr, sizeof(double)); }
92
93 inline void frexp(const real_v &value, real_v &mant, real_v &exponent) {
94 auto arg_as_int = _mm512_castpd_si512(value);
95 static const real_v offset(4503599627370496.0 + 1022.0); // 2^52 + 1022.0
96 static const __m512i pow2_52_i = _mm512_set1_epi64(0x4330000000000000); // *reinterpret_cast<const uint64_t*>(&pow2_52_d);
97 auto b = _mm512_srl_epi64(arg_as_int, _mm_cvtsi32_si128(52));
98 auto c = _mm512_or_si512(b, pow2_52_i);
99 exponent = real_v(_mm512_castsi512_pd(c)) - offset;
100 mant
101 = _mm512_castsi512_pd(_mm512_or_si512(_mm512_and_si512(arg_as_int, _mm512_set1_epi64(0x000FFFFFFFFFFFFFll)), _mm512_set1_epi64(0x3FE0000000000000ll)));
102 }
103
104 inline real_v fmadd(const real_v &a, const real_v &b, const real_v &c) { return _mm512_fmadd_pd(a, b, c); }
105 inline real_v log(const real_v &arg) {
106 static const real_v corr = 0.693147180559945286226764;
107 static const real_v CL15 = 0.148197055177935105296783;
108 static const real_v CL13 = 0.153108178020442575739679;
109 static const real_v CL11 = 0.181837339521549679055568;
110 static const real_v CL9 = 0.22222194152736701733275;
111 static const real_v CL7 = 0.285714288030134544449368;
112 static const real_v CL5 = 0.399999999989941956712869;
113 static const real_v CL3 = 0.666666666666685503450651;
114 static const real_v CL1 = 2.0;
115 real_v mant, exponent;
116 frexp(arg, mant, exponent);
117 auto x = (mant - 1.) / (mant + 1.);
118 auto x2 = x * x;
119 auto p = fmadd(CL15, x2, CL13);
120 p = fmadd(p, x2, CL11);
121 p = fmadd(p, x2, CL9);
122 p = fmadd(p, x2, CL7);
123 p = fmadd(p, x2, CL5);
124 p = fmadd(p, x2, CL3);
125 p = fmadd(p, x2, CL1);
126 p = fmadd(p, x, corr * exponent);
127 return p;
128 }
130 return a - real_v(_mm512_roundscale_pd(a / b, _MM_FROUND_TO_NEG_INF)) * b;
131 }
132 inline real_v fmod(const real_v &a, const real_v &b) {
133 auto r = remainder(abs(a), abs(b));
134 return select(a > 0., r, -r);
135 }
136
137 inline std::ostream &operator<<(std::ostream &os, const real_v &obj) {
138 auto buffer = obj.to_array();
139 for(unsigned i = 0; i != 8; ++i) os << buffer[i] << " ";
140 return os;
141 }
142
143 using complex_v = std::complex<real_v>;
144 inline complex_v operator+(const complex_v &lhs, const real_v &rhs) { return complex_v(lhs.real() + rhs, lhs.imag()); }
145 inline complex_v operator-(const complex_v &lhs, const real_v &rhs) { return complex_v(lhs.real() - rhs, lhs.imag()); }
146 inline complex_v operator*(const complex_v &lhs, const real_v &rhs) { return complex_v(lhs.real() * rhs, lhs.imag() * rhs); }
147 inline complex_v operator/(const complex_v &lhs, const real_v &rhs) { return complex_v(lhs.real() / rhs, lhs.imag() / rhs); }
148 inline complex_v operator+(const real_v &lhs, const complex_v &rhs) { return complex_v(lhs + rhs.real(), rhs.imag()); }
149 inline complex_v operator-(const real_v &lhs, const complex_v &rhs) { return complex_v(lhs - rhs.real(), -rhs.imag()); }
150 inline complex_v operator*(const real_v &lhs, const complex_v &rhs) { return complex_v(lhs * rhs.real(), lhs * rhs.imag()); }
151 inline complex_v operator/(const real_v &lhs, const complex_v &rhs) {
152 return complex_v(lhs * rhs.real(), -lhs * rhs.imag()) / (rhs.real() * rhs.real() + rhs.imag() * rhs.imag());
153 }
154 inline real_v abs(const complex_v &v) { return sqrt(v.real() * v.real() + v.imag() * v.imag()); }
155 inline real_v norm(const complex_v &v) { return (v.real() * v.real() + v.imag() * v.imag()); }
156 inline complex_v select(const __mmask8 &mask, const complex_v &a, const complex_v &b) {
157 return complex_v(select(mask, a.real(), b.real()), select(mask, a.imag(), b.imag()));
158 }
159 inline complex_v select(const __mmask8 &mask, const real_v &a, const complex_v &b) {
160 return complex_v(select(mask, a, b.real()), select(mask, 0.f, b.imag()));
161 }
162 inline complex_v select(const __mmask8 &mask, const complex_v &a, const real_v &b) {
163 return complex_v(select(mask, a.real(), b), select(mask, a.imag(), 0.f));
164 }
165 inline complex_v select(const bool &mask, const complex_v &a, const complex_v &b) { return mask ? a : b; }
166 inline complex_v exp(const complex_v &v) {
167 auto [s, c] = sincos(v.imag());
168 return exp(v.real()) * complex_v(c, s);
169 }
170 inline complex_v sqrt(const complex_v &v) {
171 auto r = abs(v);
172 return complex_v(sqrt(0.5 * (r + v.real())), sign(v.imag()) * sqrt(0.5 * (r - v.real())));
173 }
174 inline complex_v log(const complex_v &v) { return complex_v(0.5 * log(norm(v)), atan2(v.imag(), v.real())); }
175
176 inline std::ostream &operator<<(std::ostream &os, const complex_v &obj) { return os << "( " << obj.real() << ") (" << obj.imag() << ")"; }
177#pragma omp declare reduction(+ : real_v : omp_out = omp_out + omp_in)
178#pragma omp declare reduction(+ : complex_v : omp_out = omp_out + omp_in)
179
180 }
181}
182
183#endif
#define stl_fallback(x)
real_v abs(const real_v &v)
real_v operator||(const real_v &lhs, const real_v &rhs)
real_v sqrt(const real_v &v)
real_v atan2(const real_v &y, const real_v &x)
real_v gather(const double *base_addr, const real_v &offsets)
real_v fmadd(const real_v &a, const real_v &b, const real_v &c)
real_v tan(const real_v &v)
real_v operator-(const real_v &lhs, const real_v &rhs)
real_v cos(const real_v &v)
__mmask8 operator>(const real_v &lhs, const real_v &rhs)
real_v operator|(const real_v &lhs, const real_v &rhs)
real_v fmod(const real_v &a, const real_v &b)
real_v log(const real_v &arg)
real_v operator-=(real_v &lhs, const real_v &rhs)
__m512i double_to_int(const real_v &x)
real_v select(const __mmask8 &mask, const real_v &a, const real_v &b)
real_v operator!(const real_v &x)
void frexp(const real_v &value, real_v &mant, real_v &exponent)
std::complex< real_v > complex_v
__mmask8 operator<(const real_v &lhs, const real_v &rhs)
real_v operator^(const real_v &lhs, const real_v &rhs)
real_v operator/(const real_v &lhs, const real_v &rhs)
real_v sign(const real_v &v)
std::ostream & operator<<(std::ostream &os, const real_v &obj)
real_v sin(const real_v &v)
real_v operator&&(const real_v &lhs, const real_v &rhs)
real_v operator&(const real_v &lhs, const real_v &rhs)
real_v remainder(const real_v &a, const real_v &b)
__mmask8 operator==(const real_v &lhs, const real_v &rhs)
real_v operator*=(real_v &lhs, const real_v &rhs)
real_v operator/=(real_v &lhs, const real_v &rhs)
real_v operator+=(real_v &lhs, const real_v &rhs)
real_v operator+(const real_v &lhs, const real_v &rhs)
real_v norm(const complex_v &v)
real_v exp(const real_v &v)
real_v operator*(const real_v &lhs, const real_v &rhs)
AVX::real_v real_v
Definition utils.h:47
real_v(const double &f)
std::array< double, 8 > to_array() const
void store(double *ptr) const
double at(const unsigned i) const
real_v(const double *f)
real_v(const double &x0, const double &x1, const double &x2, const double &x3, const double &x4, const double &x5, const double &x6, const double &x7)
static constexpr unsigned size