diff options
Diffstat (limited to 'src/vectors-8-AVX.h')
-rw-r--r-- | src/vectors-8-AVX.h | 218 |
1 files changed, 159 insertions, 59 deletions
diff --git a/src/vectors-8-AVX.h b/src/vectors-8-AVX.h index ce43542..7ff04c0 100644 --- a/src/vectors-8-AVX.h +++ b/src/vectors-8-AVX.h @@ -1,3 +1,4 @@ +// -*-C++-*- // Vectorise using Intel's or AMD's AVX // Use the type __m256d directly, without introducing a wrapper class @@ -5,6 +6,7 @@ #include <cstdlib> +#include <cstring> @@ -25,9 +27,13 @@ // Vector type corresponding to CCTK_REAL +// Note: some boolean masks (e.g. ~0) correspond to nan when +// interpreted as floating point number. gcc 4.8 is clever enough to +// optimize away such constants with fast-math. We therefore need to +// handle this constant as integer number. typedef __m256d CCTK_REAL8_VEC; typedef __m256i CCTK_INTEGER8_VEC; -typedef __m256d CCTK_BOOLEAN8_VEC; +typedef __m256i CCTK_BOOLEAN8_VEC; // Number of vector elements in a CCTK_REAL_VEC #define CCTK_REAL8_VEC_SIZE 4 @@ -36,16 +42,21 @@ vec_static_assert(sizeof(CCTK_REAL8_VEC) == sizeof(CCTK_REAL8) * CCTK_REAL8_VEC_SIZE); // Integer and boolean types corresponding to this real type -typedef CCTK_INT8 CCTK_INTEGER8; -typedef CCTK_REAL8 CCTK_BOOLEAN8; +typedef CCTK_INT8 CCTK_INTEGER8; +typedef CCTK_INT8 CCTK_BOOLEAN8; + + + +// These macros are undefined at the end of this file -- use them only +// within functions, not within macros that are exported +#define I2R(x) _mm256_castsi256_pd(x) +#define R2I(x) _mm256_castpd_si256(x) union k8const_t { CCTK_INTEGER8 i[CCTK_REAL8_VEC_SIZE]; - CCTK_REAL8 f[CCTK_REAL8_VEC_SIZE]; CCTK_INTEGER8_VEC vi; - CCTK_REAL8_VEC vf; }; #define k8sign (vec8_set1i( (CCTK_INTEGER8)(1ULL << 63ULL))) @@ -61,9 +72,9 @@ CCTK_REAL8_VEC vec8_set1(CCTK_REAL8 const a) return _mm256_set1_pd(a); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE -CCTK_REAL8_VEC vec8_set1i(CCTK_INT8 const a) +CCTK_INTEGER8_VEC vec8_set1i(CCTK_INT8 const a) { - return _mm256_castsi256_pd(_mm256_set1_epi64x(a)); + return _mm256_set1_epi64x(a); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC vec8_set(CCTK_REAL8 const a, @@ -75,29 +86,25 @@ CCTK_REAL8_VEC vec8_set(CCTK_REAL8 const a, } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE -CCTK_REAL8 vec8_elt0(CCTK_REAL8_VEC const x) -{ - return ((CCTK_REAL8 const*)&x)[0]; -} -static inline CCTK_ATTRIBUTE_ALWAYS_INLINE -CCTK_REAL8 vec8_elt1(CCTK_REAL8_VEC const x) -{ - return ((CCTK_REAL8 const*)&x)[1]; -} -static inline CCTK_ATTRIBUTE_ALWAYS_INLINE -CCTK_REAL8 vec8_elt2(CCTK_REAL8_VEC const x) +CCTK_REAL8 vec8_elt(CCTK_REAL8_VEC const x, std::ptrdiff_t const d) { - return ((CCTK_REAL8 const*)&x)[2]; + CCTK_REAL8 e; + std::memcpy(&e, &((char const*)&x)[d*sizeof e], sizeof e); + return e; } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE -CCTK_REAL8 vec8_elt3(CCTK_REAL8_VEC const x) +CCTK_INTEGER8 vec8_elti(CCTK_INTEGER8_VEC const x, std::ptrdiff_t const d) { - return ((CCTK_REAL8 const*)&x)[3]; + CCTK_INTEGER8 e; + std::memcpy(&e, &((char const*)&x)[d*sizeof e], sizeof e); + return e; } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE -CCTK_REAL8 vec8_elt(CCTK_REAL8_VEC const x, std::ptrdiff_t const d) +CCTK_BOOLEAN8 vec8_eltb(CCTK_BOOLEAN8_VEC const x, std::ptrdiff_t const d) { - return ((CCTK_REAL8 const*)&x)[d]; + CCTK_BOOLEAN8 e; + std::memcpy(&e, &((char const*)&x)[d*sizeof e], sizeof e); + return e; } @@ -268,14 +275,14 @@ void vec8_store_nta_partial_lo(CCTK_REAL8& p, CCTK_REAL8_VEC const x, ptrdiff_t const n) { - _mm256_maskstore_pd(&p, _mm256_castsi256_pd(k8store_lo[n].vi), x); + _mm256_maskstore_pd(&p, I2R(k8store_lo[n].vi), x); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE void vec8_store_nta_partial_hi(CCTK_REAL8& p, CCTK_REAL8_VEC const x, ptrdiff_t const n) { - _mm256_maskstore_pd(&p, _mm256_castsi256_pd(k8store_hi[n].vi), x); + _mm256_maskstore_pd(&p, I2R(k8store_hi[n].vi), x); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE void vec8_store_nta_partial_mid(CCTK_REAL8& p, @@ -283,10 +290,7 @@ void vec8_store_nta_partial_mid(CCTK_REAL8& p, ptrdiff_t const nlo, ptrdiff_t const nhi) { - _mm256_maskstore_pd - (&p, - _mm256_castsi256_pd(k8store_lo[nlo].vi & k8store_hi[nhi].vi), - x); + _mm256_maskstore_pd(&p, I2R(k8store_lo[nlo].vi & k8store_hi[nhi].vi), x); } #else static inline CCTK_ATTRIBUTE_ALWAYS_INLINE @@ -311,7 +315,7 @@ void vec8_store_nta_partial_mid(CCTK_REAL8& p, { _mm256_maskstore_pd (&p, - _mm256_castpd_si256(_mm256_and_pd(k8store_lo[nlo].vf, k8store_hi[nhi].vf)), + R2I(_mm256_and_pd(I2R(k8store_lo[nlo].vi), I2R(k8store_hi[nhi].vi))), x); } #endif @@ -324,7 +328,7 @@ void vec8_store_nta_partial_mid(CCTK_REAL8& p, static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8neg(CCTK_REAL8_VEC const x) { - return _mm256_xor_pd(k8sign, x); + return _mm256_xor_pd(I2R(k8sign), x); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE @@ -413,13 +417,13 @@ CCTK_REAL8_VEC k8nmsub(CCTK_REAL8_VEC const x, static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8copysign(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_or_pd(_mm256_and_pd(k8notsign, x), - _mm256_and_pd(k8sign , y)); + return _mm256_or_pd(_mm256_and_pd(I2R(k8notsign), x), + _mm256_and_pd(I2R(k8sign ), y)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8fabs(CCTK_REAL8_VEC const x) { - return _mm256_and_pd(k8notsign, x); + return _mm256_and_pd(I2R(k8notsign), x); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8fmax(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) @@ -434,7 +438,7 @@ CCTK_REAL8_VEC k8fmin(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8fnabs(CCTK_REAL8_VEC const x) { - return _mm256_or_pd(k8sign, x); + return _mm256_or_pd(I2R(k8sign), x); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8sqrt(CCTK_REAL8_VEC const x) @@ -442,22 +446,111 @@ CCTK_REAL8_VEC k8sqrt(CCTK_REAL8_VEC const x) return _mm256_sqrt_pd(x); } + + +// Expensive functions +#if defined __ICC +// The Intel compiler provides intrinsics for these + +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8acos(CCTK_REAL8_VEC const x) +{ + return _mm256_acos_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8acosh(CCTK_REAL8_VEC const x) +{ + return _mm256_acosh_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8asin(CCTK_REAL8_VEC const x) +{ + return _mm256_asin_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8asinh(CCTK_REAL8_VEC const x) +{ + return _mm256_asinh_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8atan(CCTK_REAL8_VEC const x) +{ + return _mm256_atan_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8atan2(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) +{ + return _mm256_atan2_pd(x,y); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8atanh(CCTK_REAL8_VEC const x) +{ + return _mm256_atanh_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8cos(CCTK_REAL8_VEC const x) +{ + return _mm256_cos_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8cosh(CCTK_REAL8_VEC const x) +{ + return _mm256_cosh_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8exp(CCTK_REAL8_VEC const x) +{ + return _mm256_exp_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8log(CCTK_REAL8_VEC const x) +{ + return _mm256_log_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8pow(CCTK_REAL8_VEC const x, CCTK_REAL8 const a) +{ + return _mm256_pow_pd(x, _mm256_set1_pd(a)); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8sin(CCTK_REAL8_VEC const x) +{ + return _mm256_sin_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8sinh(CCTK_REAL8_VEC const x) +{ + return _mm256_sinh_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8tan(CCTK_REAL8_VEC const x) +{ + return _mm256_tan_pd(x); +} +static inline CCTK_ATTRIBUTE_ALWAYS_INLINE +CCTK_REAL8_VEC k8tanh(CCTK_REAL8_VEC const x) +{ + return _mm256_tanh_pd(x); +} + +#else + // Expensive functions #define K8REPL(f,x) \ - vec8_set(f(vec8_elt0(x)), \ - f(vec8_elt1(x)), \ - f(vec8_elt2(x)), \ - f(vec8_elt3(x))); + vec8_set(f(vec8_elt(x,0)), \ + f(vec8_elt(x,1)), \ + f(vec8_elt(x,2)), \ + f(vec8_elt(x,3))); #define K8REPL2S(f,x,a) \ - vec8_set(f(vec8_elt0(x),a), \ - f(vec8_elt1(x),a), \ - f(vec8_elt2(x),a), \ - f(vec8_elt3(x),a)); + vec8_set(f(vec8_elt(x,0),a), \ + f(vec8_elt(x,1),a), \ + f(vec8_elt(x,2),a), \ + f(vec8_elt(x,3),a)); #define K8REPL2(f,x,y) \ - vec8_set(f(vec8_elt0(x),vec8_elt0(y)), \ - f(vec8_elt1(x),vec8_elt1(y)), \ - f(vec8_elt2(x),vec8_elt2(y)), \ - f(vec8_elt3(x),vec8_elt3(y))); + vec8_set(f(vec8_elt(x,0),vec8_elt(y,0)), \ + f(vec8_elt(x,1),vec8_elt(y,1)), \ + f(vec8_elt(x,2),vec8_elt(y,2)), \ + f(vec8_elt(x,3),vec8_elt(y,3))); static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8acos(CCTK_REAL8_VEC const x) @@ -540,6 +633,8 @@ CCTK_REAL8_VEC k8tanh(CCTK_REAL8_VEC const x) return K8REPL(tanh,x); } +#endif + #define k8lfalse (vec8_set1i( 0)) @@ -547,60 +642,60 @@ CCTK_REAL8_VEC k8tanh(CCTK_REAL8_VEC const x) static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8lnot(CCTK_BOOLEAN8_VEC const x) { - return _mm256_xor_pd(k8ltrue, x); + return R2I(_mm256_xor_pd(I2R(k8ltrue), I2R(x))); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8land(CCTK_BOOLEAN8_VEC const x, CCTK_BOOLEAN8_VEC const y) { - return _mm256_and_pd(x, y); + return R2I(_mm256_and_pd(I2R(x), I2R(y))); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8lor(CCTK_BOOLEAN8_VEC const x, CCTK_BOOLEAN8_VEC const y) { - return _mm256_or_pd(x, y); + return R2I(_mm256_or_pd(I2R(x), I2R(y))); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8lxor(CCTK_BOOLEAN8_VEC const x, CCTK_BOOLEAN8_VEC const y) { - return _mm256_xor_pd(x, y); + return R2I(_mm256_xor_pd(I2R(x), I2R(y))); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8ifthen(CCTK_BOOLEAN8_VEC const x, CCTK_REAL8_VEC const y, CCTK_REAL8_VEC const z) { - return _mm256_blendv_pd(z, y, x); + return _mm256_blendv_pd(z, y, I2R(x)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8cmpeq(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_cmp_pd(x, y, _CMP_EQ_OQ); + return R2I(_mm256_cmp_pd(x, y, _CMP_EQ_OQ)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8cmpne(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_cmp_pd(x, y, _CMP_NEQ_OQ); + return R2I(_mm256_cmp_pd(x, y, _CMP_NEQ_UQ)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8cmpgt(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_cmp_pd(x, y, _CMP_GT_OQ); + return R2I(_mm256_cmp_pd(x, y, _CMP_GT_OQ)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8cmpge(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_cmp_pd(x, y, _CMP_GE_OQ); + return R2I(_mm256_cmp_pd(x, y, _CMP_GE_OQ)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8cmplt(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_cmp_pd(x, y, _CMP_LT_OQ); + return R2I(_mm256_cmp_pd(x, y, _CMP_LT_OQ)); } static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_BOOLEAN8_VEC k8cmple(CCTK_REAL8_VEC const x, CCTK_REAL8_VEC const y) { - return _mm256_cmp_pd(x, y, _CMP_LE_OQ); + return R2I(_mm256_cmp_pd(x, y, _CMP_LE_OQ)); } @@ -609,7 +704,12 @@ static inline CCTK_ATTRIBUTE_ALWAYS_INLINE CCTK_REAL8_VEC k8sgn(CCTK_REAL8_VEC const x) { CCTK_BOOLEAN8_VEC const iszero = k8cmpeq(x, vec8_set1(0.0)); - CCTK_REAL8_VEC const sign = _mm256_and_pd(k8sign, x); + CCTK_REAL8_VEC const sign = _mm256_and_pd(I2R(k8sign), x); CCTK_REAL8_VEC const signedone = _mm256_or_pd(sign, vec8_set1(1.0)); return k8ifthen(iszero, vec8_set1(0.0), signedone); } + + + +#undef I2R +#undef R2I |