summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--mathfuncs_sqrt.h8
-rw-r--r--test.cc6
-rw-r--r--vec_double_avx.h184
-rw-r--r--vec_double_sse2.h433
-rw-r--r--vec_float_avx.h506
-rw-r--r--vec_float_sse2.h415
-rw-r--r--vecmathlib.h10
8 files changed, 1460 insertions, 103 deletions
diff --git a/.gitignore b/.gitignore
index c58f8d1..b69d47d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ example
old
test
.ninja_log
+OUT
diff --git a/mathfuncs_sqrt.h b/mathfuncs_sqrt.h
index c1ea3f7..050fc91 100644
--- a/mathfuncs_sqrt.h
+++ b/mathfuncs_sqrt.h
@@ -57,6 +57,14 @@ namespace vecmathlib {
template<typename realvec_t>
realvec_t mathfuncs<realvec_t>::vml_rsqrt(realvec_t x)
{
+#if 0
+ double const x_2 = 0.5 * x; // x/2
+ // Newton method:
+ // Solve f(r) = 0 for f(r) = x - 1/r^2
+ // r <- r - f(r) / f'(r)
+ // r <- (3 r - r^3 x) / 2
+ return r * (1.5 - r*r * x_2);
+#endif
return rcp(sqrt(x));
}
diff --git a/test.cc b/test.cc
index 9d45069..c61d0ae 100644
--- a/test.cc
+++ b/test.cc
@@ -40,7 +40,7 @@ struct vecmathlib_test {
// Test each function with this many random values
- static int const imax = 100000;
+ static int const imax = 10000;
// Require that 3/4 of the digits are correct
static real_t constexpr accuracy = pow(realvec_t::epsilon(), R(0.75));
@@ -380,7 +380,11 @@ int main(int argc, char** argv)
cout << "Testing math functions:\n";
vecmathlib_test<realvec<float,1>>::test();
+ vecmathlib_test<realvec<float,4>>::test();
+ vecmathlib_test<realvec<float,8>>::test();
+
vecmathlib_test<realvec<double,1>>::test();
+ vecmathlib_test<realvec<double,2>>::test();
vecmathlib_test<realvec<double,4>>::test();
cout << "\n";
diff --git a/vec_double_avx.h b/vec_double_avx.h
index f311095..081045f 100644
--- a/vec_double_avx.h
+++ b/vec_double_avx.h
@@ -171,34 +171,27 @@ namespace vecmathlib {
// Note: not all arithmetic operations are supported!
intvec operator+() const { return *this; }
- intvec operator-() const
- {
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- v01 = _mm_sub_epi64(_mm_set1_epi64x(0), v01);
- v23 = _mm_sub_epi64(_mm_set1_epi64x(0), v23);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
- }
+ intvec operator-() const { return IV(I(0)) - *this; }
intvec operator+(intvec x) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- __m128i xv01 = _mm256_castsi256_si128(x.v);
- __m128i xv23 = _mm256_extractf128_si256(x.v, 1);
- v01 = _mm_add_epi64(v01, xv01);
- v23 = _mm_add_epi64(v23, xv23);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i xvlo = _mm256_castsi256_si128(x.v);
+ __m128i xvhi = _mm256_extractf128_si256(x.v, 1);
+ vlo = _mm_add_epi64(vlo, xvlo);
+ vhi = _mm_add_epi64(vhi, xvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec operator-(intvec x) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- __m128i xv01 = _mm256_castsi256_si128(x.v);
- __m128i xv23 = _mm256_extractf128_si256(x.v, 1);
- v01 = _mm_sub_epi64(v01, xv01);
- v23 = _mm_sub_epi64(v23, xv23);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i xvlo = _mm256_castsi256_si128(x.v);
+ __m128i xvhi = _mm256_extractf128_si256(x.v, 1);
+ vlo = _mm_sub_epi64(vlo, xvlo);
+ vhi = _mm_sub_epi64(vhi, xvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec& operator+=(intvec const& x) { return *this=*this+x; }
@@ -206,11 +199,7 @@ namespace vecmathlib {
- intvec operator~() const
- {
- return _mm256_castpd_si256(_mm256_xor_pd(_mm256_castsi256_pd(IV(~U(0))),
- _mm256_castsi256_pd(v)));
- }
+ intvec operator~() const { return IV(~U(0)) ^ *this; }
intvec operator&(intvec x) const
{
@@ -234,118 +223,109 @@ namespace vecmathlib {
- // SSE2 shift instructions potentially relevant for 64-bit
- // operations:
- // _mm_slli_epi64
- // _mm_srli_epi64
- // _mm_sll_epi64
- // _mm_srl_epi64
- // _mm_srai_epi32
- // _mm_sra_epi32
- // _mm_srli_si128
- // _mm_slli_si128
intvec lsr(int_t n) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- v01 = _mm_srli_epi64(v01, n);
- v23 = _mm_srli_epi64(v23, n);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ vlo = _mm_srli_epi64(vlo, n);
+ vhi = _mm_srli_epi64(vhi, n);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec operator>>(int_t n) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- // There is no _mm_srai_epi64. To emulate it, add 0x8000000
- // before shifting, and subtracted the shifted 0x80000000 after shifting
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ // There is no _mm_srai_epi64. To emulate it, add 0x80000000
+ // before shifting, and subtract the shifted 0x80000000 after
+ // shifting
#if 0
__m128i signmask01 = _mm_sub_epi64(_mm_set1_epi64x(0),
- _mm_srli_epi64(v01, 63));
+ _mm_srli_epi64(vlo, 63));
__m128i signmask23 = _mm_sub_epi64(_mm_set1_epi64x(0),
- _mm_srli_epi64(v23, 63));
- v01 = _mm_xor_si128(signmask01, v01);
- v23 = _mm_xor_si128(signmask23, v23);
- v01 = _mm_srli_epi64(v01, n);
- v23 = _mm_srli_epi64(v23, n);
- v01 = _mm_xor_si128(signmask01, v01);
- v23 = _mm_xor_si128(signmask23, v23);
+ _mm_srli_epi64(vhi, 63));
+ vlo = _mm_xor_si128(signmask01, vlo);
+ vhi = _mm_xor_si128(signmask23, vhi);
+ vlo = _mm_srli_epi64(vlo, n);
+ vhi = _mm_srli_epi64(vhi, n);
+ vlo = _mm_xor_si128(signmask01, vlo);
+ vhi = _mm_xor_si128(signmask23, vhi);
#else
// Convert signed to unsiged
- v01 += _mm_set1_epi64x(U(1) << (bits-1));
- v23 += _mm_set1_epi64x(U(1) << (bits-1));
+ vlo += _mm_set1_epi64x(U(1) << (bits-1));
+ vhi += _mm_set1_epi64x(U(1) << (bits-1));
// Shift
- v01 = _mm_srli_epi64(v01, n);
- v23 = _mm_srli_epi64(v23, n);
+ vlo = _mm_srli_epi64(vlo, n);
+ vhi = _mm_srli_epi64(vhi, n);
// Undo conversion
- v01 -= _mm_set1_epi64x(U(1) << (bits-n));
- v23 -= _mm_set1_epi64x(U(1) << (bits-n));
+ vlo -= _mm_set1_epi64x(U(1) << (bits-n));
+ vhi -= _mm_set1_epi64x(U(1) << (bits-n));
#endif
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec operator<<(int_t n) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- v01 = _mm_slli_epi64(v01, n);
- v23 = _mm_slli_epi64(v23, n);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ vlo = _mm_slli_epi64(vlo, n);
+ vhi = _mm_slli_epi64(vhi, n);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec& operator>>=(int_t n) { return *this=*this>>n; }
intvec& operator<<=(int_t n) { return *this=*this<<n; }
intvec lsr(intvec n) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- __m128i nv01 = _mm256_castsi256_si128(n.v);
- __m128i nv23 = _mm256_extractf128_si256(n.v, 1);
- v01 = _mm_srl_epi64(v01, nv01);
- v23 = _mm_srl_epi64(v23, nv23);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i nvlo = _mm256_castsi256_si128(n.v);
+ __m128i nvhi = _mm256_extractf128_si256(n.v, 1);
+ vlo = _mm_srl_epi64(vlo, nvlo);
+ vhi = _mm_srl_epi64(vhi, nvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec operator>>(intvec n) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- __m128i nv01 = _mm256_castsi256_si128(n.v);
- __m128i nv23 = _mm256_extractf128_si256(n.v, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i nvlo = _mm256_castsi256_si128(n.v);
+ __m128i nvhi = _mm256_extractf128_si256(n.v, 1);
#if 0
// There is no _mm_srai_epi64. To emulate it, invert all bits
// before and after shifting if the sign bit is set.
__m128i signmask01 = _mm_sub_epi64(_mm_set1_epi64x(0),
- _mm_srli_epi64(v01, 63));
+ _mm_srli_epi64(vlo, 63));
__m128i signmask23 = _mm_sub_epi64(_mm_set1_epi64x(0),
- _mm_srli_epi64(v23, 63));
- v01 = _mm_xor_si128(signmask01, v01);
- v23 = _mm_xor_si128(signmask23, v23);
- v01 = _mm_srl_epi64(v01, nv01);
- v23 = _mm_srl_epi64(v23, nv23);
- v01 = _mm_xor_si128(signmask01, v01);
- v23 = _mm_xor_si128(signmask23, v23);
+ _mm_srli_epi64(vhi, 63));
+ vlo = _mm_xor_si128(signmask01, vlo);
+ vhi = _mm_xor_si128(signmask23, vhi);
+ vlo = _mm_srl_epi64(vlo, nvlo);
+ vhi = _mm_srl_epi64(vhi, nvhi);
+ vlo = _mm_xor_si128(signmask01, vlo);
+ vhi = _mm_xor_si128(signmask23, vhi);
#else
// Convert signed to unsiged
- v01 += _mm_set1_epi64x(U(1) << (bits-1));
- v23 += _mm_set1_epi64x(U(1) << (bits-1));
+ vlo += _mm_set1_epi64x(U(1) << (bits-1));
+ vhi += _mm_set1_epi64x(U(1) << (bits-1));
// Shift
- v01 = _mm_srl_epi64(v01, nv01);
- v23 = _mm_srl_epi64(v23, nv23);
+ vlo = _mm_srl_epi64(vlo, nvlo);
+ vhi = _mm_srl_epi64(vhi, nvhi);
// Undo conversion
- v01 -= _mm_sll_epi64(_mm_set1_epi64x(1),
- _mm_sub_epi64(_mm_set1_epi64x(bits), nv01));
- v23 -= _mm_sll_epi64(_mm_set1_epi64x(1),
- _mm_sub_epi64(_mm_set1_epi64x(bits), nv23));
+ vlo -= _mm_sll_epi64(_mm_set1_epi64x(1),
+ _mm_sub_epi64(_mm_set1_epi64x(bits), nvlo));
+ vhi -= _mm_sll_epi64(_mm_set1_epi64x(1),
+ _mm_sub_epi64(_mm_set1_epi64x(bits), nvhi));
#endif
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec operator<<(intvec n) const
{
- __m128i v01 = _mm256_castsi256_si128(v);
- __m128i v23 = _mm256_extractf128_si256(v, 1);
- __m128i nv01 = _mm256_castsi256_si128(n.v);
- __m128i nv23 = _mm256_extractf128_si256(n.v, 1);
- v01 = _mm_sll_epi64(v01, nv01);
- v23 = _mm_sll_epi64(v23, nv23);
- return _mm256_insertf128_si256(_mm256_castsi128_si256(v01), v23, 1);
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i nvlo = _mm256_castsi256_si128(n.v);
+ __m128i nvhi = _mm256_extractf128_si256(n.v, 1);
+ vlo = _mm_sll_epi64(vlo, nvlo);
+ vhi = _mm_sll_epi64(vhi, nvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
}
intvec& operator>>=(intvec n) { return *this=*this>>n; }
intvec& operator<<=(intvec n) { return *this=*this<<n; }
@@ -403,7 +383,7 @@ namespace vecmathlib {
realvec operator+() const { return *this; }
- realvec operator-() const { return _mm256_sub_pd(_mm256_set1_pd(0.0), v); }
+ realvec operator-() const { return RV(0.0) - *this; }
realvec operator+(realvec x) const { return _mm256_add_pd(v, x.v); }
realvec operator-(realvec x) const { return _mm256_sub_pd(v, x.v); }
diff --git a/vec_double_sse2.h b/vec_double_sse2.h
new file mode 100644
index 0000000..1c6648c
--- /dev/null
+++ b/vec_double_sse2.h
@@ -0,0 +1,433 @@
+// -*-C++-*-
+
+#ifndef VEC_DOUBLE_SSE2_H
+#define VEC_DOUBLE_SSE2_H
+
+#include "floatprops.h"
+#include "mathfuncs.h"
+#include "vec_base.h"
+
+#include <cmath>
+
+// SSE2 intrinsics
+#include <emmintrin.h>
+#ifdef __SSE4_1__ // Intel's SSE 4.1
+# include <smmintrin.h>
+#endif
+#ifdef __SSE4A__ // AMD's SSE 4a
+# include <ammintrin.h>
+#endif
+
+
+
+namespace vecmathlib {
+
+ template<> struct boolvec<double,2>;
+ template<> struct intvec<double,2>;
+ template<> struct realvec<double,2>;
+
+
+
+ template<>
+ struct boolvec<double,2>: floatprops<double>
+ {
+ static int const size = 2;
+ typedef bool scalar_t;
+ typedef __m128d bvector_t;
+
+ static_assert(size * sizeof(real_t) == sizeof(bvector_t),
+ "vector size is wrong");
+
+ private:
+ // true values have the sign bit set, false values have it unset
+ static uint_t from_bool(bool a) { return - uint_t(a); }
+ static bool to_bool(uint_t a) { return int_t(a) < int_t(0); }
+ public:
+
+ typedef boolvec boolvec_t;
+ typedef intvec<real_t, size> intvec_t;
+ typedef realvec<real_t, size> realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ bvector_t v;
+
+ boolvec() {}
+ boolvec(boolvec const& x): v(x.v) {}
+ boolvec& operator=(boolvec const& x) { return v=x.v, *this; }
+ boolvec(bvector_t x): v(x) {}
+ boolvec(bool a):
+ v(_mm_castsi128_pd(_mm_set1_epi64x(from_bool(a)))) {}
+ boolvec(bool const* as):
+ v(_mm_castsi128_pd(_mm_set_epi64x(from_bool(as[1]), from_bool(as[0])))) {}
+
+ operator bvector_t() const { return v; }
+ bool operator[](int n) const { return to_bool(((uint_t const*)&v)[n]); }
+ boolvec& set_elt(int n, bool a)
+ {
+ return ((int_t*)&v)[n] = from_bool(a), *this;
+ }
+
+
+
+ auto as_int() const -> intvec_t; // defined after intvec
+ auto convert_int() const -> intvec_t; // defined after intvec
+
+
+
+ boolvec operator!() const { return _mm_xor_pd(boolvec(true), v); }
+
+ boolvec operator&&(boolvec x) const { return _mm_and_pd(v, x.v); }
+ boolvec operator||(boolvec x) const { return _mm_or_pd(v, x.v); }
+ boolvec operator==(boolvec x) const { return !(*this==x); }
+ boolvec operator!=(boolvec x) const { return _mm_xor_pd(v, x.v); }
+
+ bool all() const
+ {
+ return (*this)[0] && (*this)[1];
+ }
+ bool any() const
+ {
+ return (*this)[0] || (*this)[1];
+ }
+
+
+
+ // ifthen(condition, then-value, else-value)
+ auto ifthen(intvec_t x,
+ intvec_t y) const -> intvec_t; // defined after intvec
+ auto ifthen(realvec_t x,
+ realvec_t y) const -> realvec_t; // defined after realvec
+
+ };
+
+
+
+ template<>
+ struct intvec<double,2>: floatprops<double>
+ {
+ static int const size = 2;
+ typedef int_t scalar_t;
+ typedef __m128i ivector_t;
+
+ static_assert(size * sizeof(real_t) == sizeof(ivector_t),
+ "vector size is wrong");
+
+ typedef boolvec<real_t, size> boolvec_t;
+ typedef intvec intvec_t;
+ typedef realvec<real_t, size> realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ ivector_t v;
+
+ intvec() {}
+ intvec(intvec const& x): v(x.v) {}
+ intvec& operator=(intvec const& x) { return v=x.v, *this; }
+ intvec(ivector_t x): v(x) {}
+ intvec(int_t a): v(_mm_set1_epi64x(a)) {}
+ intvec(int_t const* as): v(_mm_set_epi64x(as[1], as[0])) {}
+
+ operator ivector_t() const { return v; }
+ int_t operator[](int n) const { return ((int_t const*)&v)[n]; }
+ intvec& set_elt(int n, int_t a) { return ((int_t*)&v)[n]=a, *this; }
+
+
+
+ auto as_bool() const -> boolvec_t { return _mm_castsi128_pd(v); }
+ auto convert_bool() const -> boolvec_t
+ {
+ // Result: convert_bool(0)=false, convert_bool(else)=true
+ // There is no intrinsic to compare with zero. Instead, we check
+ // whether x is positive and x-1 is negative.
+ intvec x = *this;
+ intvec xm1 = x - 1;
+ // We know that boolvec values depend only on the sign bit
+ // return (~xm1 | x).as_bool();
+ return x.as_bool() || !xm1.as_bool();
+ }
+ auto as_float() const -> realvec_t; // defined after realvec
+ auto convert_float() const -> realvec_t; // defined after realvec
+
+
+
+ // Note: not all arithmetic operations are supported!
+
+ intvec operator+() const { return *this; }
+ intvec operator-() const { return IV(I(0)) - *this; }
+
+ intvec operator+(intvec x) const { return _mm_add_epi64(v, x.v); }
+ intvec operator-(intvec x) const { return _mm_sub_epi64(v, x.v); }
+
+ intvec& operator+=(intvec const& x) { return *this=*this+x; }
+ intvec& operator-=(intvec const& x) { return *this=*this-x; }
+
+
+
+ intvec operator~() const { return IV(~U(0)) ^ *this; }
+
+ intvec operator&(intvec x) const
+ {
+ return _mm_castpd_si128(_mm_and_pd(_mm_castsi128_pd(v),
+ _mm_castsi128_pd(x.v)));
+ }
+ intvec operator|(intvec x) const
+ {
+ return _mm_castpd_si128(_mm_or_pd(_mm_castsi128_pd(v),
+ _mm_castsi128_pd(x.v)));
+ }
+ intvec operator^(intvec x) const
+ {
+ return _mm_castpd_si128(_mm_xor_pd(_mm_castsi128_pd(v),
+ _mm_castsi128_pd(x.v)));
+ }
+
+ intvec& operator&=(intvec const& x) { return *this=*this&x; }
+ intvec& operator|=(intvec const& x) { return *this=*this|x; }
+ intvec& operator^=(intvec const& x) { return *this=*this^x; }
+
+
+
+ intvec lsr(int_t n) const { return _mm_srli_epi64(v, n); }
+ intvec operator>>(int_t n) const
+ {
+ // There is no _mm_srai_epi64. To emulate it, add 0x80000000
+ // before shifting, and subtract the shifted 0x80000000 after
+ // shifting
+ intvec x = *this;
+ // Convert signed to unsiged
+ x += U(1) << (bits-1);
+ // Shift
+ x = x.lsr(x);
+ // Undo conversion
+ x -= U(1) << (bits-n);
+ return x;
+ }
+ intvec operator<<(int_t n) const { return _mm_slli_epi64(v, n); }
+ intvec& operator>>=(int_t n) { return *this=*this>>n; }
+ intvec& operator<<=(int_t n) { return *this=*this<<n; }
+
+ intvec lsr(intvec n) const { return _mm_srl_epi64(v, n.v); }
+ intvec operator>>(intvec n) const
+ {
+ // There is no _mm_srai_epi64. To emulate it, add 0x80000000
+ // before shifting, and subtract the shifted 0x80000000 after
+ // shifting
+ intvec x = *this;
+ // Convert signed to unsiged
+ x += U(1) << (bits-1);
+ // Shift
+ x = x.lsr(n);
+ // Undo conversion
+ x -= IV(1) << (IV(bits) - n);
+ return x;
+ }
+ intvec operator<<(intvec n) const { return _mm_sll_epi64(v, n.v); }
+ intvec& operator>>=(intvec n) { return *this=*this>>n; }
+ intvec& operator<<=(intvec n) { return *this=*this<<n; }
+ };
+
+
+
+ template<>
+ struct realvec<double,2>: floatprops<double>
+ {
+ static int const size = 2;
+ typedef real_t scalar_t;
+ typedef __m128d vector_t;
+
+ static constexpr char const* const name = "<SSE2:2*double>";
+ inline void barrier() { asm("": "+x" (v)); }
+
+ static_assert(size * sizeof(real_t) == sizeof(vector_t),
+ "vector size is wrong");
+
+ typedef boolvec<real_t, size> boolvec_t;
+ typedef intvec<real_t, size> intvec_t;
+ typedef realvec realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ vector_t v;
+
+ realvec() {}
+ realvec(realvec const& x): v(x.v) {}
+ realvec& operator=(realvec const& x) { return v=x.v, *this; }
+ realvec(vector_t x): v(x) {}
+ realvec(real_t a): v(_mm_set1_pd(a)) {}
+ realvec(real_t const* as): v(_mm_set_pd(as[1], as[0])) {}
+
+ operator vector_t() const { return v; }
+ real_t operator[](int n) const { return ((real_t const*)&v)[n]; }
+ realvec& set_elt(int n, real_t a) { return ((real_t*)&v)[n]=a, *this; }
+
+
+
+ intvec_t as_int() const { return _mm_castpd_si128(v); }
+ intvec_t convert_int() const { return MF::vml_convert_int(*this); }
+
+
+
+ realvec operator+() const { return *this; }
+ realvec operator-() const { return RV(0.0) - *this; }
+
+ realvec operator+(realvec x) const { return _mm_add_pd(v, x.v); }
+ realvec operator-(realvec x) const { return _mm_sub_pd(v, x.v); }
+ realvec operator*(realvec x) const { return _mm_mul_pd(v, x.v); }
+ realvec operator/(realvec x) const { return _mm_div_pd(v, x.v); }
+
+ realvec& operator+=(realvec const& x) { return *this=*this+x; }
+ realvec& operator-=(realvec const& x) { return *this=*this-x; }
+ realvec& operator*=(realvec const& x) { return *this=*this*x; }
+ realvec& operator/=(realvec const& x) { return *this=*this/x; }
+
+ real_t prod() const
+ {
+ return (*this)[0] * (*this)[1];
+ }
+ real_t sum() const
+ {
+ return (*this)[0] + (*this)[1];
+ }
+
+
+
+ boolvec_t operator==(realvec const& x) const
+ {
+ return _mm_cmpeq_pd(v, x.v);
+ }
+ boolvec_t operator!=(realvec const& x) const
+ {
+ return _mm_cmpneq_pd(v, x.v);
+ }
+ boolvec_t operator<(realvec const& x) const
+ {
+ return _mm_cmplt_pd(v, x.v);
+ }
+ boolvec_t operator<=(realvec const& x) const
+ {
+ return _mm_cmple_pd(v, x.v);
+ }
+ boolvec_t operator>(realvec const& x) const
+ {
+ return _mm_cmpgt_pd(v, x.v);
+ }
+ boolvec_t operator>=(realvec const& x) const
+ {
+ return _mm_cmpge_pd(v, x.v);
+ }
+
+
+
+ realvec acos() const { return MF::vml_acos(*this); }
+ realvec acosh() const { return MF::vml_acosh(*this); }
+ realvec asin() const { return MF::vml_asin(*this); }
+ realvec asinh() const { return MF::vml_asinh(*this); }
+ realvec atan() const { return MF::vml_atan(*this); }
+ realvec atanh() const { return MF::vml_atanh(*this); }
+ realvec ceil() const { return _mm_ceil_pd(v); }
+ realvec copysign(realvec y) const { return MF::vml_copysign(*this, y); }
+ realvec cos() const { return MF::vml_cos(*this); }
+ realvec cosh() const { return MF::vml_cosh(*this); }
+ realvec exp() const { return MF::vml_exp(*this); }
+ realvec exp10() const { return MF::vml_exp10(*this); }
+ realvec exp2() const { return MF::vml_exp2(*this); }
+ realvec expm1() const { return MF::vml_expm1(*this); }
+ realvec fabs() const { return MF::vml_fabs(*this); }
+ realvec floor() const { return _mm_floor_pd(v); }
+ realvec fmod(realvec y) const { return MF::vml_fmod(*this, y); }
+ intvec_t ilogb() const { return MF::vml_ilogb(*this); }
+ realvec log() const { return MF::vml_log(*this); }
+ realvec log10() const { return MF::vml_log10(*this); }
+ realvec log1p() const { return MF::vml_log1p(*this); }
+ realvec log2() const { return MF::vml_log2(*this); }
+ realvec pow(realvec y) const { return MF::vml_pow(*this, y); }
+ realvec rcp() const { return _mm_div_pd(_mm_set1_pd(1.0), v); }
+ realvec remainder(realvec y) const { return MF::vml_remainder(*this, y); }
+ realvec round() const { return _mm_round_pd(v, _MM_FROUND_NINT); }
+ realvec rsqrt() const { return MF::vml_rsqrt(*this); }
+ realvec scalbn(intvec_t n) const { return MF::vml_scalbn(*this, n); }
+ boolvec_t signbit() const { return v; }
+ realvec sin() const { return MF::vml_sin(*this); }
+ realvec sinh() const { return MF::vml_sinh(*this); }
+ realvec sqrt() const { return _mm_sqrt_pd(v); }
+ realvec tan() const { return MF::vml_tan(*this); }
+ realvec tanh() const { return MF::vml_tanh(*this); }
+ };
+
+
+
+ // boolvec definitions
+
+ inline
+ auto boolvec<double,2>::as_int() const -> intvec_t
+ {
+ return _mm_castpd_si128(v);
+ }
+
+ inline
+ auto boolvec<double,2>::convert_int() const -> intvec_t
+ {
+ //return ifthen(v, U(1), U(0));
+ return lsr(as_int(), bits-1);
+ }
+
+ inline
+ auto boolvec<double,2>::ifthen(intvec_t x, intvec_t y) const -> intvec_t
+ {
+ return ifthen(x.as_float(), y.as_float()).as_int();
+ }
+
+ inline
+ auto boolvec<double,2>::ifthen(realvec_t x, realvec_t y) const -> realvec_t
+ {
+ return _mm_blendv_pd(y.v, x.v, v);
+ }
+
+
+
+ // intvec definitions
+
+ inline auto intvec<double,2>::as_float() const -> realvec_t
+ {
+ return _mm_castsi128_pd(v);
+ }
+
+ inline auto intvec<double,2>::convert_float() const -> realvec_t
+ {
+ return MF::vml_convert_float(*this);
+ }
+
+} // namespace vecmathlib
+
+#endif // #ifndef VEC_DOUBLE_SSE2_H
diff --git a/vec_float_avx.h b/vec_float_avx.h
new file mode 100644
index 0000000..4a19673
--- /dev/null
+++ b/vec_float_avx.h
@@ -0,0 +1,506 @@
+// -*-C++-*-
+
+#ifndef VEC_FLOAT_AVX_H
+#define VEC_FLOAT_AVX_H
+
+#include "floatprops.h"
+#include "mathfuncs.h"
+#include "vec_base.h"
+
+#include <cmath>
+
+// AVX intrinsics
+#include <immintrin.h>
+
+
+
+namespace vecmathlib {
+
+ template<> struct boolvec<float,8>;
+ template<> struct intvec<float,8>;
+ template<> struct realvec<float,8>;
+
+
+
+ template<>
+ struct boolvec<float,8>: floatprops<float>
+ {
+ static int const size = 8;
+ typedef bool scalar_t;
+ typedef __m256 bvector_t;
+
+ static_assert(size * sizeof(real_t) == sizeof(bvector_t),
+ "vector size is wrong");
+
+ private:
+ // true values have the sign bit set, false values have it unset
+ static uint_t from_bool(bool a) { return - uint_t(a); }
+ static bool to_bool(uint_t a) { return int_t(a) < int_t(0); }
+ public:
+
+ typedef boolvec boolvec_t;
+ typedef intvec<real_t, size> intvec_t;
+ typedef realvec<real_t, size> realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ bvector_t v;
+
+ boolvec() {}
+ boolvec(boolvec const& x): v(x.v) {}
+ boolvec& operator=(boolvec const& x) { return v=x.v, *this; }
+ boolvec(bvector_t x): v(x) {}
+ boolvec(bool a):
+ v(_mm256_castsi256_ps(_mm256_set1_epi32(from_bool(a)))) {}
+ boolvec(bool const* as):
+ v(_mm256_castsi256_ps(_mm256_set_epi32(from_bool(as[7]),
+ from_bool(as[6]),
+ from_bool(as[5]),
+ from_bool(as[4]),
+ from_bool(as[3]),
+ from_bool(as[2]),
+ from_bool(as[1]),
+ from_bool(as[0])))) {}
+
+ operator bvector_t() const { return v; }
+ bool operator[](int n) const { return to_bool(((uint_t const*)&v)[n]); }
+ boolvec& set_elt(int n, bool a)
+ {
+ return ((int_t*)&v)[n] = from_bool(a), *this;
+ }
+
+
+
+ auto as_int() const -> intvec_t; // defined after intvec
+ auto convert_int() const -> intvec_t; // defined after intvec
+
+
+
+ boolvec operator!() const { return _mm256_xor_ps(boolvec(true), v); }
+
+ boolvec operator&&(boolvec x) const { return _mm256_and_ps(v, x.v); }
+ boolvec operator||(boolvec x) const { return _mm256_or_ps(v, x.v); }
+ boolvec operator==(boolvec x) const { return !(*this==x); }
+ boolvec operator!=(boolvec x) const { return _mm256_xor_ps(v, x.v); }
+
+ bool all() const
+ {
+ return (*this)[0] && (*this)[1] && (*this)[2] && (*this)[3];
+ }
+ bool any() const
+ {
+ return (*this)[0] || (*this)[1] || (*this)[2] || (*this)[3];
+ }
+
+
+
+ // ifthen(condition, then-value, else-value)
+ auto ifthen(intvec_t x,
+ intvec_t y) const -> intvec_t; // defined after intvec
+ auto ifthen(realvec_t x,
+ realvec_t y) const -> realvec_t; // defined after realvec
+
+ };
+
+
+
+ template<>
+ struct intvec<float,8>: floatprops<float>
+ {
+ static int const size = 8;
+ typedef int_t scalar_t;
+ typedef __m256i ivector_t;
+
+ static_assert(size * sizeof(real_t) == sizeof(ivector_t),
+ "vector size is wrong");
+
+ typedef boolvec<real_t, size> boolvec_t;
+ typedef intvec intvec_t;
+ typedef realvec<real_t, size> realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ ivector_t v;
+
+ intvec() {}
+ intvec(intvec const& x): v(x.v) {}
+ intvec& operator=(intvec const& x) { return v=x.v, *this; }
+ intvec(ivector_t x): v(x) {}
+ intvec(int_t a): v(_mm256_set1_epi32(a)) {}
+ intvec(int_t const* as): v(_mm256_set_epi32(as[7], as[6], as[5], as[4],
+ as[3], as[2], as[1], as[0])) {}
+
+ operator ivector_t() const { return v; }
+ int_t operator[](int n) const { return ((int_t const*)&v)[n]; }
+ intvec& set_elt(int n, int_t a) { return ((int_t*)&v)[n]=a, *this; }
+
+
+
+ auto as_bool() const -> boolvec_t { return _mm256_castsi256_ps(v); }
+ auto convert_bool() const -> boolvec_t
+ {
+ // Result: convert_bool(0)=false, convert_bool(else)=true
+ // There is no intrinsic to compare with zero. Instead, we check
+ // whether x is positive and x-1 is negative.
+ intvec x = *this;
+ intvec xm1 = x - 1;
+ // We know that boolvec values depend only on the sign bit
+ // return (~xm1 | x).as_bool();
+ return x.as_bool() || !xm1.as_bool();
+ }
+ auto as_float() const -> realvec_t; // defined after realvec
+ auto convert_float() const -> realvec_t; // defined after realvec
+
+
+
+ // Note: not all arithmetic operations are supported!
+
+ intvec operator+() const { return *this; }
+ intvec operator-() const { return IV(0) - *this; }
+
+ intvec operator+(intvec x) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i xvlo = _mm256_castsi256_si128(x.v);
+ __m128i xvhi = _mm256_extractf128_si256(x.v, 1);
+ vlo = _mm_add_epi32(vlo, xvlo);
+ vhi = _mm_add_epi32(vhi, xvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec operator-(intvec x) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i xvlo = _mm256_castsi256_si128(x.v);
+ __m128i xvhi = _mm256_extractf128_si256(x.v, 1);
+ vlo = _mm_sub_epi32(vlo, xvlo);
+ vhi = _mm_sub_epi32(vhi, xvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+
+ intvec& operator+=(intvec const& x) { return *this=*this+x; }
+ intvec& operator-=(intvec const& x) { return *this=*this-x; }
+
+
+
+ intvec operator~() const { return IV(~U(0)) ^ *this; }
+
+ intvec operator&(intvec x) const
+ {
+ return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(v),
+ _mm256_castsi256_ps(x.v)));
+ }
+ intvec operator|(intvec x) const
+ {
+ return _mm256_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(v),
+ _mm256_castsi256_ps(x.v)));
+ }
+ intvec operator^(intvec x) const
+ {
+ return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(v),
+ _mm256_castsi256_ps(x.v)));
+ }
+
+ intvec& operator&=(intvec const& x) { return *this=*this&x; }
+ intvec& operator|=(intvec const& x) { return *this=*this|x; }
+ intvec& operator^=(intvec const& x) { return *this=*this^x; }
+
+
+
+ intvec lsr(int_t n) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ vlo = _mm_srli_epi32(vlo, n);
+ vhi = _mm_srli_epi32(vhi, n);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec operator>>(int_t n) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ // There is no _mm_srai_epi32. To emulate it, add 0x80000000
+ // before shifting, and subtract the shifted 0x80000000 after
+ // shifting
+ // Convert signed to unsiged
+ vlo += _mm_set1_epi32(U(1) << (bits-1));
+ vhi += _mm_set1_epi32(U(1) << (bits-1));
+ // Shift
+ vlo = _mm_srli_epi32(vlo, n);
+ vhi = _mm_srli_epi32(vhi, n);
+ // Undo conversion
+ vlo -= _mm_set1_epi32(U(1) << (bits-n));
+ vhi -= _mm_set1_epi32(U(1) << (bits-n));
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec operator<<(int_t n) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ vlo = _mm_slli_epi32(vlo, n);
+ vhi = _mm_slli_epi32(vhi, n);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec& operator>>=(int_t n) { return *this=*this>>n; }
+ intvec& operator<<=(int_t n) { return *this=*this<<n; }
+
+ intvec lsr(intvec n) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i nvlo = _mm256_castsi256_si128(n.v);
+ __m128i nvhi = _mm256_extractf128_si256(n.v, 1);
+ vlo = _mm_srl_epi32(vlo, nvlo);
+ vhi = _mm_srl_epi32(vhi, nvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec operator>>(intvec n) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i nvlo = _mm256_castsi256_si128(n.v);
+ __m128i nvhi = _mm256_extractf128_si256(n.v, 1);
+ // Convert signed to unsiged
+ vlo += _mm_set1_epi32(U(1) << (bits-1));
+ vhi += _mm_set1_epi32(U(1) << (bits-1));
+ // Shift
+ vlo = _mm_srl_epi32(vlo, nvlo);
+ vhi = _mm_srl_epi32(vhi, nvhi);
+ // Undo conversion
+ vlo -= _mm_sll_epi32(_mm_set1_epi32(1),
+ _mm_sub_epi32(_mm_set1_epi32(bits), nvlo));
+ vhi -= _mm_sll_epi32(_mm_set1_epi32(1),
+ _mm_sub_epi32(_mm_set1_epi32(bits), nvhi));
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec operator<<(intvec n) const
+ {
+ __m128i vlo = _mm256_castsi256_si128(v);
+ __m128i vhi = _mm256_extractf128_si256(v, 1);
+ __m128i nvlo = _mm256_castsi256_si128(n.v);
+ __m128i nvhi = _mm256_extractf128_si256(n.v, 1);
+ vlo = _mm_sll_epi32(vlo, nvlo);
+ vhi = _mm_sll_epi32(vhi, nvhi);
+ return _mm256_insertf128_si256(_mm256_castsi128_si256(vlo), vhi, 1);
+ }
+ intvec& operator>>=(intvec n) { return *this=*this>>n; }
+ intvec& operator<<=(intvec n) { return *this=*this<<n; }
+ };
+
+
+
+ template<>
+ struct realvec<float,8>: floatprops<float>
+ {
+ static int const size = 8;
+ typedef real_t scalar_t;
+ typedef __m256 vector_t;
+
+ static constexpr char const* const name = "<AVX:8*float>";
+ inline void barrier() { asm("": "+x" (v)); }
+
+ static_assert(size * sizeof(real_t) == sizeof(vector_t),
+ "vector size is wrong");
+
+ typedef boolvec<real_t, size> boolvec_t;
+ typedef intvec<real_t, size> intvec_t;
+ typedef realvec realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ vector_t v;
+
+ realvec() {}
+ realvec(realvec const& x): v(x.v) {}
+ realvec& operator=(realvec const& x) { return v=x.v, *this; }
+ realvec(vector_t x): v(x) {}
+ realvec(real_t a): v(_mm256_set1_ps(a)) {}
+ realvec(real_t const* as): v(_mm256_set_ps(as[7], as[6], as[5], as[4],
+ as[3], as[2], as[1], as[0])) {}
+
+ operator vector_t() const { return v; }
+ real_t operator[](int n) const { return ((real_t const*)&v)[n]; }
+ realvec& set_elt(int n, real_t a) { return ((real_t*)&v)[n]=a, *this; }
+
+
+
+ intvec_t as_int() const { return _mm256_castps_si256(v); }
+ intvec_t convert_int() const { return _mm256_cvtps_epi32(v); }
+
+
+
+ realvec operator+() const { return *this; }
+ realvec operator-() const { return RV(0.0) - *this; }
+
+ realvec operator+(realvec x) const { return _mm256_add_ps(v, x.v); }
+ realvec operator-(realvec x) const { return _mm256_sub_ps(v, x.v); }
+ realvec operator*(realvec x) const { return _mm256_mul_ps(v, x.v); }
+ realvec operator/(realvec x) const { return _mm256_div_ps(v, x.v); }
+
+ realvec& operator+=(realvec const& x) { return *this=*this+x; }
+ realvec& operator-=(realvec const& x) { return *this=*this-x; }
+ realvec& operator*=(realvec const& x) { return *this=*this*x; }
+ realvec& operator/=(realvec const& x) { return *this=*this/x; }
+
+ real_t prod() const
+ {
+ return (*this)[0] * (*this)[1] * (*this)[2] * (*this)[3];
+ }
+ real_t sum() const
+ {
+ return (*this)[0] + (*this)[1] + (*this)[2] + (*this)[3];
+ }
+
+
+
+ boolvec_t operator==(realvec const& x) const
+ {
+ return _mm256_cmp_ps(v, x.v, _CMP_EQ_OQ);
+ }
+ boolvec_t operator!=(realvec const& x) const
+ {
+ return _mm256_cmp_ps(v, x.v, _CMP_NEQ_OQ);
+ }
+ boolvec_t operator<(realvec const& x) const
+ {
+ return _mm256_cmp_ps(v, x.v, _CMP_LT_OQ);
+ }
+ boolvec_t operator<=(realvec const& x) const
+ {
+ return _mm256_cmp_ps(v, x.v, _CMP_LE_OQ);
+ }
+ boolvec_t operator>(realvec const& x) const
+ {
+ return _mm256_cmp_ps(v, x.v, _CMP_GT_OQ);
+ }
+ boolvec_t operator>=(realvec const& x) const
+ {
+ return _mm256_cmp_ps(v, x.v, _CMP_GE_OQ);
+ }
+
+
+
+ realvec acos() const { return MF::vml_acos(*this); }
+ realvec acosh() const { return MF::vml_acosh(*this); }
+ realvec asin() const { return MF::vml_asin(*this); }
+ realvec asinh() const { return MF::vml_asinh(*this); }
+ realvec atan() const { return MF::vml_atan(*this); }
+ realvec atanh() const { return MF::vml_atanh(*this); }
+ realvec ceil() const { return _mm256_ceil_ps(v); }
+ realvec copysign(realvec y) const { return MF::vml_copysign(*this, y); }
+ realvec cos() const { return MF::vml_cos(*this); }
+ realvec cosh() const { return MF::vml_cosh(*this); }
+ realvec exp() const { return MF::vml_exp(*this); }
+ realvec exp10() const { return MF::vml_exp10(*this); }
+ realvec exp2() const { return MF::vml_exp2(*this); }
+ realvec expm1() const { return MF::vml_expm1(*this); }
+ realvec fabs() const { return MF::vml_fabs(*this); }
+ realvec floor() const { return _mm256_floor_ps(v); }
+ realvec fmod(realvec y) const { return MF::vml_fmod(*this, y); }
+ intvec_t ilogb() const { return MF::vml_ilogb(*this); }
+ realvec log() const { return MF::vml_log(*this); }
+ realvec log10() const { return MF::vml_log10(*this); }
+ realvec log1p() const { return MF::vml_log1p(*this); }
+ realvec log2() const { return MF::vml_log2(*this); }
+ realvec pow(realvec y) const { return MF::vml_pow(*this, y); }
+ realvec rcp() const
+ {
+ realvec x = *this;
+ realvec r = _mm256_rcp_ps(x); // this is only an approximation
+ r *= RV(2.0) - r*x; // one Newton iteration (see vml_rcp)
+ return r;
+ }
+ realvec remainder(realvec y) const { return MF::vml_remainder(*this, y); }
+ realvec round() const { return _mm256_round_ps(v, _MM_FROUND_NINT); }
+ realvec rsqrt() const
+ {
+ realvec x = *this;
+ realvec r = _mm256_rsqrt_ps(x); // this is only an approximation
+ r *= RV(1.5) - RV(0.5)*x * r*r; // one Newton iteration (see vml_rsqrt)
+ return r;
+ }
+ realvec scalbn(intvec_t n) const { return MF::vml_scalbn(*this, n); }
+ boolvec_t signbit() const { return v; }
+ realvec sin() const { return MF::vml_sin(*this); }
+ realvec sinh() const { return MF::vml_sinh(*this); }
+ realvec sqrt() const { return _mm256_sqrt_ps(v); }
+ realvec tan() const { return MF::vml_tan(*this); }
+ realvec tanh() const { return MF::vml_tanh(*this); }
+ };
+
+
+
+ // boolvec definitions
+
+ inline
+ auto boolvec<float,8>::as_int() const -> intvec_t
+ {
+ return _mm256_castps_si256(v);
+ }
+
+ inline
+ auto boolvec<float,8>::convert_int() const -> intvec_t
+ {
+ return lsr(as_int(), bits-1);
+ }
+
+ inline
+ auto boolvec<float,8>::ifthen(intvec_t x, intvec_t y) const -> intvec_t
+ {
+ return ifthen(x.as_float(), y.as_float()).as_int();
+ }
+
+ inline
+ auto boolvec<float,8>::ifthen(realvec_t x, realvec_t y) const -> realvec_t
+ {
+ return _mm256_blendv_ps(y.v, x.v, v);
+ }
+
+
+
+ // intvec definitions
+
+ inline auto intvec<float,8>::as_float() const -> realvec_t
+ {
+ return _mm256_castsi256_ps(v);
+ }
+
+ inline auto intvec<float,8>::convert_float() const -> realvec_t
+ {
+ return _mm256_cvtepi32_ps(v);
+ }
+
+} // namespace vecmathlib
+
+#endif // #ifndef VEC_FLOAT_AVX_H
diff --git a/vec_float_sse2.h b/vec_float_sse2.h
new file mode 100644
index 0000000..f99eae8
--- /dev/null
+++ b/vec_float_sse2.h
@@ -0,0 +1,415 @@
+// -*-C++-*-
+
+#ifndef VEC_FLOAT_SSE2_H
+#define VEC_FLOAT_SSE2_H
+
+#include "floatprops.h"
+#include "mathfuncs.h"
+#include "vec_base.h"
+
+#include <cmath>
+
+// SSE2 intrinsics
+#include <xmmintrin.h>
+#if defined __SSE4_1__ // Intel's SSE 4.1
+# include <smmintrin.h>
+#endif
+#if defined __SSE4A__ // AMD's SSE 4a
+# include <ammintrin.h>
+#endif
+
+
+
+namespace vecmathlib {
+
+ template<> struct boolvec<float,4>;
+ template<> struct intvec<float,4>;
+ template<> struct realvec<float,4>;
+
+
+
+ template<>
+ struct boolvec<float,4>: floatprops<float>
+ {
+ static int const size = 4;
+ typedef bool scalar_t;
+ typedef __m128 bvector_t;
+
+ static_assert(size * sizeof(real_t) == sizeof(bvector_t),
+ "vector size is wrong");
+
+ private:
+ // true values have the sign bit set, false values have it unset
+ static uint_t from_bool(bool a) { return - uint_t(a); }
+ static bool to_bool(uint_t a) { return int_t(a) < int_t(0); }
+ public:
+
+ typedef boolvec boolvec_t;
+ typedef intvec<real_t, size> intvec_t;
+ typedef realvec<real_t, size> realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ bvector_t v;
+
+ boolvec() {}
+ boolvec(boolvec const& x): v(x.v) {}
+ boolvec& operator=(boolvec const& x) { return v=x.v, *this; }
+ boolvec(bvector_t x): v(x) {}
+ boolvec(bool a):
+ v(_mm_castsi128_ps(_mm_set1_epi32(from_bool(a)))) {}
+ boolvec(bool const* as):
+ v(_mm_castsi128_ps(_mm_set_epi32(from_bool(as[3]),
+ from_bool(as[2]),
+ from_bool(as[1]),
+ from_bool(as[0])))) {}
+
+ operator bvector_t() const { return v; }
+ bool operator[](int n) const { return to_bool(((uint_t const*)&v)[n]); }
+ boolvec& set_elt(int n, bool a)
+ {
+ return ((int_t*)&v)[n] = from_bool(a), *this;
+ }
+
+
+
+ auto as_int() const -> intvec_t; // defined after intvec
+ auto convert_int() const -> intvec_t; // defined after intvec
+
+
+
+ boolvec operator!() const { return _mm_xor_ps(boolvec(true), v); }
+
+ boolvec operator&&(boolvec x) const { return _mm_and_ps(v, x.v); }
+ boolvec operator||(boolvec x) const { return _mm_or_ps(v, x.v); }
+ boolvec operator==(boolvec x) const { return !(*this==x); }
+ boolvec operator!=(boolvec x) const { return _mm_xor_ps(v, x.v); }
+
+ bool all() const
+ {
+ return (*this)[0] && (*this)[1] && (*this)[2] && (*this)[3];
+ }
+ bool any() const
+ {
+ return (*this)[0] || (*this)[1] || (*this)[2] || (*this)[3];
+ }
+
+
+
+ // ifthen(condition, then-value, else-value)
+ auto ifthen(intvec_t x,
+ intvec_t y) const -> intvec_t; // defined after intvec
+ auto ifthen(realvec_t x,
+ realvec_t y) const -> realvec_t; // defined after realvec
+
+ };
+
+
+
+ template<>
+ struct intvec<float,4>: floatprops<float>
+ {
+ static int const size = 4;
+ typedef int_t scalar_t;
+ typedef __m128i ivector_t;
+
+ static_assert(size * sizeof(real_t) == sizeof(ivector_t),
+ "vector size is wrong");
+
+ typedef boolvec<real_t, size> boolvec_t;
+ typedef intvec intvec_t;
+ typedef realvec<real_t, size> realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ ivector_t v;
+
+ intvec() {}
+ intvec(intvec const& x): v(x.v) {}
+ intvec& operator=(intvec const& x) { return v=x.v, *this; }
+ intvec(ivector_t x): v(x) {}
+ intvec(int_t a): v(_mm_set1_epi32(a)) {}
+ intvec(int_t const* as): v(_mm_set_epi32(as[3], as[2], as[1], as[0])) {}
+
+ operator ivector_t() const { return v; }
+ int_t operator[](int n) const { return ((int_t const*)&v)[n]; }
+ intvec& set_elt(int n, int_t a) { return ((int_t*)&v)[n]=a, *this; }
+
+
+
+ auto as_bool() const -> boolvec_t { return _mm_castsi128_ps(v); }
+ auto convert_bool() const -> boolvec_t
+ {
+ // Result: convert_bool(0)=false, convert_bool(else)=true
+ return ! IV(_mm_cmpeq_epi32(v, IV(0))).as_bool();
+ }
+ auto as_float() const -> realvec_t; // defined after realvec
+ auto convert_float() const -> realvec_t; // defined after realvec
+
+
+
+ // Note: not all arithmetic operations are supported!
+
+ intvec operator+() const { return *this; }
+ intvec operator-() const { return IV(0) - *this; }
+
+ intvec operator+(intvec x) const { return _mm_add_epi32(v, x.v); }
+ intvec operator-(intvec x) const { return _mm_sub_epi32(v, x.v); }
+
+ intvec& operator+=(intvec const& x) { return *this=*this+x; }
+ intvec& operator-=(intvec const& x) { return *this=*this-x; }
+
+
+
+ intvec operator~() const { return IV(~U(0)) ^ *this; }
+
+ intvec operator&(intvec x) const
+ {
+ return _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(v),
+ _mm_castsi128_ps(x.v)));
+ }
+ intvec operator|(intvec x) const
+ {
+ return _mm_castps_si128(_mm_or_ps(_mm_castsi128_ps(v),
+ _mm_castsi128_ps(x.v)));
+ }
+ intvec operator^(intvec x) const
+ {
+ return _mm_castps_si128(_mm_xor_ps(_mm_castsi128_ps(v),
+ _mm_castsi128_ps(x.v)));
+ }
+
+ intvec& operator&=(intvec const& x) { return *this=*this&x; }
+ intvec& operator|=(intvec const& x) { return *this=*this|x; }
+ intvec& operator^=(intvec const& x) { return *this=*this^x; }
+
+
+
+ intvec lsr(int_t n) const { return _mm_srli_epi32(v, n); }
+ intvec operator>>(int_t n) const { return _mm_srai_epi32(v, n); }
+ intvec operator<<(int_t n) const { return _mm_slli_epi32(v, n); }
+ intvec& operator>>=(int_t n) { return *this=*this>>n; }
+ intvec& operator<<=(int_t n) { return *this=*this<<n; }
+
+ intvec lsr(intvec n) const { return _mm_srl_epi32(v, n.v); }
+ intvec operator>>(intvec n) const { return _mm_sra_epi32(v, n.v); }
+ intvec operator<<(intvec n) const { return _mm_sll_epi32(v, n.v); }
+ intvec& operator>>=(intvec n) { return *this=*this>>n; }
+ intvec& operator<<=(intvec n) { return *this=*this<<n; }
+ };
+
+
+
+ template<>
+ struct realvec<float,4>: floatprops<float>
+ {
+ static int const size = 4;
+ typedef real_t scalar_t;
+ typedef __m128 vector_t;
+
+ static constexpr char const* const name = "<SSE2:4*float>";
+ inline void barrier() { asm("": "+x" (v)); }
+
+ static_assert(size * sizeof(real_t) == sizeof(vector_t),
+ "vector size is wrong");
+
+ typedef boolvec<real_t, size> boolvec_t;
+ typedef intvec<real_t, size> intvec_t;
+ typedef realvec realvec_t;
+
+ // Short names for type casts
+ typedef real_t R;
+ typedef int_t I;
+ typedef uint_t U;
+ typedef realvec_t RV;
+ typedef intvec_t IV;
+ typedef boolvec_t BV;
+ typedef floatprops<real_t> FP;
+ typedef mathfuncs<realvec_t> MF;
+
+
+
+ vector_t v;
+
+ realvec() {}
+ realvec(realvec const& x): v(x.v) {}
+ realvec& operator=(realvec const& x) { return v=x.v, *this; }
+ realvec(vector_t x): v(x) {}
+ realvec(real_t a): v(_mm_set1_ps(a)) {}
+ realvec(real_t const* as): v(_mm_set_ps(as[3], as[2], as[1], as[0])) {}
+
+ operator vector_t() const { return v; }
+ real_t operator[](int n) const { return ((real_t const*)&v)[n]; }
+ realvec& set_elt(int n, real_t a) { return ((real_t*)&v)[n]=a, *this; }
+
+
+
+ intvec_t as_int() const { return _mm_castps_si128(v); }
+ intvec_t convert_int() const { return _mm_cvtps_epi32(v); }
+
+
+
+ realvec operator+() const { return *this; }
+ realvec operator-() const { return RV(0.0) - *this; }
+
+ realvec operator+(realvec x) const { return _mm_add_ps(v, x.v); }
+ realvec operator-(realvec x) const { return _mm_sub_ps(v, x.v); }
+ realvec operator*(realvec x) const { return _mm_mul_ps(v, x.v); }
+ realvec operator/(realvec x) const { return _mm_div_ps(v, x.v); }
+
+ realvec& operator+=(realvec const& x) { return *this=*this+x; }
+ realvec& operator-=(realvec const& x) { return *this=*this-x; }
+ realvec& operator*=(realvec const& x) { return *this=*this*x; }
+ realvec& operator/=(realvec const& x) { return *this=*this/x; }
+
+ real_t prod() const
+ {
+ return (*this)[0] * (*this)[1] * (*this)[2] * (*this)[3];
+ }
+ real_t sum() const
+ {
+ return (*this)[0] + (*this)[1] + (*this)[2] + (*this)[3];
+ }
+
+
+
+ boolvec_t operator==(realvec const& x) const
+ {
+ return _mm_cmpeq_ps(v, x.v);
+ }
+ boolvec_t operator!=(realvec const& x) const
+ {
+ return _mm_cmpneq_ps(v, x.v);
+ }
+ boolvec_t operator<(realvec const& x) const
+ {
+ return _mm_cmplt_ps(v, x.v);
+ }
+ boolvec_t operator<=(realvec const& x) const
+ {
+ return _mm_cmple_ps(v, x.v);
+ }
+ boolvec_t operator>(realvec const& x) const
+ {
+ return _mm_cmpgt_ps(v, x.v);
+ }
+ boolvec_t operator>=(realvec const& x) const
+ {
+ return _mm_cmpge_ps(v, x.v);
+ }
+
+
+
+ realvec acos() const { return MF::vml_acos(*this); }
+ realvec acosh() const { return MF::vml_acosh(*this); }
+ realvec asin() const { return MF::vml_asin(*this); }
+ realvec asinh() const { return MF::vml_asinh(*this); }
+ realvec atan() const { return MF::vml_atan(*this); }
+ realvec atanh() const { return MF::vml_atanh(*this); }
+ realvec ceil() const { return _mm_ceil_ps(v); }
+ realvec copysign(realvec y) const { return MF::vml_copysign(*this, y); }
+ realvec cos() const { return MF::vml_cos(*this); }
+ realvec cosh() const { return MF::vml_cosh(*this); }
+ realvec exp() const { return MF::vml_exp(*this); }
+ realvec exp10() const { return MF::vml_exp10(*this); }
+ realvec exp2() const { return MF::vml_exp2(*this); }
+ realvec expm1() const { return MF::vml_expm1(*this); }
+ realvec fabs() const { return MF::vml_fabs(*this); }
+ realvec floor() const { return _mm_floor_ps(v); }
+ realvec fmod(realvec y) const { return MF::vml_fmod(*this, y); }
+ intvec_t ilogb() const { return MF::vml_ilogb(*this); }
+ realvec log() const { return MF::vml_log(*this); }
+ realvec log10() const { return MF::vml_log10(*this); }
+ realvec log1p() const { return MF::vml_log1p(*this); }
+ realvec log2() const { return MF::vml_log2(*this); }
+ realvec pow(realvec y) const { return MF::vml_pow(*this, y); }
+ realvec rcp() const
+ {
+ realvec x = *this;
+ realvec r = _mm_rcp_ps(x); // this is only an approximation
+ r *= RV(2.0) - r*x; // one Newton iteration (see vml_rcp)
+ return r;
+ }
+ realvec remainder(realvec y) const { return MF::vml_remainder(*this, y); }
+ realvec round() const { return _mm_round_ps(v, _MM_FROUND_NINT); }
+ realvec rsqrt() const
+ {
+ realvec x = *this;
+ realvec r = _mm_rsqrt_ps(x); // this is only an approximation
+ r *= RV(1.5) - RV(0.5)*x * r*r; // one Newton iteration (see vml_rsqrt)
+ return r;
+ }
+ realvec scalbn(intvec_t n) const { return MF::vml_scalbn(*this, n); }
+ boolvec_t signbit() const { return v; }
+ realvec sin() const { return MF::vml_sin(*this); }
+ realvec sinh() const { return MF::vml_sinh(*this); }
+ realvec sqrt() const { return _mm_sqrt_ps(v); }
+ realvec tan() const { return MF::vml_tan(*this); }
+ realvec tanh() const { return MF::vml_tanh(*this); }
+ };
+
+
+
+ // boolvec definitions
+
+ inline
+ auto boolvec<float,4>::as_int() const -> intvec_t
+ {
+ return _mm_castps_si128(v);
+ }
+
+ inline
+ auto boolvec<float,4>::convert_int() const -> intvec_t
+ {
+ return lsr(as_int(), bits-1);
+ }
+
+ inline
+ auto boolvec<float,4>::ifthen(intvec_t x, intvec_t y) const -> intvec_t
+ {
+ return ifthen(x.as_float(), y.as_float()).as_int();
+ }
+
+ inline
+ auto boolvec<float,4>::ifthen(realvec_t x, realvec_t y) const -> realvec_t
+ {
+ return _mm_blendv_ps(y.v, x.v, v);
+ }
+
+
+
+ // intvec definitions
+
+ inline auto intvec<float,4>::as_float() const -> realvec_t
+ {
+ return _mm_castsi128_ps(v);
+ }
+
+ inline auto intvec<float,4>::convert_float() const -> realvec_t
+ {
+ return _mm_cvtepi32_ps(v);
+ }
+
+} // namespace vecmathlib
+
+#endif // #ifndef VEC_FLOAT_SSE2_H
diff --git a/vecmathlib.h b/vecmathlib.h
index b5703bb..83396ad 100644
--- a/vecmathlib.h
+++ b/vecmathlib.h
@@ -4,7 +4,17 @@
#define VECMATHLIB_H
#include "vec_float.h"
+#if defined __SSE2__ // Intel SSE 2
+# include "vec_float_sse2.h"
+#endif
+#if defined __AVX__ // Intel AVX
+# include "vec_float_avx.h"
+#endif
+
#include "vec_double.h"
+#if defined __SSE2__ // Intel SSE 2
+# include "vec_double_sse2.h"
+#endif
#if defined __AVX__ // Intel AVX
# include "vec_double_avx.h"
#endif
OpenPOWER on IntegriCloud