mirror of
https://github.com/paboyle/Grid.git
synced 2025-06-12 20:27:06 +01:00
Build reorg with which I am a bit happier
This commit is contained in:
344
lib/simd/Grid_vComplexD.h
Normal file
344
lib/simd/Grid_vComplexD.h
Normal file
@ -0,0 +1,344 @@
|
||||
#ifndef GRID_VCOMPLEXD_H
|
||||
#define GRID_VCOMPLEXD_H
|
||||
|
||||
namespace Grid {
|
||||
class vComplexD {
|
||||
public:
|
||||
zvec v;
|
||||
public:
|
||||
typedef zvec vector_type;
|
||||
typedef ComplexD scalar_type;
|
||||
|
||||
vComplexD & operator = ( Zero & z){
|
||||
vzero(*this);
|
||||
return (*this);
|
||||
}
|
||||
vComplexD(){};
|
||||
vComplexD(ComplexD a){
|
||||
vsplat(*this,a);
|
||||
};
|
||||
vComplexD(double a){
|
||||
vsplat(*this,ComplexD(a));
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// mac, mult, sub, add, adj
|
||||
// Should do an AVX2 version with mac.
|
||||
///////////////////////////////////////////////
|
||||
friend inline void mac (vComplexD * __restrict__ y,const vComplexD * __restrict__ a,const vComplexD *__restrict__ x) {*y = (*a)*(*x)+(*y);};
|
||||
friend inline void mult(vComplexD * __restrict__ y,const vComplexD * __restrict__ l,const vComplexD *__restrict__ r) {*y = (*l) * (*r);}
|
||||
friend inline void sub (vComplexD * __restrict__ y,const vComplexD * __restrict__ l,const vComplexD *__restrict__ r) {*y = (*l) - (*r);}
|
||||
friend inline void add (vComplexD * __restrict__ y,const vComplexD * __restrict__ l,const vComplexD *__restrict__ r) {*y = (*l) + (*r);}
|
||||
friend inline vComplexD adj(const vComplexD &in){ return conj(in); }
|
||||
|
||||
//////////////////////////////////
|
||||
// Initialise to 1,0,i
|
||||
//////////////////////////////////
|
||||
friend inline void vone (vComplexD &ret){ vsplat(ret,1.0,0.0);}
|
||||
friend inline void vzero (vComplexD &ret){ vsplat(ret,0.0,0.0);}
|
||||
friend inline void vcomplex_i(vComplexD &ret){ vsplat(ret,0.0,1.0);}
|
||||
|
||||
////////////////////////////////////
|
||||
// Arithmetic operator overloads +,-,*
|
||||
////////////////////////////////////
|
||||
friend inline vComplexD operator + (vComplexD a, vComplexD b)
|
||||
{
|
||||
vComplexD ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_add_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_add_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_add_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_add(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vComplexD operator - (vComplexD a, vComplexD b)
|
||||
{
|
||||
vComplexD ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_sub_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_sub_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_sub_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_sub(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vComplexD operator * (vComplexD a, vComplexD b)
|
||||
{
|
||||
vComplexD ret;
|
||||
|
||||
//Multiplicationof (ak+ibk)*(ck+idk)
|
||||
// a + i b can be stored as a data structure
|
||||
//From intel optimisation reference guide
|
||||
/*
|
||||
movsldup xmm0, Src1; load real parts into the destination,
|
||||
; a1, a1, a0, a0
|
||||
movaps xmm1, src2; load the 2nd pair of complex values, ; i.e. d1, c1, d0, c0
|
||||
mulps xmm0, xmm1; temporary results, a1d1, a1c1, a0d0, ; a0c0
|
||||
shufps xmm1, xmm1, b1; reorder the real and imaginary ; parts, c1, d1, c0, d0
|
||||
movshdup xmm2, Src1; load the imaginary parts into the ; destination, b1, b1, b0, b0
|
||||
mulps xmm2, xmm1; temporary results, b1c1, b1d1, b0c0, ; b0d0
|
||||
addsubps xmm0, xmm2; b1c1+a1d1, a1c1 -b1d1, b0c0+a0d
|
||||
VSHUFPD (VEX.256 encoded version)
|
||||
IF IMM0[0] = 0
|
||||
THEN DEST[63:0]=SRC1[63:0] ELSE DEST[63:0]=SRC1[127:64] FI;
|
||||
IF IMM0[1] = 0
|
||||
THEN DEST[127:64]=SRC2[63:0] ELSE DEST[127:64]=SRC2[127:64] FI;
|
||||
IF IMM0[2] = 0
|
||||
THEN DEST[191:128]=SRC1[191:128] ELSE DEST[191:128]=SRC1[255:192] FI;
|
||||
IF IMM0[3] = 0
|
||||
THEN DEST[255:192]=SRC2[191:128] ELSE DEST[255:192]=SRC2[255:192] FI;
|
||||
*/
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
zvec ymm0,ymm1,ymm2;
|
||||
ymm0 = _mm256_shuffle_pd(a.v,a.v,0x0); // ymm0 <- ar ar, ar,ar b'00,00
|
||||
ymm0 = _mm256_mul_pd(ymm0,b.v); // ymm0 <- ar bi, ar br
|
||||
ymm1 = _mm256_shuffle_pd(b.v,b.v,0x5); // ymm1 <- br,bi b'01,01
|
||||
ymm2 = _mm256_shuffle_pd(a.v,a.v,0xF); // ymm2 <- ai,ai b'11,11
|
||||
ymm1 = _mm256_mul_pd(ymm1,ymm2); // ymm1 <- br ai, ai bi
|
||||
ret.v= _mm256_addsub_pd(ymm0,ymm1);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
zvec ymm0,ymm1,ymm2;
|
||||
ymm0 = _mm_shuffle_pd(a.v,a.v,0x0); // ymm0 <- ar ar,
|
||||
ymm0 = _mm_mul_pd(ymm0,b.v); // ymm0 <- ar bi, ar br
|
||||
ymm1 = _mm_shuffle_pd(b.v,b.v,0x1); // ymm1 <- br,bi b01
|
||||
ymm2 = _mm_shuffle_pd(a.v,a.v,0x3); // ymm2 <- ai,ai b11
|
||||
ymm1 = _mm_mul_pd(ymm1,ymm2); // ymm1 <- br ai, ai bi
|
||||
ret.v= _mm_addsub_pd(ymm0,ymm1);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
/* This is from
|
||||
* Automatic SIMD Vectorization of Fast Fourier Transforms for the Larrabee and AVX Instruction Sets
|
||||
* @inproceedings{McFarlin:2011:ASV:1995896.1995938,
|
||||
* author = {McFarlin, Daniel S. and Arbatov, Volodymyr and Franchetti, Franz and P\"{u}schel, Markus},
|
||||
* title = {Automatic SIMD Vectorization of Fast Fourier Transforms for the Larrabee and AVX Instruction Sets},
|
||||
* booktitle = {Proceedings of the International Conference on Supercomputing},
|
||||
* series = {ICS '11},
|
||||
* year = {2011},
|
||||
* isbn = {978-1-4503-0102-2},
|
||||
* location = {Tucson, Arizona, USA},
|
||||
* pages = {265--274},
|
||||
* numpages = {10},
|
||||
* url = {http://doi.acm.org/10.1145/1995896.1995938},
|
||||
* doi = {10.1145/1995896.1995938},
|
||||
* acmid = {1995938},
|
||||
* publisher = {ACM},
|
||||
* address = {New York, NY, USA},
|
||||
* keywords = {autovectorization, fourier transform, program generation, simd, super-optimization},
|
||||
* }
|
||||
*/
|
||||
zvec vzero,ymm0,ymm1,real,imag;
|
||||
vzero = _mm512_setzero();
|
||||
ymm0 = _mm512_swizzle_pd(a.v, _MM_SWIZ_REG_CDAB); //
|
||||
real = _mm512_mask_or_epi64(a.v, 0xAAAA,vzero, ymm0);
|
||||
imag = _mm512_mask_sub_pd(a.v, 0x5555,vzero, ymm0);
|
||||
ymm1 = _mm512_mul_pd(real, b.v);
|
||||
ymm0 = _mm512_swizzle_pd(b.v, _MM_SWIZ_REG_CDAB); // OK
|
||||
ret.v= _mm512_fmadd_pd(ymm0,imag,ymm1);
|
||||
/* Imag OK */
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_mul(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// General permute; assumes vector length is same across
|
||||
// all subtypes; may not be a good assumption, but could
|
||||
// add the vector width as a template param for BG/Q for example
|
||||
////////////////////////////////////////////////////////////////////
|
||||
friend inline void permute(vComplexD &y,vComplexD b,int perm)
|
||||
{
|
||||
Gpermute<vComplexD>(y,b,perm);
|
||||
}
|
||||
friend inline void merge(vComplexD &y,std::vector<ComplexD *> &extracted)
|
||||
{
|
||||
Gmerge<vComplexD,ComplexD >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vComplexD &y,std::vector<ComplexD *> &extracted)
|
||||
{
|
||||
Gextract<vComplexD,ComplexD>(y,extracted);
|
||||
}
|
||||
friend inline void merge(vComplexD &y,std::vector<ComplexD > &extracted)
|
||||
{
|
||||
Gmerge<vComplexD,ComplexD >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vComplexD &y,std::vector<ComplexD > &extracted)
|
||||
{
|
||||
Gextract<vComplexD,ComplexD>(y,extracted);
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// Splat
|
||||
///////////////////////
|
||||
friend inline void vsplat(vComplexD &ret,ComplexD c){
|
||||
float a= real(c);
|
||||
float b= imag(c);
|
||||
vsplat(ret,a,b);
|
||||
}
|
||||
|
||||
|
||||
friend inline void vsplat(vComplexD &ret,double rl,double ig){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_pd(ig,rl,ig,rl);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_pd(ig,rl);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_pd(ig,rl,ig,rl,ig,rl,ig,rl);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {ig,rl,ig,rl};
|
||||
#endif
|
||||
}
|
||||
|
||||
friend inline void vset(vComplexD &ret,ComplexD *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_pd(a[1].imag(),a[1].real(),a[0].imag(),a[0].real());
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_pd(a[0].imag(),a[0].real());
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_pd(a[3].imag(),a[3].real(),a[2].imag(),a[2].real(),a[1].imag(),a[1].real(),a[0].imag(),a[0].real());
|
||||
// Note v has a0 a1 a2 a3
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a[0].real(),a[0].imag(),a[1].real(),a[3].imag()};
|
||||
#endif
|
||||
}
|
||||
|
||||
friend inline void vstore(const vComplexD &ret, ComplexD *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
_mm256_store_pd((double *)a,ret.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
_mm_store_pd((double *)a,ret.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
_mm512_store_pd((double *)a,ret.v);
|
||||
//Note v has a3 a2 a1 a0
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
friend inline void vprefetch(const vComplexD &v)
|
||||
{
|
||||
_mm_prefetch((const char*)&v.v,_MM_HINT_T0);
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// Conjugate
|
||||
////////////////////////
|
||||
friend inline vComplexD conj(const vComplexD &in){
|
||||
vComplexD ret ; vzero(ret);
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
// addsubps 0, inv=>0+in.v[3] 0-in.v[2], 0+in.v[1], 0-in.v[0], ...
|
||||
__m256d tmp = _mm256_addsub_pd(ret.v,_mm256_shuffle_pd(in.v,in.v,0x5));
|
||||
ret.v=_mm256_shuffle_pd(tmp,tmp,0x5);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_addsub_pd(ret.v,in.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
// Xeon does not have fmaddsub or addsub
|
||||
// with mask 0xa (1010), v[0] -v[1] v[2] -v[3] ....
|
||||
ret.v = _mm512_mask_sub_pd(in.v, 0xaaaa,ret.v, in.v);
|
||||
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
// REDUCE FIXME must be a cleaner implementation
|
||||
friend inline ComplexD Reduce(const vComplexD & in)
|
||||
{
|
||||
#if defined (AVX1) || defined(AVX2)
|
||||
// return std::complex<double>(_mm256_mask_reduce_add_pd(0x55, in.v),_mm256_mask_reduce_add_pd(0xAA, in.v));
|
||||
__attribute__ ((aligned(32))) double c_[4];
|
||||
_mm256_store_pd(c_,in.v);
|
||||
return ComplexD(c_[0]+c_[2],c_[1]+c_[3]);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
return ComplexD(_mm512_mask_reduce_add_pd(0x5555, in.v),_mm512_mask_reduce_add_pd(0xAAAA, in.v));
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#endif
|
||||
}
|
||||
|
||||
// Unary negation
|
||||
friend inline vComplexD operator -(const vComplexD &r) {
|
||||
vComplexD ret;
|
||||
vzero(ret);
|
||||
ret = ret - r;
|
||||
return ret;
|
||||
}
|
||||
// *=,+=,-= operators
|
||||
inline vComplexD &operator *=(const vComplexD &r) {
|
||||
*this = (*this)*r;
|
||||
return *this;
|
||||
}
|
||||
inline vComplexD &operator +=(const vComplexD &r) {
|
||||
*this = *this+r;
|
||||
return *this;
|
||||
}
|
||||
inline vComplexD &operator -=(const vComplexD &r) {
|
||||
*this = *this-r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
static int Nsimd(void) { return sizeof(zvec)/sizeof(double)/2;}
|
||||
};
|
||||
|
||||
|
||||
inline vComplexD innerProduct(const vComplexD & l, const vComplexD & r) { return conj(l)*r; }
|
||||
|
||||
|
||||
typedef vComplexD vDComplex;
|
||||
inline void zeroit(vComplexD &z){ vzero(z);}
|
||||
|
||||
inline vComplexD outerProduct(const vComplexD &l, const vComplexD& r)
|
||||
{
|
||||
return l*r;
|
||||
}
|
||||
inline vComplexD trace(const vComplexD &arg){
|
||||
return arg;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//// Generic routine to promote object<complex> -> object<vcomplex>
|
||||
//// Supports the array reordering transformation that gives me SIMD utilisation
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
template<template<class> class object>
|
||||
inline object<vComplex> splat(object<Complex >s){
|
||||
object<vComplex> ret;
|
||||
vComplex * v_ptr = (vComplex *)& ret;
|
||||
Complex * s_ptr = (Complex *) &s;
|
||||
for(int i=0;i<sizeof(ret);i+=sizeof(vComplex)){
|
||||
vsplat(*(v_ptr++),*(s_ptr++));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
}
|
||||
#endif
|
383
lib/simd/Grid_vComplexF.h
Normal file
383
lib/simd/Grid_vComplexF.h
Normal file
@ -0,0 +1,383 @@
|
||||
#ifndef GRID_VCOMPLEXF
|
||||
#define GRID_VCOMPLEXF
|
||||
|
||||
namespace Grid {
|
||||
|
||||
/*
|
||||
inline void Print(const char *A,cvec c) {
|
||||
float *fp=(float *)&c;
|
||||
printf(A);
|
||||
printf(" %le %le %le %le %le %le %le %le\n",
|
||||
fp[0],fp[1],fp[2],fp[3],fp[4],fp[5],fp[6],fp[7]);
|
||||
}
|
||||
*/
|
||||
|
||||
class vComplexF {
|
||||
// protected:
|
||||
|
||||
public:
|
||||
cvec v;
|
||||
|
||||
public:
|
||||
static inline int Nsimd(void) { return sizeof(cvec)/sizeof(float)/2;}
|
||||
public:
|
||||
typedef cvec vector_type;
|
||||
typedef ComplexF scalar_type;
|
||||
|
||||
vComplexF & operator = ( Zero & z){
|
||||
vzero(*this);
|
||||
return (*this);
|
||||
}
|
||||
vComplexF(){};
|
||||
vComplexF(ComplexF a){
|
||||
vsplat(*this,a);
|
||||
};
|
||||
vComplexF(double a){
|
||||
vsplat(*this,ComplexF(a));
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// mac, mult, sub, add, adj
|
||||
// Should do an AVX2 version with mac.
|
||||
///////////////////////////////////////////////
|
||||
friend inline void mac (vComplexF * __restrict__ y,const vComplexF * __restrict__ a,const vComplexF *__restrict__ x){ *y = (*a)*(*x)+(*y); };
|
||||
friend inline void mult(vComplexF * __restrict__ y,const vComplexF * __restrict__ l,const vComplexF *__restrict__ r){ *y = (*l) * (*r); }
|
||||
friend inline void sub (vComplexF * __restrict__ y,const vComplexF * __restrict__ l,const vComplexF *__restrict__ r){ *y = (*l) - (*r); }
|
||||
friend inline void add (vComplexF * __restrict__ y,const vComplexF * __restrict__ l,const vComplexF *__restrict__ r){ *y = (*l) + (*r); }
|
||||
friend inline vComplexF adj(const vComplexF &in){ return conj(in); }
|
||||
|
||||
//////////////////////////////////
|
||||
// Initialise to 1,0,i
|
||||
//////////////////////////////////
|
||||
friend inline void vone(vComplexF &ret) { vsplat(ret,1.0,0.0); }
|
||||
friend inline void vzero(vComplexF &ret) { vsplat(ret,0.0,0.0); }
|
||||
friend inline void vcomplex_i(vComplexF &ret){ vsplat(ret,0.0,1.0);}
|
||||
|
||||
////////////////////////////////////
|
||||
// Arithmetic operator overloads +,-,*
|
||||
////////////////////////////////////
|
||||
friend inline vComplexF operator + (vComplexF a, vComplexF b)
|
||||
{
|
||||
vComplexF ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_add_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_add_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_add_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#error
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vComplexF operator - (vComplexF a, vComplexF b)
|
||||
{
|
||||
vComplexF ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_sub_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_sub_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_sub_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#error
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vComplexF operator * (vComplexF a, vComplexF b)
|
||||
{
|
||||
vComplexF ret;
|
||||
|
||||
//Multiplicationof (ak+ibk)*(ck+idk)
|
||||
// a + i b can be stored as a data structure
|
||||
//From intel optimisation reference
|
||||
/*
|
||||
movsldup xmm0, Src1; load real parts into the destination,
|
||||
; a1, a1, a0, a0
|
||||
movaps xmm1, src2; load the 2nd pair of complex values, ; i.e. d1, c1, d0, c0
|
||||
mulps xmm0, xmm1; temporary results, a1d1, a1c1, a0d0, ; a0c0
|
||||
shufps xmm1, xmm1, b1; reorder the real and imaginary ; parts, c1, d1, c0, d0
|
||||
movshdup xmm2, Src1; load the imaginary parts into the ; destination, b1, b1, b0, b0
|
||||
mulps xmm2, xmm1; temporary results, b1c1, b1d1, b0c0, ; b0d0
|
||||
addsubps xmm0, xmm2; b1c1+a1d1, a1c1 -b1d1, b0c0+a0d
|
||||
*/
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
cvec ymm0,ymm1,ymm2;
|
||||
ymm0 = _mm256_shuffle_ps(a.v,a.v,_MM_SHUFFLE(2,2,0,0)); // ymm0 <- ar ar,
|
||||
ymm0 = _mm256_mul_ps(ymm0,b.v); // ymm0 <- ar bi, ar br
|
||||
// FIXME AVX2 could MAC
|
||||
ymm1 = _mm256_shuffle_ps(b.v,b.v,_MM_SHUFFLE(2,3,0,1)); // ymm1 <- br,bi
|
||||
ymm2 = _mm256_shuffle_ps(a.v,a.v,_MM_SHUFFLE(3,3,1,1)); // ymm2 <- ai,ai
|
||||
ymm1 = _mm256_mul_ps(ymm1,ymm2); // ymm1 <- br ai, ai bi
|
||||
ret.v= _mm256_addsub_ps(ymm0,ymm1);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
cvec ymm0,ymm1,ymm2;
|
||||
ymm0 = _mm_shuffle_ps(a.v,a.v,_MM_SHUFFLE(2,2,0,0)); // ymm0 <- ar ar,
|
||||
ymm0 = _mm_mul_ps(ymm0,b.v); // ymm0 <- ar bi, ar br
|
||||
ymm1 = _mm_shuffle_ps(b.v,b.v,_MM_SHUFFLE(2,3,0,1)); // ymm1 <- br,bi
|
||||
ymm2 = _mm_shuffle_ps(a.v,a.v,_MM_SHUFFLE(3,3,1,1)); // ymm2 <- ai,ai
|
||||
ymm1 = _mm_mul_ps(ymm1,ymm2); // ymm1 <- br ai, ai bi
|
||||
ret.v= _mm_addsub_ps(ymm0,ymm1);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
//
|
||||
cvec vzero,ymm0,ymm1,real, imag;
|
||||
vzero = _mm512_setzero();
|
||||
ymm0 = _mm512_swizzle_ps(a.v, _MM_SWIZ_REG_CDAB); //
|
||||
real = _mm512_mask_or_epi32(a.v, 0xAAAA,vzero, ymm0);
|
||||
imag = _mm512_mask_sub_ps(a.v, 0x5555,vzero, ymm0);
|
||||
ymm1 = _mm512_mul_ps(real, b.v);
|
||||
ymm0 = _mm512_swizzle_ps(b.v, _MM_SWIZ_REG_CDAB); // OK
|
||||
ret.v = _mm512_fmadd_ps(ymm0,imag,ymm1);
|
||||
|
||||
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_mul(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// FIXME: gonna remove these load/store, get, set, prefetch
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
friend inline void vset(vComplexF &ret, ComplexF *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_ps(a[3].imag(),a[3].real(),a[2].imag(),a[2].real(),a[1].imag(),a[1].real(),a[0].imag(),a[0].real());
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_ps(a[1].imag(), a[1].real(),a[0].imag(),a[0].real());
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_ps(a[7].imag(),a[7].real(),a[6].imag(),a[6].real(),a[5].imag(),a[5].real(),a[4].imag(),a[4].real(),a[3].imag(),a[3].real(),a[2].imag(),a[2].real(),a[1].imag(),a[1].real(),a[0].imag(),a[0].real());
|
||||
// Note v has a0 a1 a2 a3 a4 a5 a6 a7
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a[0].real(),a[0].imag(),a[1].real(),a[1].imag(),a[2].real(),a[2].imag(),a[3].real(),a[3].imag()};
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// Splat
|
||||
///////////////////////
|
||||
friend inline void vsplat(vComplexF &ret,ComplexF c){
|
||||
float a= real(c);
|
||||
float b= imag(c);
|
||||
vsplat(ret,a,b);
|
||||
}
|
||||
|
||||
friend inline void vstore(const vComplexF &ret, ComplexF *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
_mm256_store_ps((float *)a,ret.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
_mm_store_ps((float *)a,ret.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
_mm512_store_ps((float *)a,ret.v);
|
||||
//Note v has a3 a2 a1 a0
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
friend inline void vprefetch(const vComplexF &v)
|
||||
{
|
||||
_mm_prefetch((const char*)&v.v,_MM_HINT_T0);
|
||||
}
|
||||
|
||||
friend inline void vsplat(vComplexF &ret,float a,float b){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_ps(b,a,b,a,b,a,b,a);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_ps(a,b,a,b);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_ps(b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a,b,a,b};
|
||||
#endif
|
||||
}
|
||||
friend inline ComplexF Reduce(const vComplexF & in)
|
||||
{
|
||||
#ifdef SSE4
|
||||
#error
|
||||
#endif
|
||||
#if defined (AVX1) || defined(AVX2)
|
||||
// FIXME this is inefficient and use
|
||||
__attribute__ ((aligned(32))) float c_[8];
|
||||
_mm256_store_ps(c_,in.v);
|
||||
return ComplexF(c_[0]+c_[2]+c_[4]+c_[6],c_[1]+c_[3]+c_[5]+c_[7]);
|
||||
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
return ComplexF(_mm512_mask_reduce_add_ps(0x5555, in.v),_mm512_mask_reduce_add_ps(0xAAAA, in.v));
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#endif
|
||||
}
|
||||
|
||||
friend inline vComplexF operator * (const ComplexF &a, vComplexF b){
|
||||
vComplexF va;
|
||||
vsplat(va,a);
|
||||
return va*b;
|
||||
}
|
||||
friend inline vComplexF operator * (vComplexF b,const ComplexF &a){
|
||||
return a*b;
|
||||
}
|
||||
|
||||
/*
|
||||
template<class real>
|
||||
friend inline vComplexF operator * (vComplexF b,const real &a){
|
||||
vComplexF va;
|
||||
Complex ca(a,0);
|
||||
vsplat(va,ca);
|
||||
return va*b;
|
||||
}
|
||||
template<class real>
|
||||
friend inline vComplexF operator * (const real &a,vComplexF b){
|
||||
return a*b;
|
||||
}
|
||||
|
||||
friend inline vComplexF operator + (const Complex &a, vComplexF b){
|
||||
vComplexF va;
|
||||
vsplat(va,a);
|
||||
return va+b;
|
||||
}
|
||||
friend inline vComplexF operator + (vComplexF b,const Complex &a){
|
||||
return a+b;
|
||||
}
|
||||
template<class real>
|
||||
friend inline vComplexF operator + (vComplexF b,const real &a){
|
||||
vComplexF va;
|
||||
Complex ca(a,0);
|
||||
vsplat(va,ca);
|
||||
return va+b;
|
||||
}
|
||||
template<class real>
|
||||
friend inline vComplexF operator + (const real &a,vComplexF b){
|
||||
return a+b;
|
||||
}
|
||||
friend inline vComplexF operator - (const Complex &a, vComplexF b){
|
||||
vComplexF va;
|
||||
vsplat(va,a);
|
||||
return va-b;
|
||||
}
|
||||
friend inline vComplexF operator - (vComplexF b,const Complex &a){
|
||||
vComplexF va;
|
||||
vsplat(va,a);
|
||||
return b-va;
|
||||
}
|
||||
template<class real>
|
||||
friend inline vComplexF operator - (vComplexF b,const real &a){
|
||||
vComplexF va;
|
||||
Complex ca(a,0);
|
||||
vsplat(va,ca);
|
||||
return b-va;
|
||||
}
|
||||
template<class real>
|
||||
friend inline vComplexF operator - (const real &a,vComplexF b){
|
||||
vComplexF va;
|
||||
Complex ca(a,0);
|
||||
vsplat(va,ca);
|
||||
return va-b;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
///////////////////////
|
||||
// Conjugate
|
||||
///////////////////////
|
||||
|
||||
friend inline vComplexF conj(const vComplexF &in){
|
||||
vComplexF ret ; vzero(ret);
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
cvec tmp;
|
||||
tmp = _mm256_addsub_ps(ret.v,_mm256_shuffle_ps(in.v,in.v,_MM_SHUFFLE(2,3,0,1))); // ymm1 <- br,bi
|
||||
ret.v=_mm256_shuffle_ps(tmp,tmp,_MM_SHUFFLE(2,3,0,1));
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_addsub_ps(ret.v,in.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_mask_sub_ps(in.v,0xaaaa,ret.v,in.v); // Zero out 0+real 0-imag
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Unary negation
|
||||
friend inline vComplexF operator -(const vComplexF &r) {
|
||||
vComplexF ret;
|
||||
vzero(ret);
|
||||
ret = ret - r;
|
||||
return ret;
|
||||
}
|
||||
// *=,+=,-= operators
|
||||
inline vComplexF &operator *=(const vComplexF &r) {
|
||||
*this = (*this)*r;
|
||||
return *this;
|
||||
}
|
||||
inline vComplexF &operator +=(const vComplexF &r) {
|
||||
*this = *this+r;
|
||||
return *this;
|
||||
}
|
||||
inline vComplexF &operator -=(const vComplexF &r) {
|
||||
*this = *this-r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline void permute(vComplexF &y,vComplexF b,int perm)
|
||||
{
|
||||
Gpermute<vComplexF>(y,b,perm);
|
||||
}
|
||||
friend inline void merge(vComplexF &y,std::vector<ComplexF *> &extracted)
|
||||
{
|
||||
Gmerge<vComplexF,ComplexF >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vComplexF &y,std::vector<ComplexF *> &extracted)
|
||||
{
|
||||
Gextract<vComplexF,ComplexF>(y,extracted);
|
||||
}
|
||||
friend inline void merge(vComplexF &y,std::vector<ComplexF > &extracted)
|
||||
{
|
||||
Gmerge<vComplexF,ComplexF >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vComplexF &y,std::vector<ComplexF > &extracted)
|
||||
{
|
||||
Gextract<vComplexF,ComplexF>(y,extracted);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
inline vComplexF innerProduct(const vComplexF & l, const vComplexF & r)
|
||||
{
|
||||
return conj(l)*r;
|
||||
}
|
||||
|
||||
inline void zeroit(vComplexF &z){ vzero(z);}
|
||||
|
||||
inline vComplexF outerProduct(const vComplexF &l, const vComplexF& r)
|
||||
{
|
||||
return l*r;
|
||||
}
|
||||
inline vComplexF trace(const vComplexF &arg){
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
#endif
|
257
lib/simd/Grid_vInteger.h
Normal file
257
lib/simd/Grid_vInteger.h
Normal file
@ -0,0 +1,257 @@
|
||||
#ifndef GRID_VINTEGER_H
|
||||
#define GRID_VINTEGER_H
|
||||
|
||||
namespace Grid {
|
||||
|
||||
#define _mm256_set_m128i(hi,lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo),(hi),1)
|
||||
// _mm256_set_m128i(hi,lo); // not defined in all versions of immintrin.h
|
||||
|
||||
typedef uint32_t Integer;
|
||||
|
||||
class vInteger {
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
ivec v;
|
||||
|
||||
typedef ivec vector_type;
|
||||
typedef Integer scalar_type;
|
||||
|
||||
vInteger(){};
|
||||
vInteger & operator = (const Zero & z){
|
||||
vzero(*this);
|
||||
return (*this);
|
||||
}
|
||||
vInteger(Integer a){
|
||||
vsplat(*this,a);
|
||||
};
|
||||
////////////////////////////////////
|
||||
// Arithmetic operator overloads +,-,*
|
||||
////////////////////////////////////
|
||||
friend inline vInteger operator + ( vInteger a, vInteger b)
|
||||
{
|
||||
vInteger ret;
|
||||
#if defined (AVX1)
|
||||
__m128i a0,a1;
|
||||
__m128i b0,b1;
|
||||
a0 = _mm256_extractf128_si256(a.v,0);
|
||||
b0 = _mm256_extractf128_si256(b.v,0);
|
||||
a1 = _mm256_extractf128_si256(a.v,1);
|
||||
b1 = _mm256_extractf128_si256(b.v,1);
|
||||
a0 = _mm_add_epi32(a0,b0);
|
||||
a1 = _mm_add_epi32(a1,b1);
|
||||
ret.v = _mm256_set_m128i(a1,a0);
|
||||
#endif
|
||||
#if defined (AVX2)
|
||||
ret.v = _mm256_add_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_add_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_add_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
// Implement as array of ints is only option
|
||||
#error
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vInteger operator - ( vInteger a, vInteger b)
|
||||
{
|
||||
vInteger ret;
|
||||
#if defined (AVX1)
|
||||
__m128i a0,a1;
|
||||
__m128i b0,b1;
|
||||
a0 = _mm256_extractf128_si256(a.v,0);
|
||||
b0 = _mm256_extractf128_si256(b.v,0);
|
||||
a1 = _mm256_extractf128_si256(a.v,1);
|
||||
b1 = _mm256_extractf128_si256(b.v,1);
|
||||
a0 = _mm_sub_epi32(a0,b0);
|
||||
a1 = _mm_sub_epi32(a1,b1);
|
||||
ret.v = _mm256_set_m128i(a1,a0);
|
||||
#endif
|
||||
#if defined (AVX2)
|
||||
ret.v = _mm256_sub_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_sub_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_sub_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
// Implement as array of ints is only option
|
||||
#error
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vInteger operator * ( vInteger a, vInteger b)
|
||||
{
|
||||
vInteger ret;
|
||||
#if defined (AVX1)
|
||||
__m128i a0,a1;
|
||||
__m128i b0,b1;
|
||||
a0 = _mm256_extractf128_si256(a.v,0);
|
||||
b0 = _mm256_extractf128_si256(b.v,0);
|
||||
a1 = _mm256_extractf128_si256(a.v,1);
|
||||
b1 = _mm256_extractf128_si256(b.v,1);
|
||||
a0 = _mm_mul_epi32(a0,b0);
|
||||
a1 = _mm_mul_epi32(a1,b1);
|
||||
ret.v = _mm256_set_m128i(a1,a0);
|
||||
#endif
|
||||
#if defined (AVX2)
|
||||
ret.v = _mm256_mul_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_mul_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_mul_epi32(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
// Implement as array of ints is only option
|
||||
#error
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// mult, sub, add, adj,conj, mac functions
|
||||
///////////////////////////////////////////////
|
||||
friend inline void mult(vInteger * __restrict__ y,const vInteger * __restrict__ l,const vInteger *__restrict__ r) {*y = (*l) * (*r);}
|
||||
friend inline void sub (vInteger * __restrict__ y,const vInteger * __restrict__ l,const vInteger *__restrict__ r) {*y = (*l) - (*r);}
|
||||
friend inline void add (vInteger * __restrict__ y,const vInteger * __restrict__ l,const vInteger *__restrict__ r) {*y = (*l) + (*r);}
|
||||
friend inline void mac (vInteger &y,const vInteger a,const vInteger x){
|
||||
y = a*x+y;
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Initialise to 1,0,i
|
||||
//////////////////////////////////
|
||||
friend inline void vone (vInteger &ret){vsplat(ret,1);}
|
||||
friend inline void vzero(vInteger &ret){vsplat(ret,0);}
|
||||
friend inline void vtrue (vInteger &ret){vsplat(ret,0xFFFFFFFF);}
|
||||
friend inline void vfalse(vInteger &ret){vsplat(ret,0);}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// Broadcast a value across Nsimd copies.
|
||||
/////////////////////////////////////////////////////
|
||||
friend inline void vsplat(vInteger &ret,scalar_type a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set1_epi32(a);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set1_epi32(a);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set1_epi32(a);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#error
|
||||
#endif
|
||||
}
|
||||
friend inline void vset(vInteger &ret,scalar_type *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_epi32(a[7],a[6],a[5],a[4],a[3],a[2],a[1],a[0]);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_epi32(a[0],a[1],a[2],a[3]);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_epi32( a[15],a[14],a[13],a[12],a[11],a[10],a[9],a[8],
|
||||
a[7],a[6],a[5],a[4],a[3],a[2],a[1],a[0]);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#error
|
||||
#endif
|
||||
}
|
||||
|
||||
friend inline void vstore(const vInteger &ret, Integer *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
_mm256_store_si256((__m256i*)a,ret.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
_mm_store_si128((__m128i *)a,ret.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
_mm512_store_si512(a,ret.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
friend inline void vprefetch(const vInteger &v)
|
||||
{
|
||||
_mm_prefetch((const char*)&v.v,_MM_HINT_T0);
|
||||
}
|
||||
|
||||
// Unary negation
|
||||
friend inline vInteger operator -(const vInteger &r) {
|
||||
vInteger ret;
|
||||
vzero(ret);
|
||||
ret = ret - r;
|
||||
return ret;
|
||||
}
|
||||
friend inline Integer Reduce(const vInteger & in)
|
||||
{
|
||||
// unimplemented
|
||||
assert(0);
|
||||
}
|
||||
// *=,+=,-= operators
|
||||
inline vInteger &operator *=(const vInteger &r) {
|
||||
*this = (*this)*r;
|
||||
return *this;
|
||||
}
|
||||
inline vInteger &operator +=(const vInteger &r) {
|
||||
*this = *this+r;
|
||||
return *this;
|
||||
}
|
||||
inline vInteger &operator -=(const vInteger &r) {
|
||||
*this = *this-r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline void permute(vInteger &y,const vInteger b,int perm)
|
||||
{
|
||||
Gpermute<vInteger>(y,b,perm);
|
||||
}
|
||||
friend inline void merge(vInteger &y,std::vector<Integer *> &extracted)
|
||||
{
|
||||
Gmerge<vInteger,Integer>(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vInteger &y,std::vector<Integer *> &extracted)
|
||||
{
|
||||
Gextract<vInteger,Integer>(y,extracted);
|
||||
}
|
||||
friend inline void merge(vInteger &y,std::vector<Integer> &extracted)
|
||||
{
|
||||
Gmerge<vInteger,Integer>(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vInteger &y,std::vector<Integer> &extracted)
|
||||
{
|
||||
Gextract<vInteger,Integer>(y,extracted);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
static inline int Nsimd(void) { return sizeof(ivec)/sizeof(Integer);}
|
||||
};
|
||||
|
||||
inline vInteger localInnerProduct(const vInteger & l, const vInteger & r) { return l*r; }
|
||||
|
||||
inline void zeroit(vInteger &z){ vzero(z);}
|
||||
|
||||
inline vInteger outerProduct(const vInteger &l, const vInteger& r)
|
||||
{
|
||||
return l*r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
257
lib/simd/Grid_vRealD.h
Normal file
257
lib/simd/Grid_vRealD.h
Normal file
@ -0,0 +1,257 @@
|
||||
#ifndef GRID_VREALD_H
|
||||
#define GRID_VREALD_H
|
||||
|
||||
namespace Grid {
|
||||
class vRealD {
|
||||
public:
|
||||
dvec v; // dvec is double precision vector
|
||||
|
||||
public:
|
||||
typedef dvec vector_type;
|
||||
typedef RealD scalar_type;
|
||||
|
||||
vRealD(){};
|
||||
vRealD(RealD a){
|
||||
vsplat(*this,a);
|
||||
};
|
||||
|
||||
friend inline void mult(vRealD * __restrict__ y,const vRealD * __restrict__ l,const vRealD *__restrict__ r) {*y = (*l) * (*r);}
|
||||
friend inline void sub (vRealD * __restrict__ y,const vRealD * __restrict__ l,const vRealD *__restrict__ r) {*y = (*l) - (*r);}
|
||||
friend inline void add (vRealD * __restrict__ y,const vRealD * __restrict__ l,const vRealD *__restrict__ r) {*y = (*l) + (*r);}
|
||||
friend inline vRealD adj(const vRealD &in) { return in; }
|
||||
friend inline vRealD conj(const vRealD &in){ return in; }
|
||||
|
||||
friend inline void mac (vRealD &y,const vRealD a,const vRealD x){
|
||||
#if defined (AVX1) || defined (SSE4)
|
||||
y = a*x+y;
|
||||
#endif
|
||||
#ifdef AVX2 // AVX 2 introduced FMA support. FMA4 eliminates a copy, but AVX only has FMA3
|
||||
// accelerates multiply accumulate, but not general multiply add
|
||||
y.v = _mm256_fmadd_pd(a.v,x.v,y.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
// here precision of vector are still single
|
||||
y.v = _mm512_fmadd_pd(a.v,x.v,y.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
y.v = vec_madd(a.v,x.v,y.v);
|
||||
#endif
|
||||
}
|
||||
//////////////////////////////////
|
||||
// Initialise to 1,0
|
||||
//////////////////////////////////
|
||||
friend inline void vone (vRealD &ret){ vsplat(ret,1.0);}
|
||||
friend inline void vzero(vRealD &ret){ vsplat(ret,0.0);}
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// Arithmetic operator overloads +,-,*
|
||||
////////////////////////////////////
|
||||
friend inline vRealD operator + (vRealD a, vRealD b)
|
||||
{
|
||||
vRealD ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_add_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_add_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_add_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_add(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
friend inline vRealD operator - (vRealD a, vRealD b)
|
||||
{
|
||||
vRealD ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_sub_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_sub_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_sub_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_sub(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vRealD operator * (vRealD a, vRealD b)
|
||||
{
|
||||
vRealD ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_mul_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_mul_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_mul_pd(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = vec_mul(a.v,b.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// General permute; assumes vector length is same across
|
||||
// all subtypes; may not be a good assumption, but could
|
||||
// add the vector width as a template param for BG/Q for example
|
||||
////////////////////////////////////////////////////////////////////
|
||||
friend inline void permute(vRealD &y,vRealD b,int perm)
|
||||
{
|
||||
Gpermute<vRealD>(y,b,perm);
|
||||
}
|
||||
friend inline void merge(vRealD &y,std::vector<RealD *> &extracted)
|
||||
{
|
||||
Gmerge<vRealD,RealD >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vRealD &y,std::vector<RealD *> &extracted)
|
||||
{
|
||||
Gextract<vRealD,RealD>(y,extracted);
|
||||
}
|
||||
friend inline void merge(vRealD &y,std::vector<RealD > &extracted)
|
||||
{
|
||||
Gmerge<vRealD,RealD >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vRealD &y,std::vector<RealD > &extracted)
|
||||
{
|
||||
Gextract<vRealD,RealD>(y,extracted);
|
||||
}
|
||||
|
||||
|
||||
friend inline void vsplat(vRealD &ret,double a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_pd(a,a,a,a);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_pd(a,a);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set1_pd(a);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a,a,a,a};
|
||||
#endif
|
||||
}
|
||||
friend inline void vset(vRealD &ret, double *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_pd(a[3],a[2],a[1],a[0]);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_pd(a[0],a[1]);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_pd(a[7],a[6],a[5],a[4],a[3],a[2],a[1],a[0]);
|
||||
// Note v has a0 a1 a2 a3 a4 a5 a6 a7
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a[0],a[1],a[2],a[3]};
|
||||
#endif
|
||||
}
|
||||
|
||||
friend inline void vstore(const vRealD &ret, double *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
_mm256_store_pd(a,ret.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
_mm_store_pd(a,ret.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
_mm512_store_pd(a,ret.v);
|
||||
// Note v has a7 a6 a5ba4 a3 a2 a1 a0
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
friend inline void vprefetch(const vRealD &v)
|
||||
{
|
||||
_mm_prefetch((const char*)&v.v,_MM_HINT_T0);
|
||||
}
|
||||
// Unary negation
|
||||
friend inline vRealD operator -(const vRealD &r) {
|
||||
vRealD ret;
|
||||
vzero(ret);
|
||||
ret = ret - r;
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend inline RealD Reduce(const vRealD & in)
|
||||
{
|
||||
#if defined (AVX1) || defined(AVX2)
|
||||
typedef union {
|
||||
uint64_t l;
|
||||
double d;
|
||||
} my_conv_t;
|
||||
my_conv_t converter;
|
||||
// more reduce_add
|
||||
/*
|
||||
__attribute__ ((aligned(32))) double c_[16];
|
||||
__m256d tmp = _mm256_permute2f128_pd(in.v,in.v,0x01); // tmp 1032; in= 3210
|
||||
__m256d hadd = _mm256_hadd_pd(in.v,tmp); // hadd = 1+0,3+2,3+2,1+0
|
||||
tmp = _mm256_permute2f128_pd(hadd,hadd,0x01);// tmp = 3+2,1+0,1+0,3+2
|
||||
hadd = _mm256_hadd_pd(tmp,tmp); // tmp = 3+2+1+0,3+2+1+0,1+0+3+2,1+0+3+2
|
||||
_mm256_store_pd(c_,hadd);<3B>
|
||||
return c[0]
|
||||
*/
|
||||
__m256d tmp = _mm256_permute2f128_pd(in.v,in.v,0x01); // tmp 1032; in= 3210
|
||||
__m256d hadd = _mm256_hadd_pd(in.v,tmp); // hadd = 1+0,3+2,3+2,1+0
|
||||
hadd = _mm256_hadd_pd(hadd,hadd); // hadd = 1+0+3+2...
|
||||
converter.l = _mm256_extract_epi64(hadd,0);
|
||||
return converter.d;
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
return _mm512_reduce_add_pd(in.v);
|
||||
/*
|
||||
__attribute__ ((aligned(32))) double c_[8];
|
||||
_mm512_store_pd(c_,in.v);
|
||||
return c_[0]+c_[1]+c_[2]+c_[3]+c_[4]+c_[5]+c_[6]+c_[7];
|
||||
*/
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#endif
|
||||
}
|
||||
|
||||
// *=,+=,-= operators
|
||||
inline vRealD &operator *=(const vRealD &r) {
|
||||
*this = (*this)*r;
|
||||
return *this;
|
||||
}
|
||||
inline vRealD &operator +=(const vRealD &r) {
|
||||
*this = *this+r;
|
||||
return *this;
|
||||
}
|
||||
inline vRealD &operator -=(const vRealD &r) {
|
||||
*this = *this-r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
static int Nsimd(void) { return sizeof(dvec)/sizeof(double);}
|
||||
};
|
||||
|
||||
inline vRealD innerProduct(const vRealD & l, const vRealD & r) { return conj(l)*r; }
|
||||
inline void zeroit(vRealD &z){ vzero(z);}
|
||||
|
||||
inline vRealD outerProduct(const vRealD &l, const vRealD& r)
|
||||
{
|
||||
return l*r;
|
||||
}
|
||||
inline vRealD trace(const vRealD &arg){
|
||||
return arg;
|
||||
}
|
||||
inline vRealD real(const vRealD &arg){
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
278
lib/simd/Grid_vRealF.h
Normal file
278
lib/simd/Grid_vRealF.h
Normal file
@ -0,0 +1,278 @@
|
||||
#ifndef GRID_VREALF_H
|
||||
#define GRID_VREALF_H
|
||||
|
||||
|
||||
namespace Grid {
|
||||
class vRealF {
|
||||
public:
|
||||
fvec v;
|
||||
|
||||
public:
|
||||
|
||||
typedef fvec vector_type;
|
||||
typedef RealF scalar_type;
|
||||
|
||||
vRealF(){};
|
||||
vRealF(RealF a){
|
||||
vsplat(*this,a);
|
||||
};
|
||||
////////////////////////////////////
|
||||
// Arithmetic operator overloads +,-,*
|
||||
////////////////////////////////////
|
||||
friend inline vRealF operator + ( vRealF a, vRealF b)
|
||||
{
|
||||
vRealF ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_add_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_add_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_add_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
vector4double aa,bb,cc;
|
||||
aa = vec_lda(0,(float *)&a);
|
||||
bb = vec_lda(0,(float *)&b);
|
||||
cc = vec_add(aa,bb);
|
||||
vec_sta(cc,0,(float *)&ret.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vRealF operator - ( vRealF a, vRealF b)
|
||||
{
|
||||
vRealF ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_sub_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_sub_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_sub_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
vector4double aa,bb,cc;
|
||||
aa = vec_lda(0,(float *)&a);
|
||||
bb = vec_lda(0,(float *)&b);
|
||||
cc = vec_sub(aa,bb);
|
||||
vec_sta(cc,0,(float *)&ret.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
friend inline vRealF operator * ( vRealF a, vRealF b)
|
||||
{
|
||||
vRealF ret;
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_mul_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_mul_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_mul_ps(a.v,b.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
vector4double aa,bb,cc; // QPX single we are forced to load as this promotes single mem->double regs.
|
||||
aa = vec_lda(0,(float *)&a);
|
||||
bb = vec_lda(0,(float *)&b);
|
||||
cc = vec_mul(aa,bb);
|
||||
vec_sta(cc,0,(float *)&ret.v);
|
||||
#endif
|
||||
return ret;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// mult, sub, add, adj,conj, mac functions
|
||||
///////////////////////////////////////////////
|
||||
friend inline void mult(vRealF * __restrict__ y,const vRealF * __restrict__ l,const vRealF *__restrict__ r) {*y = (*l) * (*r);}
|
||||
friend inline void sub (vRealF * __restrict__ y,const vRealF * __restrict__ l,const vRealF *__restrict__ r) {*y = (*l) - (*r);}
|
||||
friend inline void add (vRealF * __restrict__ y,const vRealF * __restrict__ l,const vRealF *__restrict__ r) {*y = (*l) + (*r);}
|
||||
friend inline vRealF adj(const vRealF &in) { return in; }
|
||||
friend inline vRealF conj(const vRealF &in){ return in; }
|
||||
|
||||
friend inline void mac (vRealF &y,const vRealF a,const vRealF x){
|
||||
#if defined (AVX1) || defined (SSE4)
|
||||
y = a*x+y;
|
||||
#endif
|
||||
#ifdef AVX2 // AVX 2 introduced FMA support. FMA4 eliminates a copy, but AVX only has FMA3
|
||||
// accelerates multiply accumulate, but not general multiply add
|
||||
y.v = _mm256_fmadd_ps(a.v,x.v,y.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
y.v = _mm512_fmadd_ps(a.v,x.v,y.v);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
vector4double aa,xx,yy; // QPX single we are forced to load as this promotes single mem->double regs.
|
||||
aa = vec_lda(0,(float *)&a.v);
|
||||
xx = vec_lda(0,(float *)&x.v);
|
||||
yy = vec_lda(0,(float *)&y.v);
|
||||
yy = vec_madd(aa,xx,yy);
|
||||
vec_sta(yy,0,(float *)&y.v);
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Initialise to 1,0,i
|
||||
//////////////////////////////////
|
||||
friend inline void vone (vRealF &ret){vsplat(ret,1.0);}
|
||||
friend inline void vzero(vRealF &ret){vsplat(ret,0.0);}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// General permute; assumes vector length is same across
|
||||
// all subtypes; may not be a good assumption, but could
|
||||
// add the vector width as a template param for BG/Q for example
|
||||
////////////////////////////////////////////////////////////////////
|
||||
friend inline void permute(vRealF &y,vRealF b,int perm)
|
||||
{
|
||||
Gpermute<vRealF>(y,b,perm);
|
||||
}
|
||||
friend inline void merge(vRealF &y,std::vector<RealF *> &extracted)
|
||||
{
|
||||
Gmerge<vRealF,RealF >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vRealF &y,std::vector<RealF *> &extracted)
|
||||
{
|
||||
Gextract<vRealF,RealF>(y,extracted);
|
||||
}
|
||||
friend inline void merge(vRealF &y,std::vector<RealF> &extracted)
|
||||
{
|
||||
Gmerge<vRealF,RealF >(y,extracted);
|
||||
}
|
||||
friend inline void extract(const vRealF &y,std::vector<RealF> &extracted)
|
||||
{
|
||||
Gextract<vRealF,RealF>(y,extracted);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// Broadcast a value across Nsimd copies.
|
||||
/////////////////////////////////////////////////////
|
||||
friend inline void vsplat(vRealF &ret,float a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_ps(a,a,a,a,a,a,a,a);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_ps(a,a,a,a);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
//ret.v = _mm512_set_ps(a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a);
|
||||
ret.v = _mm512_set1_ps(a);
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a,a,a,a};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
friend inline void vset(vRealF &ret, float *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
ret.v = _mm256_set_ps(a[7],a[6],a[5],a[4],a[3],a[2],a[1],a[0]);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
ret.v = _mm_set_ps(a[0],a[1],a[2],a[3]);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
ret.v = _mm512_set_ps( a[15],a[14],a[13],a[12],a[11],a[10],a[9],a[8],
|
||||
a[7],a[6],a[5],a[4],a[3],a[2],a[1],a[0]);
|
||||
// Note v has a0 a1 a2 a3 a4 a5 a6 a7
|
||||
#endif
|
||||
#ifdef QPX
|
||||
ret.v = {a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]};
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// FIXME: gonna remove these load/store, get, set, prefetch
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
friend inline void vstore(const vRealF &ret, float *a){
|
||||
#if defined (AVX1)|| defined (AVX2)
|
||||
_mm256_store_ps(a,ret.v);
|
||||
#endif
|
||||
#ifdef SSE4
|
||||
_mm_store_ps(a,ret.v);
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
_mm512_store_ps(a,ret.v);
|
||||
// Note v has a7 a6 a5ba4 a3 a2 a1 a0
|
||||
#endif
|
||||
#ifdef QPX
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
friend inline void vprefetch(const vRealF &v)
|
||||
{
|
||||
_mm_prefetch((const char*)&v.v,_MM_HINT_T0);
|
||||
}
|
||||
// Unary negation
|
||||
friend inline vRealF operator -(const vRealF &r) {
|
||||
vRealF ret;
|
||||
vzero(ret);
|
||||
ret = ret - r;
|
||||
return ret;
|
||||
}
|
||||
friend inline RealF Reduce(const vRealF & in)
|
||||
{
|
||||
#if defined (AVX1) || defined(AVX2)
|
||||
__attribute__ ((aligned(32))) float c_[16];
|
||||
__m256 tmp = _mm256_permute2f128_ps(in.v,in.v,0x01);
|
||||
__m256 hadd = _mm256_hadd_ps(in.v,tmp);
|
||||
tmp = _mm256_permute2f128_ps(hadd,hadd,0x01);
|
||||
hadd = _mm256_hadd_ps(tmp,tmp);
|
||||
_mm256_store_ps(c_,hadd);
|
||||
return (float)c_[0];
|
||||
|
||||
#endif
|
||||
#ifdef AVX512
|
||||
return _mm512_reduce_add_ps(in.v);
|
||||
/*
|
||||
__attribute__ ((aligned(64))) float c_[16];
|
||||
_mm512_store_ps(c_,in.v);
|
||||
return c_[0]+c_[1]+c_[2]+c_[3]+c_[4]+c_[5]+c_[6]+c_[7]
|
||||
+c_[8]+c_[9]+c_[10]+c_[11]+c_[12]+c_[13]+c_[14]+c_[15];
|
||||
*/
|
||||
#endif
|
||||
#ifdef QPX
|
||||
#endif
|
||||
}
|
||||
|
||||
// *=,+=,-= operators
|
||||
inline vRealF &operator *=(const vRealF &r) {
|
||||
*this = (*this)*r;
|
||||
return *this;
|
||||
}
|
||||
inline vRealF &operator +=(const vRealF &r) {
|
||||
*this = *this+r;
|
||||
return *this;
|
||||
}
|
||||
inline vRealF &operator -=(const vRealF &r) {
|
||||
*this = *this-r;
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
static inline int Nsimd(void) { return sizeof(fvec)/sizeof(float);}
|
||||
};
|
||||
inline vRealF innerProduct(const vRealF & l, const vRealF & r) { return conj(l)*r; }
|
||||
inline void zeroit(vRealF &z){ vzero(z);}
|
||||
|
||||
inline vRealF outerProduct(const vRealF &l, const vRealF& r)
|
||||
{
|
||||
return l*r;
|
||||
}
|
||||
inline vRealF trace(const vRealF &arg){
|
||||
return arg;
|
||||
}
|
||||
inline vRealF real(const vRealF &arg){
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user