Bladeren bron

merge Libin's upgrade for AVX512

Dhairya Malhotra 5 jaren geleden
bovenliggende
commit
8cee070602
1 gewijzigde bestanden met toevoegingen van 460 en 27 verwijderingen
  1. 460 27
      include/sctl/vec.hpp

+ 460 - 27
include/sctl/vec.hpp

@@ -25,28 +25,79 @@
 #include <immintrin.h>
 #endif
 
+// TODO: Implement AVX versions of floats, int32_t, int64_t
+
 // TODO: Check alignment when SCTL_MEMDEBUG is defined
 // TODO: Replace pointers with iterators
 
 namespace SCTL_NAMESPACE {
 
+  enum class DataType {
+    Integer,
+    Real,
+    Bool
+  };
+
   template <class ValueType> class TypeTraits {
     public:
-      static constexpr Integer SigBits = 0;
+      static constexpr DataType Type = DataType::Bool;
+      static constexpr Integer Size = sizeof(ValueType);
+      static constexpr Integer SigBits = 1;
+  };
+  template <> class TypeTraits<int32_t> {
+    public:
+      static constexpr DataType Type = DataType::Integer;
+      static constexpr Integer Size = sizeof(int32_t);
+      static constexpr Integer SigBits = Size * 8;
+  };
+  template <> class TypeTraits<int64_t> {
+    public:
+      static constexpr DataType Type = DataType::Integer;
+      static constexpr Integer Size = sizeof(int64_t);
+      static constexpr Integer SigBits = Size * 8;
   };
   template <> class TypeTraits<float> {
     public:
+      static constexpr DataType Type = DataType::Real;
+      static constexpr Integer Size = sizeof(float);
       static constexpr Integer SigBits = 23;
   };
   template <> class TypeTraits<double> {
     public:
+      static constexpr DataType Type = DataType::Real;
+      static constexpr Integer Size = sizeof(double);
       static constexpr Integer SigBits = 52;
   };
 
+  template <DataType type, Integer size> class GetType {
+    public:
+      typedef bool ValueType;
+  };
+  template <> class GetType<DataType::Integer,4> {
+    public:
+      typedef int32_t ValueType;
+  };
+  template <> class GetType<DataType::Integer,8> {
+    public:
+      typedef int64_t ValueType;
+  };
+  template <> class GetType<DataType::Real,4> {
+    public:
+      typedef float ValueType;
+  };
+  template <> class GetType<DataType::Real,8> {
+    public:
+      typedef double ValueType;
+  };
 
   template <class ValueType, Integer N> class alignas(sizeof(ValueType) * N) Vec {
+
     public:
 
+      typedef typename GetType<DataType::Integer,TypeTraits<ValueType>::Size>::ValueType IntegerType;
+      typedef typename GetType<DataType::Real,TypeTraits<ValueType>::Size>::ValueType RealType;
+      typedef Vec<IntegerType,N> IntegerVec;
+      typedef Vec<RealType,N> RealVec;
       typedef ValueType ScalarType;
 
       static constexpr Integer Size() {
@@ -75,7 +126,7 @@ namespace SCTL_NAMESPACE {
         return r;
       }
 
-      Vec() {}
+      Vec() = default;
 
       Vec(const ValueType& a) {
         for (Integer i = 0; i < N; i++) v[i] = a;
@@ -108,11 +159,11 @@ namespace SCTL_NAMESPACE {
       }
 
       // C-style cast
-      template <class RetValueType> explicit operator Vec<RetValueType,N>() const {
-        Vec<RetValueType,N> r;
-        for (Integer i = 0; i < N; i++) r.v[i] = (RetValueType)v[i];
-        return r;
-      }
+      //template <class RetValueType> explicit operator Vec<RetValueType,N>() const {
+      //  Vec<RetValueType,N> r;
+      //  for (Integer i = 0; i < N; i++) r.v[i] = (RetValueType)v[i];
+      //  return r;
+      //}
 
       // Arithmetic operators
       friend Vec operator*(Vec lhs, const Vec& rhs) {
@@ -193,6 +244,13 @@ namespace SCTL_NAMESPACE {
         return lhs & (~rhs);
       }
 
+      // Bitshift
+      friend IntegerVec operator<<(const Vec& lhs, const Integer& rhs) {
+        IntegerVec r = IntegerVec::LoadAligned(&lhs.v[0]);
+        for (Integer i = 0; i < N; i++) r.v[i] = r.v[i] << rhs;
+        return r;
+      }
+
       // Assignment operators
       Vec& operator+=(const Vec& rhs) {
         for (Integer i = 0; i < N; i++) v[i] += rhs.v[i];
@@ -225,6 +283,9 @@ namespace SCTL_NAMESPACE {
         return *this;
       }
 
+      // Conversion operators
+      // /
+
       // Other operators
       friend Vec max(Vec lhs, const Vec& rhs) {
         for (Integer i = 0; i < N; i++) {
@@ -251,6 +312,8 @@ namespace SCTL_NAMESPACE {
         return r;
       }
 
+      template <class Vec1, class Vec2> friend Vec1 reinterpret(const Vec2& x);
+
     private:
 
       static const ValueType const_zero() {
@@ -274,6 +337,11 @@ namespace SCTL_NAMESPACE {
   };
 
   // Other operators
+  template <class RetVec, class Vec> RetVec reinterpret(const Vec& v){
+    static_assert(sizeof(RetVec) == sizeof(Vec));
+    RetVec& r = *(RetVec*)&v;
+    return r;
+  }
   template <class RealVec, class IntVec> RealVec ConvertInt2Real(const IntVec& x) {
     typedef typename RealVec::ScalarType Real;
     typedef typename IntVec::ScalarType Int;
@@ -287,18 +355,20 @@ namespace SCTL_NAMESPACE {
     IntVec l(x + IntVec(Cint));
     return *(RealVec*)&l - RealVec(Creal);
   }
-  template <class IntVec, class RealVec> IntVec RoundReal2Int(const RealVec& x) {
-    typedef typename RealVec::ScalarType Real;
-    typedef typename IntVec::ScalarType Int;
-    assert(sizeof(RealVec) == sizeof(IntVec));
-    assert(sizeof(Real) == sizeof(Int));
-    static constexpr Integer SigBits = TypeTraits<Real>::SigBits;
+  template <class Vec> typename Vec::IntegerVec RoundReal2Int(const Vec& x) {
+    using IntegerType = typename Vec::IntegerType;
+    using RealType = typename Vec::RealType;
+    using IntegerVec = typename Vec::IntegerVec;
+    using RealVec = typename Vec::RealVec;
+    static_assert(std::is_same<RealVec,Vec>::value, "RoundReal2Int: expected real input argument!");
+
+    static constexpr Integer SigBits = TypeTraits<RealType>::SigBits;
     union {
-      Int Cint = (1UL << (SigBits - 1)) + ((SigBits + ((1UL<<(sizeof(Real)*8 - SigBits - 2))-1)) << SigBits);
-      Real Creal;
+      IntegerType Cint = (1UL << (SigBits - 1)) + ((SigBits + ((1UL<<(sizeof(RealType)*8 - SigBits - 2))-1)) << SigBits);
+      RealType Creal;
     };
-    RealVec d(x + RealVec(Creal));
-    return *(IntVec*)&d - IntVec(Cint);
+    RealVec d = x + RealVec(Creal);
+    return reinterpret<IntegerVec>(d) - IntegerVec(Cint);
   }
   template <class Vec> Vec RoundReal2Real(const Vec& x) {
     typedef typename Vec::ScalarType Real;
@@ -408,8 +478,8 @@ namespace SCTL_NAMESPACE {
       Real real_two;
     };
     Vec x_offset(real_zero);
-    Vec xAnd1 = (((x_+x_offset) & Vec(real_one)) == x_offset);
-    Vec xAnd2 = (((x_+x_offset) & Vec(real_two)) == x_offset);
+    auto xAnd1 = (((x_+x_offset) & Vec(real_one)) == x_offset);
+    auto xAnd2 = (((x_+x_offset) & Vec(real_two)) == x_offset);
 
     Vec s2 = AndNot( c1,xAnd1) | (s1 & xAnd1);
     Vec c2 = AndNot(-s1,xAnd1) | (c1 & xAnd1);
@@ -419,6 +489,95 @@ namespace SCTL_NAMESPACE {
     sinx = s3;
     cosx = c3;
   }
+  template <class Vec> void exp_intrin(Vec& expx, const Vec& x) {
+    constexpr Integer ORDER = 10;
+    using IntegerType = typename Vec::IntegerType;
+    using RealType = typename Vec::RealType;
+    using IntegerVec = typename Vec::IntegerVec;
+    using RealVec = typename Vec::RealVec;
+    static_assert(std::is_same<Vec,RealVec>::value, "exp_intrin: expected a real argument");
+
+    using Real = typename RealVec::ScalarType;
+    static constexpr Integer SigBits = TypeTraits<Real>::SigBits;
+    static constexpr Real coeff2  = 1/(((Real)2));
+    static constexpr Real coeff3  = 1/(((Real)2)*3);
+    static constexpr Real coeff4  = 1/(((Real)2)*3*4);
+    static constexpr Real coeff5  = 1/(((Real)2)*3*4*5);
+    static constexpr Real coeff6  = 1/(((Real)2)*3*4*5*6);
+    static constexpr Real coeff7  = 1/(((Real)2)*3*4*5*6*7);
+    static constexpr Real coeff8  = 1/(((Real)2)*3*4*5*6*7*8);
+    static constexpr Real coeff9  = 1/(((Real)2)*3*4*5*6*7*8*9);
+    static constexpr Real coeff10 = 1/(((Real)2)*3*4*5*6*7*8*9*10);
+    static constexpr Real x0 = (Real)0.693147180559945309417232121458l; // ln(2)
+    static constexpr Real invx0 = 1 / x0;
+
+    RealVec x_ = RoundReal2Real(x * invx0); // 4.5 - cycles
+    IntegerVec int_x_ = RoundReal2Int<RealVec>(x_);
+    RealVec x1 = x - x_ * x0; // 2 - cycles
+    RealVec x2, x3, x4, x5, x6, x7, x8, x9, x10;
+
+    RealVec e1 = 1.0 + x1;
+    if (ORDER >= 2) {
+      x2 = x1 * x1;
+      e1 += x2 * coeff2;
+    }
+    if (ORDER >= 3) {
+      x3 = x2 * x1;
+      e1 += x3 * coeff3;
+    }
+    if (ORDER >= 4) {
+      x4 = x2 * x2;
+      e1 += x4 * coeff4;
+    }
+    if (ORDER >= 5) {
+      x5 = x3 * x2;
+      e1 += x5 * coeff5;
+    }
+    if (ORDER >= 6) {
+      x6 = x3 * x3;
+      e1 += x6 * coeff6;
+    }
+    if (ORDER >= 7) {
+      x7 = x4 * x3;
+      e1 += x7 * coeff7;
+    }
+    if (ORDER >= 8) {
+      x8 = x4 * x4;
+      e1 += x8 * coeff8;
+    }
+    if (ORDER >= 9) {
+      x9 = x5 * x4;
+      e1 += x9 * coeff9;
+    }
+    if (ORDER >= 10) {
+      x10 = x5 * x5;
+      e1 += x10 * coeff10;
+    }
+
+    RealVec e2;
+    { // set e2 = 2 ^ x_
+      union {
+        RealType real_one = 1.0;
+        IntegerType int_one;
+      };
+      //__m256i int_e2 = _mm256_add_epi64(
+      //                                  _mm256_set1_epi64x(int_one),
+      //                                  _mm256_slli_epi64(
+      //                                                      _mm256_load_si256((__m256i const*)&int_x_),
+      //                                                      SigBits
+      //                                                    )
+      //                                  ); // int_e2 = int_one + (int_x_ << SigBits);
+      IntegerVec int_e2 = IntegerVec(int_one) + (int_x_ << SigBits);
+
+      // Handle underflow
+      static constexpr IntegerType max_exp = -(IntegerType)(1UL<<((sizeof(Real)*8-SigBits-2)));
+      int_e2 &= (int_x_ > IntegerVec(max_exp));
+
+      e2 = RealVec::LoadAligned((RealType*)&int_e2);
+    }
+
+    expx = e1 * e2;
+  }
 
 #ifdef __AVX__
   template <> class alignas(sizeof(double)*4) Vec<double,4> {
@@ -427,6 +586,10 @@ namespace SCTL_NAMESPACE {
     static constexpr Integer N = 4;
     public:
 
+      typedef typename GetType<DataType::Integer,TypeTraits<ValueType>::Size>::ValueType IntegerType;
+      typedef typename GetType<DataType::Real,TypeTraits<ValueType>::Size>::ValueType RealType;
+      typedef Vec<IntegerType,N> IntegerVec;
+      typedef Vec<RealType,N> RealVec;
       typedef ValueType ScalarType;
 
       static constexpr Integer Size() {
@@ -455,7 +618,7 @@ namespace SCTL_NAMESPACE {
         return r;
       }
 
-      Vec() {}
+      Vec() = default;
 
       Vec(const ValueType& a) {
         v = _mm256_set1_pd(a);
@@ -485,12 +648,8 @@ namespace SCTL_NAMESPACE {
       }
 
       // C-style cast
-      template <class RetValueType> explicit operator Vec<RetValueType,N>() const {
-        Vec<RetValueType,N> r;
-        VecType& ret_v = *(VecType*)&r.v;
-        ret_v = v;
-        return r;
-      }
+      //template <class RetValueType> explicit operator Vec<RetValueType,N>() const {
+      //}
 
       // Arithmetic operators
       friend Vec operator*(Vec lhs, const Vec& rhs) {
@@ -534,7 +693,6 @@ namespace SCTL_NAMESPACE {
       friend Vec operator==(Vec lhs, const Vec& rhs) {
         lhs.v = _mm256_cmp_pd(lhs.v, rhs.v, _CMP_EQ_OS);
         return lhs;
-        return lhs;
       }
       friend Vec operator!=(Vec lhs, const Vec& rhs) {
         lhs.v = _mm256_cmp_pd(lhs.v, rhs.v, _CMP_NEQ_OS);
@@ -610,14 +768,25 @@ namespace SCTL_NAMESPACE {
         return r;
       }
 
+      template <class Vec1, class Vec2> friend Vec1 reinterpret(const Vec2& x);
       template <class Vec> friend Vec RoundReal2Real(const Vec& x);
       template <class Vec> friend void sincos_intrin(Vec& sinx, Vec& cosx, const Vec& x);
+      template <class Vec> friend void exp_intrin(Vec& expx, const Vec& x);
 
     private:
 
       VecType v;
   };
 
+  template <> inline Vec<int64_t,4> reinterpret<Vec<int64_t,4>,Vec<double,4>>(const Vec<double,4>& x){
+    union {
+      Vec<int64_t,4> r;
+      __m256i y;
+    };
+    y = _mm256_castpd_si256(x.v);
+    return r;
+  }
+
   template <> inline Vec<double,4> RoundReal2Real(const Vec<double,4>& x) {
     Vec<double,4> r;
     r.v = _mm256_round_pd(x.v,_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC);
@@ -629,6 +798,270 @@ namespace SCTL_NAMESPACE {
     sinx.v = _mm256_sin_pd(x.v);
     cosx.v = _mm256_cos_pd(x.v);
   }
+
+  template <> inline void exp_intrin(Vec<double,4>& expx, const Vec<double,4>& x) {
+    expx.v = _mm256_exp_pd(x.v);
+  }
+  #endif
+
+#endif
+
+#ifdef __AVX512F__
+  template <> class alignas(sizeof(double)*8) Vec<double,8> {
+    typedef __m512d VecType;
+    typedef double ValueType;
+    static constexpr Integer N = 8;
+    public:
+
+      typedef typename GetType<DataType::Integer,TypeTraits<ValueType>::Size>::ValueType IntegerType;
+      typedef typename GetType<DataType::Real,TypeTraits<ValueType>::Size>::ValueType RealType;
+      typedef Vec<IntegerType,N> IntegerVec;
+      typedef Vec<RealType,N> RealVec;
+      typedef ValueType ScalarType;
+
+      static constexpr Integer Size() {
+        return N;
+      }
+
+      static Vec Zero() {
+        Vec r;
+        r.v = _mm512_setzero_pd();
+        return r;
+      }
+
+      static Vec Load1(ValueType const* p) {
+        Vec r;
+        // TODO: different from _m256d, could make it faster?
+        // r.v = _mm512_broadcast_f64x4(_mm256_broadcast_sd(p));
+        r.v = _mm512_set1_pd(*p);
+        return r;
+      }
+      static Vec Load(ValueType const* p) {
+        Vec r;
+        r.v = _mm512_loadu_pd(p);
+        return r;
+      }
+      static Vec LoadAligned(ValueType const* p) {
+        Vec r;
+        r.v = _mm512_load_pd(p);
+        return r;
+      }
+
+      Vec() = default;
+
+      Vec(const ValueType& a) {
+        v = _mm512_set1_pd(a);
+      }
+
+      Vec(const __mmask8& a) = delete; // disallow implicit conversions
+
+      void Store(ValueType* p) const {
+        _mm512_storeu_pd(p, v);
+      }
+      void StoreAligned(ValueType* p) const {
+        _mm512_store_pd(p, v);
+      }
+
+      // Bitwise NOT
+      Vec operator~() const {
+        Vec r;
+        static constexpr ScalarType Creal = -1.0;
+        r.v = _mm512_xor_pd(v, _mm512_set1_pd(Creal));
+        return r;
+      }
+
+      // Unary plus and minus
+      Vec operator+() const {
+        return *this;
+      }
+      Vec operator-() const {
+        return Zero() - (*this);
+      }
+
+      // C-style cast
+      //template <class RetValueType> explicit operator Vec<RetValueType,N>() const {
+      //}
+
+      // Arithmetic operators
+      friend Vec operator*(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_mul_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec operator+(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_add_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec operator-(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_sub_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec FMA(Vec a, const Vec& b, const Vec& c) {
+        a.v = _mm512_fmadd_pd(a.v, b.v, c.v);
+        //a.v = _mm512_add_pd(_mm512_mul_pd(a.v, b.v), c.v);
+        return a;
+      }
+
+      // Comparison operators
+      //friend Vec operator< (Vec lhs, const Vec& rhs) {
+      //  lhs.v = _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_LT_OS)));
+      //  return lhs;
+      //}
+      //friend Vec operator<=(Vec lhs, const Vec& rhs) {
+      //  lhs.v = _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_LE_OS)));
+      //  return lhs;
+      //}
+      //friend Vec operator>=(Vec lhs, const Vec& rhs) {
+      //  lhs.v = _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_GE_OS)));
+      //  return lhs;
+      //}
+      //friend Vec operator> (Vec lhs, const Vec& rhs) {
+      //  lhs.v = _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_GT_OS)));
+      //  return lhs;
+      //}
+      //friend Vec operator==(Vec lhs, const Vec& rhs) {
+      //  lhs.v = _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_EQ_OS)));
+      //  return lhs;
+      //}
+      //friend Vec operator!=(Vec lhs, const Vec& rhs) {
+      //  lhs.v = _mm512_castsi512_pd(_mm512_movm_epi64(_mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_NEQ_OS)));
+      //  return lhs;
+      //}
+
+      friend __mmask8 operator< (Vec lhs, const Vec& rhs) {
+        return _mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_LT_OS);
+      }
+      friend __mmask8 operator<=(Vec lhs, const Vec& rhs) {
+        return _mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_LE_OS);
+      }
+      friend __mmask8 operator>=(Vec lhs, const Vec& rhs) {
+        return _mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_GE_OS);
+      }
+      friend __mmask8 operator> (Vec lhs, const Vec& rhs) {
+        return _mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_GT_OS);
+      }
+      friend __mmask8 operator==(Vec lhs, const Vec& rhs) {
+        return _mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_EQ_OS);
+      }
+      friend __mmask8 operator!=(Vec lhs, const Vec& rhs) {
+        return _mm512_cmp_pd_mask(lhs.v, rhs.v, _CMP_NEQ_OS);
+      }
+
+      // Bitwise operators
+      friend Vec operator&(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_and_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec operator^(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_xor_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec operator|(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_or_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec AndNot(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_andnot_pd(rhs.v, lhs.v);
+        return lhs;
+      }
+      friend Vec operator&(Vec lhs, const __mmask8& rhs) {
+        lhs.v = _mm512_maskz_mov_pd(rhs, lhs.v);
+        return lhs;
+      }
+      friend Vec AndNot(Vec lhs, const __mmask8& rhs) {
+        lhs.v = _mm512_mask_mov_pd(lhs.v, rhs, _mm512_setzero_pd());
+        return lhs;
+      }
+
+      // Assignment operators
+      Vec& operator*=(const Vec& rhs) {
+        v = _mm512_mul_pd(v, rhs.v);
+        return *this;
+      }
+      Vec& operator+=(const Vec& rhs) {
+        v = _mm512_add_pd(v, rhs.v);
+        return *this;
+      }
+      Vec& operator-=(const Vec& rhs) {
+        v = _mm512_sub_pd(v, rhs.v);
+        return *this;
+      }
+      Vec& operator&=(const Vec& rhs) {
+        v = _mm512_and_pd(v, rhs.v);
+        return *this;
+      }
+      Vec& operator^=(const Vec& rhs) {
+        v = _mm512_xor_pd(v, rhs.v);
+        return *this;
+      }
+      Vec& operator|=(const Vec& rhs) {
+        v = _mm512_or_pd(v, rhs.v);
+        return *this;
+      }
+      Vec& operator&=(const __mmask8& rhs) {
+        v = _mm512_maskz_mov_pd(rhs, v);
+        return *this;
+      }
+
+      // Other operators
+      friend Vec max(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_max_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+      friend Vec min(Vec lhs, const Vec& rhs) {
+        lhs.v = _mm512_min_pd(lhs.v, rhs.v);
+        return lhs;
+      }
+
+      friend std::ostream& operator<<(std::ostream& os, const Vec& in) {
+        union {
+          VecType vec;
+          ValueType val[N];
+        };
+        vec = in.v;
+        for (Integer i = 0; i < N; i++) os << val[i] << ' ';
+        return os;
+      }
+      friend Vec approx_rsqrt(const Vec& x) {
+        Vec r;
+        r.v = _mm512_cvtps_pd(_mm256_rsqrt_ps(_mm512_cvtpd_ps(x.v)));
+        return r;
+      }
+
+      template <class Vec1, class Vec2> friend Vec1 reinterpret(const Vec2& x);
+      template <class Vec> friend Vec RoundReal2Real(const Vec& x);
+      template <class Vec> friend void sincos_intrin(Vec& sinx, Vec& cosx, const Vec& x);
+      template <class Vec> friend void exp_intrin(Vec& expx, const Vec& x);
+
+    private:
+
+      VecType v;
+  };
+
+  template <> inline Vec<int64_t,8> reinterpret<Vec<int64_t,8>,Vec<double,8>>(const Vec<double,8>& x){
+    union {
+      Vec<int64_t,8> r;
+      __m512i y;
+    };
+    y = _mm512_castpd_si512(x.v);
+    return r;
+  }
+
+  template <> inline Vec<double,8> RoundReal2Real(const Vec<double,8>& x) {
+    Vec<double,8> r;
+    // TODO: need double check
+    r.v = _mm512_roundscale_pd(x.v,_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC);
+    return r;
+  }
+
+  #ifdef SCTL_HAVE_SVML
+  template <> inline void sincos_intrin(Vec<double,8>& sinx, Vec<double,8>& cosx, const Vec<double,8>& x) {
+    sinx.v = _mm512_sin_pd(x.v);
+    cosx.v = _mm512_cos_pd(x.v);
+  }
+
+  template <> inline void exp_intrin(Vec<double,8>& expx, const Vec<double,8>& x) {
+    expx.v = _mm512_exp_pd(x.v);
+  }
   #endif
 
 #endif