mirror of
				https://github.com/paboyle/Grid.git
				synced 2025-11-03 21:44:33 +00:00 
			
		
		
		
	Improving the reduction to go through our on permute.
Must also do this for avx512
This commit is contained in:
		@@ -14,7 +14,23 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace Optimization {
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  template<class vtype>
 | 
			
		||||
  union uconv {
 | 
			
		||||
    __m256 f;
 | 
			
		||||
    vtype v;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  union u256f {
 | 
			
		||||
    __m256 v;
 | 
			
		||||
    float f[8];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  union u256d {
 | 
			
		||||
    __m256d v;
 | 
			
		||||
    double f[4];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct Vsplat{
 | 
			
		||||
    //Complex float
 | 
			
		||||
    inline __m256 operator()(float a, float b){
 | 
			
		||||
@@ -54,7 +70,6 @@ namespace Optimization {
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct Vstream{
 | 
			
		||||
    //Float
 | 
			
		||||
    inline void operator()(float * a, __m256 b){
 | 
			
		||||
@@ -68,8 +83,6 @@ namespace Optimization {
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct Vset{
 | 
			
		||||
    // Complex float 
 | 
			
		||||
    inline __m256 operator()(Grid::ComplexF *a){
 | 
			
		||||
@@ -92,7 +105,6 @@ namespace Optimization {
 | 
			
		||||
      return _mm256_set_epi32(a[7],a[6],a[5],a[4],a[3],a[2],a[1],a[0]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  template <typename Out_type, typename In_type>
 | 
			
		||||
@@ -106,9 +118,6 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
  /////////////////////////////////////////////////////
 | 
			
		||||
  // Arithmetic operations
 | 
			
		||||
  /////////////////////////////////////////////////////
 | 
			
		||||
@@ -170,7 +179,6 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct MultComplex{
 | 
			
		||||
    // Complex float
 | 
			
		||||
    inline __m256 operator()(__m256 a, __m256 b){
 | 
			
		||||
@@ -207,7 +215,6 @@ namespace Optimization {
 | 
			
		||||
	IF IMM0[3] = 0
 | 
			
		||||
	THEN DEST[255:192]=SRC2[191:128] ELSE DEST[255:192]=SRC2[255:192] FI; // Ox5 r<->i   ; 0xC unchanged
 | 
			
		||||
      */
 | 
			
		||||
      
 | 
			
		||||
      __m256d ymm0,ymm1,ymm2;
 | 
			
		||||
      ymm0 = _mm256_shuffle_pd(a,a,0x0); // ymm0 <- ar ar, ar,ar b'00,00
 | 
			
		||||
      ymm0 = _mm256_mul_pd(ymm0,b);      // ymm0 <- ar bi, ar br
 | 
			
		||||
@@ -247,7 +254,6 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct Conj{
 | 
			
		||||
    // Complex single
 | 
			
		||||
    inline __m256 operator()(__m256 in){
 | 
			
		||||
@@ -292,18 +298,13 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  //////////////////////////////////////////////
 | 
			
		||||
  // Some Template specialization
 | 
			
		||||
  //////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
  template < typename vtype > 
 | 
			
		||||
    void permute(vtype &a, vtype &b, int perm) {
 | 
			
		||||
    union { 
 | 
			
		||||
      __m256 f;
 | 
			
		||||
      vtype v;
 | 
			
		||||
    } conv;
 | 
			
		||||
    void permute(vtype &a,vtype b, int perm) {
 | 
			
		||||
    uconv<vtype> conv;
 | 
			
		||||
    conv.v = b;
 | 
			
		||||
    switch (perm){
 | 
			
		||||
      // 8x32 bits=>3 permutes
 | 
			
		||||
@@ -313,24 +314,20 @@ namespace Optimization {
 | 
			
		||||
    default: assert(0); break;
 | 
			
		||||
    }
 | 
			
		||||
    a = conv.v;
 | 
			
		||||
    
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  //Complex float Reduce
 | 
			
		||||
  template<>
 | 
			
		||||
    inline Grid::ComplexF Reduce<Grid::ComplexF, __m256>::operator()(__m256 in){
 | 
			
		||||
    __m256 v1,v2;
 | 
			
		||||
    union { 
 | 
			
		||||
      __m256 v;
 | 
			
		||||
      float f[8];
 | 
			
		||||
    } conv;
 | 
			
		||||
    Optimization::permute(v1,in,0); // sse 128; paired complex single
 | 
			
		||||
    v1 = _mm256_add_ps(v1,in);
 | 
			
		||||
    Optimization::permute(v2,v1,1); // avx 256; quad complex single
 | 
			
		||||
    v1 = _mm256_add_ps(v1,v2);
 | 
			
		||||
    conv.v = v1;
 | 
			
		||||
    u256f conv; conv.v = v1;
 | 
			
		||||
    return Grid::ComplexF(conv.f[0],conv.f[1]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //Real float Reduce
 | 
			
		||||
  template<>
 | 
			
		||||
  inline Grid::RealF Reduce<Grid::RealF, __m256>::operator()(__m256 in){
 | 
			
		||||
@@ -341,7 +338,8 @@ namespace Optimization {
 | 
			
		||||
    v1 = _mm256_add_ps(v1,v2);
 | 
			
		||||
    Optimization::permute(v2,v1,2); 
 | 
			
		||||
    v1 = _mm256_add_ps(v1,v2);
 | 
			
		||||
    return v1[0];
 | 
			
		||||
    u256f conv; conv.v=v1;
 | 
			
		||||
    return conv.f[0];
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
@@ -351,7 +349,8 @@ namespace Optimization {
 | 
			
		||||
    __m256d v1;
 | 
			
		||||
    Optimization::permute(v1,in,0); // sse 128; paired complex single
 | 
			
		||||
    v1 = _mm256_add_pd(v1,in);
 | 
			
		||||
    return Grid::ComplexD(v1[0],v1[1]);
 | 
			
		||||
    u256d conv; conv.v = v1;
 | 
			
		||||
    return Grid::ComplexD(conv.f[0],conv.f[1]);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  //Real double Reduce
 | 
			
		||||
@@ -362,7 +361,8 @@ namespace Optimization {
 | 
			
		||||
    v1 = _mm256_add_pd(v1,in);
 | 
			
		||||
    Optimization::permute(v2,v1,1); 
 | 
			
		||||
    v1 = _mm256_add_pd(v1,v2);
 | 
			
		||||
    return v1[0];
 | 
			
		||||
    u256d conv; conv.v = v1;
 | 
			
		||||
    return conv.f[0];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //Integer Reduce
 | 
			
		||||
@@ -390,22 +390,9 @@ namespace Grid {
 | 
			
		||||
      _mm_prefetch(ptr+i+512,_MM_HINT_T0);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  template < typename VectorSIMD > 
 | 
			
		||||
    inline void Gpermute(VectorSIMD &y,const VectorSIMD &b, int perm ) {
 | 
			
		||||
    union { 
 | 
			
		||||
      __m256 f;
 | 
			
		||||
      decltype(VectorSIMD::v) v;
 | 
			
		||||
    } conv;
 | 
			
		||||
    conv.v = b.v;
 | 
			
		||||
    switch(perm){
 | 
			
		||||
    case 3: break; //empty for AVX1/2
 | 
			
		||||
    case 2: conv.f = _mm256_shuffle_ps(conv.f,conv.f,_MM_SHUFFLE(2,3,0,1)); break;
 | 
			
		||||
    case 1: conv.f = _mm256_shuffle_ps(conv.f,conv.f,_MM_SHUFFLE(1,0,3,2));  break; 
 | 
			
		||||
    case 0: conv.f = _mm256_permute2f128_ps(conv.f,conv.f,0x01); break;
 | 
			
		||||
    default: assert(0); break;
 | 
			
		||||
    }
 | 
			
		||||
    y.v=conv.v;
 | 
			
		||||
    Optimization::permute(y.v,b.v,perm);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Function name aliases
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,21 @@
 | 
			
		||||
#include <pmmintrin.h>
 | 
			
		||||
 | 
			
		||||
namespace Optimization {
 | 
			
		||||
 | 
			
		||||
  template<class vtype>
 | 
			
		||||
  union uconv {
 | 
			
		||||
    __m128 f;
 | 
			
		||||
    vtype v;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  union u128f {
 | 
			
		||||
    __m128 v;
 | 
			
		||||
    float f[4];
 | 
			
		||||
  };
 | 
			
		||||
  union u128d {
 | 
			
		||||
    __m128d v;
 | 
			
		||||
    double f[2];
 | 
			
		||||
  };
 | 
			
		||||
  
 | 
			
		||||
  struct Vsplat{
 | 
			
		||||
    //Complex float
 | 
			
		||||
@@ -50,7 +65,6 @@ namespace Optimization {
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct Vstream{
 | 
			
		||||
    //Float
 | 
			
		||||
    inline void operator()(float * a, __m128 b){
 | 
			
		||||
@@ -64,8 +78,6 @@ namespace Optimization {
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct Vset{
 | 
			
		||||
    // Complex float 
 | 
			
		||||
    inline __m128 operator()(Grid::ComplexF *a){
 | 
			
		||||
@@ -102,9 +114,6 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
  /////////////////////////////////////////////////////
 | 
			
		||||
  // Arithmetic operations
 | 
			
		||||
  /////////////////////////////////////////////////////
 | 
			
		||||
@@ -138,7 +147,6 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct MultComplex{
 | 
			
		||||
    // Complex float
 | 
			
		||||
    inline __m128 operator()(__m128 a, __m128 b){
 | 
			
		||||
@@ -177,7 +185,6 @@ namespace Optimization {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  struct Conj{
 | 
			
		||||
    // Complex single
 | 
			
		||||
    inline __m128 operator()(__m128 in){
 | 
			
		||||
@@ -216,57 +223,61 @@ namespace Optimization {
 | 
			
		||||
      __m128d tmp = _mm_shuffle_pd(in,in,0x1);
 | 
			
		||||
      return _mm_addsub_pd(_mm_setzero_pd(),tmp); // r,-i
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  //////////////////////////////////////////////
 | 
			
		||||
  // Some Template specialization
 | 
			
		||||
  
 | 
			
		||||
  template < typename vtype > 
 | 
			
		||||
    void permute(vtype &a, vtype b, int perm) {
 | 
			
		||||
    uconv<vtype> conv; 
 | 
			
		||||
    conv.v = b;
 | 
			
		||||
    switch(perm){
 | 
			
		||||
    case 3: break; //empty for SSE4
 | 
			
		||||
    case 2: break; //empty for SSE4
 | 
			
		||||
    case 1: conv.f = _mm_shuffle_ps(conv.f,conv.f,_MM_SHUFFLE(2,3,0,1)); break;
 | 
			
		||||
    case 0: conv.f = _mm_shuffle_ps(conv.f,conv.f,_MM_SHUFFLE(1,0,3,2)); break;
 | 
			
		||||
    default: assert(0); break;
 | 
			
		||||
    }
 | 
			
		||||
    a=conv.v;
 | 
			
		||||
  }; 
 | 
			
		||||
 | 
			
		||||
  //Complex float Reduce
 | 
			
		||||
  template<>
 | 
			
		||||
  inline Grid::ComplexF Reduce<Grid::ComplexF, __m128>::operator()(__m128 in){
 | 
			
		||||
    union {
 | 
			
		||||
      __m128 v1;  
 | 
			
		||||
      float f[4]; 
 | 
			
		||||
    } u128;
 | 
			
		||||
    u128.v1 = _mm_add_ps(in, _mm_shuffle_ps(in,in, 0b01001110)); // FIXME Prefer to use _MM_SHUFFLE macros
 | 
			
		||||
    return Grid::ComplexF(u128.f[0], u128.f[1]);   
 | 
			
		||||
    __m128 v1; // two complex
 | 
			
		||||
    Optimization::permute(v1,in,0); 
 | 
			
		||||
    v1= _mm_add_ps(v1,in);
 | 
			
		||||
    u128f conv;    conv.v=v1;
 | 
			
		||||
    return Grid::ComplexF(conv.f[0],conv.f[1]);
 | 
			
		||||
  }
 | 
			
		||||
  //Real float Reduce
 | 
			
		||||
  template<>
 | 
			
		||||
  inline Grid::RealF Reduce<Grid::RealF, __m128>::operator()(__m128 in){
 | 
			
		||||
    // FIXME Hack
 | 
			
		||||
    const Grid::RealF * ptr = (const Grid::RealF *) ∈
 | 
			
		||||
    Grid::RealF ret = 0; 
 | 
			
		||||
    for(int i=0;i< 4 ;i++){ // 4 number of simd lanes for float
 | 
			
		||||
      ret = ret+ptr[i];
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
    __m128 v1,v2; // quad single
 | 
			
		||||
    Optimization::permute(v1,in,0); 
 | 
			
		||||
    v1= _mm_add_ps(v1,in);
 | 
			
		||||
    Optimization::permute(v2,v1,1); 
 | 
			
		||||
    v1 = _mm_add_ps(v1,v2);
 | 
			
		||||
    u128f conv; conv.v=v1;
 | 
			
		||||
    return conv.f[0];
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
  //Complex double Reduce
 | 
			
		||||
  template<>
 | 
			
		||||
  inline Grid::ComplexD Reduce<Grid::ComplexD, __m128d>::operator()(__m128d in){
 | 
			
		||||
    printf("Reduce : Missing good complex double implementation -> FIX\n");
 | 
			
		||||
    return Grid::ComplexD(in[0], in[1]); // inefficient
 | 
			
		||||
    u128d conv; conv.v = in;
 | 
			
		||||
    return Grid::ComplexD(conv.f[0],conv.f[1]);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  //Real double Reduce
 | 
			
		||||
  template<>
 | 
			
		||||
  inline Grid::RealD Reduce<Grid::RealD, __m128d>::operator()(__m128d in){
 | 
			
		||||
    // FIXME Hack
 | 
			
		||||
    const Grid::RealD * ptr =(const Grid::RealD *)  ∈
 | 
			
		||||
    Grid::RealD ret = 0; 
 | 
			
		||||
    for(int i=0;i< 2 ;i++){// 2 number of simd lanes for float
 | 
			
		||||
      ret = ret+ptr[i];
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
    __m128d v1;
 | 
			
		||||
    Optimization::permute(v1,in,0); // avx 256; quad double
 | 
			
		||||
    v1 = _mm_add_pd(v1,in);
 | 
			
		||||
    u128d conv; conv.v = v1;
 | 
			
		||||
    return conv.f[0];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //Integer Reduce
 | 
			
		||||
@@ -276,12 +287,6 @@ namespace Optimization {
 | 
			
		||||
   printf("Reduce : Missing integer implementation -> FIX\n");
 | 
			
		||||
    assert(0);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@@ -292,27 +297,13 @@ namespace Grid {
 | 
			
		||||
  typedef __m128d SIMD_Dtype; // Double precision type
 | 
			
		||||
  typedef __m128i SIMD_Itype; // Integer type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  inline void v_prefetch0(int size, const char *ptr){};  // prefetch utilities
 | 
			
		||||
 | 
			
		||||
  // Gpermute function
 | 
			
		||||
  template < typename VectorSIMD > 
 | 
			
		||||
    inline void Gpermute(VectorSIMD &y,const VectorSIMD &b, int perm ) {
 | 
			
		||||
    union { 
 | 
			
		||||
      __m128 f;
 | 
			
		||||
      decltype(VectorSIMD::v) v;
 | 
			
		||||
    } conv;
 | 
			
		||||
    conv.v = b.v;
 | 
			
		||||
    switch(perm){
 | 
			
		||||
    case 3: break; //empty for SSE4
 | 
			
		||||
    case 2: break; //empty for SSE4
 | 
			
		||||
    case 1: conv.f = _mm_shuffle_ps(conv.f,conv.f,_MM_SHUFFLE(2,3,0,1)); break;
 | 
			
		||||
    case 0: conv.f = _mm_shuffle_ps(conv.f,conv.f,_MM_SHUFFLE(1,0,3,2)); break;
 | 
			
		||||
    default: assert(0); break;
 | 
			
		||||
    }
 | 
			
		||||
    y.v=conv.v;
 | 
			
		||||
  }; 
 | 
			
		||||
  
 | 
			
		||||
    Optimization::permute(y.v,b.v,perm);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // Function name aliases
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user