summaryrefslogtreecommitdiffstats
path: root/vec_qpx_double4.h
diff options
context:
space:
mode:
Diffstat (limited to 'vec_qpx_double4.h')
-rw-r--r--vec_qpx_double4.h1399
1 files changed, 638 insertions, 761 deletions
diff --git a/vec_qpx_double4.h b/vec_qpx_double4.h
index 9fa6bd0..b88b0da 100644
--- a/vec_qpx_double4.h
+++ b/vec_qpx_double4.h
@@ -11,785 +11,662 @@
// QPX intrinsics
#ifdef __clang__
-# include <qpxintrin.h>
+#include <qpxintrin.h>
#else
-# include <builtins.h>
+#include <builtins.h>
#endif
#include <mass_simd.h>
-
-
namespace vecmathlib {
-
+
#define VECMATHLIB_HAVE_VEC_DOUBLE_4
- template<> struct boolvec<double,4>;
- template<> struct intvec<double,4>;
- template<> struct realvec<double,4>;
-
-
-
- template<>
- struct boolvec<double,4>: floatprops<double>
- {
- static int const size = 4;
- typedef bool scalar_t;
- typedef vector4double bvector_t;
- static int const alignment = sizeof(bvector_t);
-
- static_assert(size * sizeof(real_t) == sizeof(bvector_t),
- "vector size is wrong");
-
- private:
- // canonical true is +1.0, canonical false is -1.0
- // >=0 is true, -0 is true, nan is false
- static real_t from_bool(bool a) { return a ? +1.0 : -1.0; }
- static bool to_bool(real_t a) { return a>=0.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(bvector_t x): v(x) {}
- boolvec(bool a): v(vec_splats(from_bool(a))) {}
- boolvec(const bool* as)
- {
- for (int d=0; d<size; ++d) set_elt(d, as[d]);
- }
-
- operator bvector_t() const { return v; }
- bool operator[](int n) const
- {
- return to_bool(v[n]);
- }
- boolvec& set_elt(int n, bool a)
- {
- return v[n]=from_bool(a), *this;
- }
-
-
-
- intvec_t as_int() const; // defined after intvec
- intvec_t convert_int() const; // defined after intvec
-
-
-
- boolvec operator!() const { return vec_not(v); }
-
- boolvec operator&&(boolvec x) const { return vec_and(v, x.v); }
- boolvec operator||(boolvec x) const { return vec_or(v, x.v); }
- boolvec operator==(boolvec x) const
- {
- return vec_logical(v, x.v, 0x9);
- }
- boolvec operator!=(boolvec x) const { return vec_xor(v, x.v); }
-
- bool all() const
- {
- // return (*this)[0] && (*this)[1] && (*this)[2] && (*this)[3];
- boolvec x0123 = *this;
- boolvec x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
- boolvec y0022 = x0123 && x1032;
- return y0022[0] && y0022[2];
- }
- bool any() const
- {
- // return (*this)[0] || (*this)[1] || (*this)[2] || (*this)[3];
- boolvec x0123 = *this;
- boolvec x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
- boolvec y0022 = x0123 || x1032;
- return y0022[0] || y0022[2];
- }
-
-
-
- // ifthen(condition, then-value, else-value)
- boolvec_t ifthen(boolvec_t x, boolvec_t y) const;
- intvec_t ifthen(intvec_t x, intvec_t y) const; // defined after intvec
- realvec_t ifthen(realvec_t x, realvec_t y) const; // defined after realvec
- };
-
-
-
- template<>
- struct intvec<double,4>: floatprops<double>
- {
- static int const size = 4;
- typedef int_t scalar_t;
- typedef vector4double ivector_t;
- static int const alignment = sizeof(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() {}
- // Can't have a non-trivial copy constructor; if so, objects won't
- // be passed in registers
- // intvec(const intvec& x): v(x.v) {}
- // intvec& operator=(const intvec& x) { return v=x.v, *this; }
- intvec(ivector_t x): v(x) {}
- intvec(int_t a): v(vec_splats(FP::as_float(a))) {}
- intvec(const int_t* as)
- {
- for (int d=0; d<size; ++d) set_elt(d, as[d]);
- }
- static intvec iota()
- {
- const int_t iota_[] = {0, 1, 2, 3};
- return intvec(iota_);
- }
-
- operator ivector_t() const { return v; }
- int_t operator[](int n) const
- {
- return FP::as_int(v[n]);
- }
- intvec& set_elt(int n, int_t a)
- {
- return v[n]=FP::as_float(a), *this;
- }
-
-
-
- // Vector casts do not change the bit battern
- boolvec_t as_bool() const { return v; }
- boolvec_t convert_bool() const { return *this != IV(I(0)); }
- realvec_t as_float() const; // defined after realvec
- realvec_t convert_float() const; // defined after realvec
-
-
-
- intvec operator+() const { return *this; }
- intvec operator-() const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, -(*this)[d]);
- return r;
- }
-
- intvec operator+(intvec x) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] + x[d]);
- return r;
- }
- intvec operator-(intvec x) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] - x[d]);
- return r;
- }
-
- intvec& operator+=(intvec x) { return *this=*this+x; }
- intvec& operator-=(intvec x) { return *this=*this-x; }
-
-
-
- intvec operator~() const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, ~(*this)[d]);
- return r;
- }
-
- intvec operator&(intvec x) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] & x[d]);
- return r;
- }
- intvec operator|(intvec x) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] | x[d]);
- return r;
- }
- intvec operator^(intvec x) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] ^ x[d]);
- return r;
- }
-
- intvec& operator&=(intvec x) { return *this=*this&x; }
- intvec& operator|=(intvec x) { return *this=*this|x; }
- intvec& operator^=(intvec x) { return *this=*this^x; }
-
- intvec_t bitifthen(intvec_t x, intvec_t y) const;
-
-
-
- intvec_t lsr(int_t n) const
- {
- intvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, U((*this)[d]) >> U(n));
- return r;
- }
- intvec_t rotate(int_t n) const;
- intvec operator>>(int_t n) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] >> n);
- return r;
- }
- intvec operator<<(int_t n) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] << n);
- return r;
- }
- intvec& operator>>=(int_t n) { return *this=*this>>n; }
- intvec& operator<<=(int_t n) { return *this=*this<<n; }
-
- intvec_t lsr(intvec_t n) const
- {
- intvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, U((*this)[d]) >> U(n[d]));
- return r;
- }
- intvec_t rotate(intvec_t n) const;
- intvec operator>>(intvec n) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] >> n[d]);
- return r;
- }
- intvec operator<<(intvec n) const
- {
- intvec r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] << n[d]);
- return r;
- }
- intvec& operator>>=(intvec n) { return *this=*this>>n; }
- intvec& operator<<=(intvec n) { return *this=*this<<n; }
-
- intvec_t clz() const;
- intvec_t popcount() const;
-
-
-
- boolvec_t operator==(intvec x) const
- {
- boolvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] == x[d]);
- return r;
- }
- boolvec_t operator!=(intvec x) const
- {
- boolvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] != x[d]);
- return r;
- }
- boolvec_t operator<(intvec x) const
- {
- boolvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] < x[d]);
- return r;
- }
- boolvec_t operator<=(intvec x) const
- {
- boolvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] <= x[d]);
- return r;
- }
- boolvec_t operator>(intvec x) const
- {
- boolvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] > x[d]);
- return r;
- }
- boolvec_t operator>=(intvec x) const
- {
- boolvec_t r;
- for (int d=0; d<size; ++d) r.set_elt(d, (*this)[d] >= x[d]);
- return r;
- }
-
- intvec_t abs() const;
- boolvec_t isignbit() const;
- intvec_t max(intvec_t x) const;
- intvec_t min(intvec_t x) const;
- };
-
-
-
- template<>
- struct realvec<double,4>: floatprops<double>
- {
- static int const size = 4;
- typedef real_t scalar_t;
- typedef vector4double vector_t;
- static int const alignment = sizeof(vector_t);
-
- static const char* name() { return "<QPX:4*double>"; }
- void barrier() { __asm__("": "+v"(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() {}
- // Can't have a non-trivial copy constructor; if so, objects won't
- // be passed in registers
- // realvec(const realvec& x): v(x.v) {}
- // realvec& operator=(const realvec& x) { return v=x.v, *this; }
- realvec(vector_t x): v(x) {}
- realvec(real_t a): v(vec_splats(a)) {}
- realvec(const real_t* as)
- {
- for (int d=0; d<size; ++d) set_elt(d, as[d]);
- }
-
- operator vector_t() const { return v; }
- real_t operator[](int n) const
- {
- return v[n];
- }
- realvec& set_elt(int n, real_t a)
- {
- return v[n]=a, *this;
- }
-
-
-
- typedef vecmathlib::mask_t<realvec_t> mask_t;
-
- static realvec_t loada(const real_t* p)
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- return vec_lda(0, (real_t*)p);
- }
- static realvec_t loadu(const real_t* p)
- {
- realvec_t v0 = vec_ld(0, (real_t*)p);
- realvec_t v1 = vec_ld(31, (real_t*)p);
- return vec_perm(v0.v, v1.v, vec_lvsl(0, (real_t*)p));
- }
- static realvec_t loadu(const real_t* p, std::ptrdiff_t ioff)
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- if (ioff % realvec::size == 0) return loada(p+ioff);
- // TODO: use load instruction with fixed offset
- return loadu(p+ioff);
- }
- realvec_t loada(const real_t* p, mask_t m) const
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- if (__builtin_expect(all(m.m), true)) {
- return loada(p);
- } else {
- return m.m.ifthen(loada(p), *this);
- }
- }
- realvec_t loadu(const real_t* p, mask_t m) const
- {
- if (__builtin_expect(m.all_m, true)) {
- return loadu(p);
- } else {
- return m.m.ifthen(loadu(p), *this);
- }
- }
- realvec_t loadu(const real_t* p, std::ptrdiff_t ioff, mask_t m) const
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- if (ioff % realvec::size == 0) return loada(p+ioff, m);
- // TODO: use load instruction with fixed offset
- return loadu(p+ioff, m);
- }
-
- void storea(real_t* p) const
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- vec_sta(v, 0, p);
- }
- void storeu(real_t* p) const
- {
- // Vector stores would require vector loads, which would need to
- // be atomic
- // TODO: see <https://developer.apple.com/hardwaredrivers/ve/alignment.html> for good ideas
- p[0] = (*this)[0];
- p[1] = (*this)[1];
- p[2] = (*this)[2];
- p[3] = (*this)[3];
- }
- void storeu(real_t* p, std::ptrdiff_t ioff) const
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- if (ioff % realvec::size == 0) return storea(p+ioff);
- storeu(p+ioff);
- }
- void storea(real_t* p, mask_t m) const
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- if (__builtin_expect(m.all_m, true)) {
- storea(p);
- } else {
- if (m.m[0]) p[0] = (*this)[0];
- if (m.m[1]) p[1] = (*this)[1];
- if (m.m[2]) p[2] = (*this)[2];
- if (m.m[3]) p[3] = (*this)[3];
- }
- }
- void storeu(real_t* p, mask_t m) const
- {
- if (__builtin_expect(m.all_m, true)) {
- storeu(p);
- } else {
- if (m.m[0]) p[0] = (*this)[0];
- if (m.m[1]) p[1] = (*this)[1];
- if (m.m[2]) p[2] = (*this)[2];
- if (m.m[3]) p[3] = (*this)[3];
- }
- }
- void storeu(real_t* p, std::ptrdiff_t ioff, mask_t m) const
- {
- VML_ASSERT(intptr_t(p) % alignment == 0);
- if (ioff % realvec::size == 0) return storea(p+ioff, m);
- storeu(p+ioff, m);
- }
-
-
-
- intvec_t as_int() const { return v; }
- intvec_t convert_int() const { return vec_ctidz(v); }
-
-
-
- realvec operator+() const { return *this; }
- realvec operator-() const { return vec_neg(v); }
-
- realvec operator+(realvec x) const { return vec_add(v, x.v); }
- realvec operator-(realvec x) const { return vec_sub(v, x.v); }
- realvec operator*(realvec x) const { return vec_mul(v, x.v); }
- realvec operator/(realvec x) const
- {
- // return vec_swdiv_nochk(v, x.v);
- return div_fastd4(v, x.v);
- }
-
- realvec& operator+=(realvec x) { return *this=*this+x; }
- realvec& operator-=(realvec x) { return *this=*this-x; }
- realvec& operator*=(realvec x) { return *this=*this*x; }
- realvec& operator/=(realvec x) { return *this=*this/x; }
-
- real_t maxval() const
- {
- // return vml_std::fmax(vml_std::fmax((*this)[0], (*this)[1]),
- // vml_std::fmax((*this)[2], (*this)[3]));
- realvec_t x0123 = *this;
- realvec_t x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
- realvec_t y0022 = x0123.fmax(x1032);
- return vml_std::fmax(y0022[0], y0022[2]);
+template <> struct boolvec<double, 4>;
+template <> struct intvec<double, 4>;
+template <> struct realvec<double, 4>;
+
+template <> struct boolvec<double, 4> : floatprops<double> {
+ static int const size = 4;
+ typedef bool scalar_t;
+ typedef vector4double bvector_t;
+ static int const alignment = sizeof(bvector_t);
+
+ static_assert(size * sizeof(real_t) == sizeof(bvector_t),
+ "vector size is wrong");
+
+private:
+ // canonical true is +1.0, canonical false is -1.0
+ // >=0 is true, -0 is true, nan is false
+ static real_t from_bool(bool a) { return a ? +1.0 : -1.0; }
+ static bool to_bool(real_t a) { return a >= 0.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(bvector_t x) : v(x) {}
+ boolvec(bool a) : v(vec_splats(from_bool(a))) {}
+ boolvec(const bool *as) {
+ for (int d = 0; d < size; ++d)
+ set_elt(d, as[d]);
+ }
+
+ operator bvector_t() const { return v; }
+ bool operator[](int n) const { return to_bool(v[n]); }
+ boolvec &set_elt(int n, bool a) { return v[n] = from_bool(a), *this; }
+
+ intvec_t as_int() const; // defined after intvec
+ intvec_t convert_int() const; // defined after intvec
+
+ boolvec operator!() const { return vec_not(v); }
+
+ boolvec operator&&(boolvec x) const { return vec_and(v, x.v); }
+ boolvec operator||(boolvec x) const { return vec_or(v, x.v); }
+ boolvec operator==(boolvec x) const { return vec_logical(v, x.v, 0x9); }
+ boolvec operator!=(boolvec x) const { return vec_xor(v, x.v); }
+
+ bool all() const {
+ // return (*this)[0] && (*this)[1] && (*this)[2] && (*this)[3];
+ boolvec x0123 = *this;
+ boolvec x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
+ boolvec y0022 = x0123 && x1032;
+ return y0022[0] && y0022[2];
+ }
+ bool any() const {
+ // return (*this)[0] || (*this)[1] || (*this)[2] || (*this)[3];
+ boolvec x0123 = *this;
+ boolvec x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
+ boolvec y0022 = x0123 || x1032;
+ return y0022[0] || y0022[2];
+ }
+
+ // ifthen(condition, then-value, else-value)
+ boolvec_t ifthen(boolvec_t x, boolvec_t y) const;
+ intvec_t ifthen(intvec_t x, intvec_t y) const; // defined after intvec
+ realvec_t ifthen(realvec_t x, realvec_t y) const; // defined after realvec
+};
+
+template <> struct intvec<double, 4> : floatprops<double> {
+ static int const size = 4;
+ typedef int_t scalar_t;
+ typedef vector4double ivector_t;
+ static int const alignment = sizeof(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() {}
+ // Can't have a non-trivial copy constructor; if so, objects won't
+ // be passed in registers
+ // intvec(const intvec& x): v(x.v) {}
+ // intvec& operator=(const intvec& x) { return v=x.v, *this; }
+ intvec(ivector_t x) : v(x) {}
+ intvec(int_t a) : v(vec_splats(FP::as_float(a))) {}
+ intvec(const int_t *as) {
+ for (int d = 0; d < size; ++d)
+ set_elt(d, as[d]);
+ }
+ static intvec iota() {
+ const int_t iota_[] = {0, 1, 2, 3};
+ return intvec(iota_);
+ }
+
+ operator ivector_t() const { return v; }
+ int_t operator[](int n) const { return FP::as_int(v[n]); }
+ intvec &set_elt(int n, int_t a) { return v[n] = FP::as_float(a), *this; }
+
+ // Vector casts do not change the bit battern
+ boolvec_t as_bool() const { return v; }
+ boolvec_t convert_bool() const { return *this != IV(I(0)); }
+ realvec_t as_float() const; // defined after realvec
+ realvec_t convert_float() const; // defined after realvec
+
+ intvec operator+() const { return *this; }
+ intvec operator-() const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, -(*this)[d]);
+ return r;
+ }
+
+ intvec operator+(intvec x) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] + x[d]);
+ return r;
+ }
+ intvec operator-(intvec x) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] - x[d]);
+ return r;
+ }
+
+ intvec &operator+=(intvec x) { return *this = *this + x; }
+ intvec &operator-=(intvec x) { return *this = *this - x; }
+
+ intvec operator~() const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, ~(*this)[d]);
+ return r;
+ }
+
+ intvec operator&(intvec x) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] & x[d]);
+ return r;
+ }
+ intvec operator|(intvec x) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] | x[d]);
+ return r;
+ }
+ intvec operator^(intvec x) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] ^ x[d]);
+ return r;
+ }
+
+ intvec &operator&=(intvec x) { return *this = *this & x; }
+ intvec &operator|=(intvec x) { return *this = *this | x; }
+ intvec &operator^=(intvec x) { return *this = *this ^ x; }
+
+ intvec_t bitifthen(intvec_t x, intvec_t y) const;
+
+ intvec_t lsr(int_t n) const {
+ intvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, U((*this)[d]) >> U(n));
+ return r;
+ }
+ intvec_t rotate(int_t n) const;
+ intvec operator>>(int_t n) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] >> n);
+ return r;
+ }
+ intvec operator<<(int_t n) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] << n);
+ return r;
+ }
+ intvec &operator>>=(int_t n) { return *this = *this >> n; }
+ intvec &operator<<=(int_t n) { return *this = *this << n; }
+
+ intvec_t lsr(intvec_t n) const {
+ intvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, U((*this)[d]) >> U(n[d]));
+ return r;
+ }
+ intvec_t rotate(intvec_t n) const;
+ intvec operator>>(intvec n) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] >> n[d]);
+ return r;
+ }
+ intvec operator<<(intvec n) const {
+ intvec r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] << n[d]);
+ return r;
+ }
+ intvec &operator>>=(intvec n) { return *this = *this >> n; }
+ intvec &operator<<=(intvec n) { return *this = *this << n; }
+
+ intvec_t clz() const;
+ intvec_t popcount() const;
+
+ boolvec_t operator==(intvec x) const {
+ boolvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] == x[d]);
+ return r;
+ }
+ boolvec_t operator!=(intvec x) const {
+ boolvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] != x[d]);
+ return r;
+ }
+ boolvec_t operator<(intvec x) const {
+ boolvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] < x[d]);
+ return r;
+ }
+ boolvec_t operator<=(intvec x) const {
+ boolvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] <= x[d]);
+ return r;
+ }
+ boolvec_t operator>(intvec x) const {
+ boolvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] > x[d]);
+ return r;
+ }
+ boolvec_t operator>=(intvec x) const {
+ boolvec_t r;
+ for (int d = 0; d < size; ++d)
+ r.set_elt(d, (*this)[d] >= x[d]);
+ return r;
+ }
+
+ intvec_t abs() const;
+ boolvec_t isignbit() const;
+ intvec_t max(intvec_t x) const;
+ intvec_t min(intvec_t x) const;
+};
+
+template <> struct realvec<double, 4> : floatprops<double> {
+ static int const size = 4;
+ typedef real_t scalar_t;
+ typedef vector4double vector_t;
+ static int const alignment = sizeof(vector_t);
+
+ static const char *name() { return "<QPX:4*double>"; }
+ void barrier() { __asm__("" : "+v"(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() {}
+ // Can't have a non-trivial copy constructor; if so, objects won't
+ // be passed in registers
+ // realvec(const realvec& x): v(x.v) {}
+ // realvec& operator=(const realvec& x) { return v=x.v, *this; }
+ realvec(vector_t x) : v(x) {}
+ realvec(real_t a) : v(vec_splats(a)) {}
+ realvec(const real_t *as) {
+ for (int d = 0; d < size; ++d)
+ set_elt(d, as[d]);
+ }
+
+ operator vector_t() const { return v; }
+ real_t operator[](int n) const { return v[n]; }
+ realvec &set_elt(int n, real_t a) { return v[n] = a, *this; }
+
+ typedef vecmathlib::mask_t<realvec_t> mask_t;
+
+ static realvec_t loada(const real_t *p) {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ return vec_lda(0, (real_t *)p);
+ }
+ static realvec_t loadu(const real_t *p) {
+ realvec_t v0 = vec_ld(0, (real_t *)p);
+ realvec_t v1 = vec_ld(31, (real_t *)p);
+ return vec_perm(v0.v, v1.v, vec_lvsl(0, (real_t *)p));
+ }
+ static realvec_t loadu(const real_t *p, std::ptrdiff_t ioff) {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ if (ioff % realvec::size == 0)
+ return loada(p + ioff);
+ // TODO: use load instruction with fixed offset
+ return loadu(p + ioff);
+ }
+ realvec_t loada(const real_t *p, mask_t m) const {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ if (__builtin_expect(all(m.m), true)) {
+ return loada(p);
+ } else {
+ return m.m.ifthen(loada(p), *this);
}
- real_t minval() const
- {
- // return vml_std::fmin(vml_std::fmin((*this)[0], (*this)[1]),
- // vml_std::fmin((*this)[2], (*this)[3]));
- realvec_t x0123 = *this;
- realvec_t x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
- realvec_t y0022 = x0123.fmin(x1032);
- return vml_std::fmin(y0022[0], y0022[2]);
+ }
+ realvec_t loadu(const real_t *p, mask_t m) const {
+ if (__builtin_expect(m.all_m, true)) {
+ return loadu(p);
+ } else {
+ return m.m.ifthen(loadu(p), *this);
}
- real_t prod() const
- {
- // return (*this)[0] * (*this)[1] * (*this)[2] * (*this)[3];
- realvec_t x = vec_xmul(v, v);
- return x[1] * x[3];
+ }
+ realvec_t loadu(const real_t *p, std::ptrdiff_t ioff, mask_t m) const {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ if (ioff % realvec::size == 0)
+ return loada(p + ioff, m);
+ // TODO: use load instruction with fixed offset
+ return loadu(p + ioff, m);
+ }
+
+ void storea(real_t *p) const {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ vec_sta(v, 0, p);
+ }
+ void storeu(real_t *p) const {
+ // Vector stores would require vector loads, which would need to
+ // be atomic
+ // TODO: see <https://developer.apple.com/hardwaredrivers/ve/alignment.html>
+ // for good ideas
+ p[0] = (*this)[0];
+ p[1] = (*this)[1];
+ p[2] = (*this)[2];
+ p[3] = (*this)[3];
+ }
+ void storeu(real_t *p, std::ptrdiff_t ioff) const {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ if (ioff % realvec::size == 0)
+ return storea(p + ioff);
+ storeu(p + ioff);
+ }
+ void storea(real_t *p, mask_t m) const {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ if (__builtin_expect(m.all_m, true)) {
+ storea(p);
+ } else {
+ if (m.m[0])
+ p[0] = (*this)[0];
+ if (m.m[1])
+ p[1] = (*this)[1];
+ if (m.m[2])
+ p[2] = (*this)[2];
+ if (m.m[3])
+ p[3] = (*this)[3];
}
- real_t sum() const
- {
- // return (*this)[0] + (*this)[1] + (*this)[2] + (*this)[3];
- realvec_t c1 = vec_logical(v, v, 0xf); // +1.0
- realvec_t x = vec_xxmadd(v, c1, v);
- return x[0] + x[2];
+ }
+ void storeu(real_t *p, mask_t m) const {
+ if (__builtin_expect(m.all_m, true)) {
+ storeu(p);
+ } else {
+ if (m.m[0])
+ p[0] = (*this)[0];
+ if (m.m[1])
+ p[1] = (*this)[1];
+ if (m.m[2])
+ p[2] = (*this)[2];
+ if (m.m[3])
+ p[3] = (*this)[3];
}
-
-
-
- boolvec_t operator==(realvec x) const { return vec_cmpeq(v, x.v); }
- boolvec_t operator!=(realvec x) const { return ! (*this == x); }
- boolvec_t operator<(realvec x) const { return vec_cmplt(v, x.v); }
- boolvec_t operator<=(realvec x) const
- {
+ }
+ void storeu(real_t *p, std::ptrdiff_t ioff, mask_t m) const {
+ VML_ASSERT(intptr_t(p) % alignment == 0);
+ if (ioff % realvec::size == 0)
+ return storea(p + ioff, m);
+ storeu(p + ioff, m);
+ }
+
+ intvec_t as_int() const { return v; }
+ intvec_t convert_int() const { return vec_ctidz(v); }
+
+ realvec operator+() const { return *this; }
+ realvec operator-() const { return vec_neg(v); }
+
+ realvec operator+(realvec x) const { return vec_add(v, x.v); }
+ realvec operator-(realvec x) const { return vec_sub(v, x.v); }
+ realvec operator*(realvec x) const { return vec_mul(v, x.v); }
+ realvec operator/(realvec x) const {
+ // return vec_swdiv_nochk(v, x.v);
+ return div_fastd4(v, x.v);
+ }
+
+ realvec &operator+=(realvec x) { return *this = *this + x; }
+ realvec &operator-=(realvec x) { return *this = *this - x; }
+ realvec &operator*=(realvec x) { return *this = *this * x; }
+ realvec &operator/=(realvec x) { return *this = *this / x; }
+
+ real_t maxval() const {
+ // return vml_std::fmax(vml_std::fmax((*this)[0], (*this)[1]),
+ // vml_std::fmax((*this)[2], (*this)[3]));
+ realvec_t x0123 = *this;
+ realvec_t x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
+ realvec_t y0022 = x0123.fmax(x1032);
+ return vml_std::fmax(y0022[0], y0022[2]);
+ }
+ real_t minval() const {
+ // return vml_std::fmin(vml_std::fmin((*this)[0], (*this)[1]),
+ // vml_std::fmin((*this)[2], (*this)[3]));
+ realvec_t x0123 = *this;
+ realvec_t x1032 = vec_perm(x0123, x0123, vec_gpci(01032));
+ realvec_t y0022 = x0123.fmin(x1032);
+ return vml_std::fmin(y0022[0], y0022[2]);
+ }
+ real_t prod() const {
+ // return (*this)[0] * (*this)[1] * (*this)[2] * (*this)[3];
+ realvec_t x = vec_xmul(v, v);
+ return x[1] * x[3];
+ }
+ real_t sum() const {
+ // return (*this)[0] + (*this)[1] + (*this)[2] + (*this)[3];
+ realvec_t c1 = vec_logical(v, v, 0xf); // +1.0
+ realvec_t x = vec_xxmadd(v, c1, v);
+ return x[0] + x[2];
+ }
+
+ boolvec_t operator==(realvec x) const { return vec_cmpeq(v, x.v); }
+ boolvec_t operator!=(realvec x) const { return !(*this == x); }
+ boolvec_t operator<(realvec x) const { return vec_cmplt(v, x.v); }
+ boolvec_t operator<=(realvec x) const {
#ifdef VML_HAVE_NAN
- return *this < x || *this == x;
+ return *this < x || *this == x;
#else
- return ! (*this > x);
+ return !(*this > x);
#endif
- }
- boolvec_t operator>(realvec x) const { return vec_cmpgt(v, x.v); }
- boolvec_t operator>=(realvec x) const
- {
+ }
+ boolvec_t operator>(realvec x) const { return vec_cmpgt(v, x.v); }
+ boolvec_t operator>=(realvec x) const {
#ifdef VML_HAVE_NAN
- return *this > x || *this == x;
+ return *this > x || *this == x;
#else
- return ! (*this < x);
+ return !(*this < x);
#endif
- }
-
-
-
- realvec acos() const { return acosd4(v); }
- realvec acosh() const { return acoshd4(v); }
- realvec asin() const { return asind4(v); }
- realvec asinh() const { return asinhd4(v); }
- realvec atan() const { return atand4(v); }
- realvec atan2(realvec y) const { return atan2d4(v, y.v); }
- realvec atanh() const { return atanhd4(v); }
- realvec cbrt() const { return cbrtd4(v); }
- realvec ceil() const { return vec_ceil(v); }
- realvec copysign(realvec y) const { return vec_cpsgn(y.v, v); }
- realvec cos() const { return cosd4(v); }
- realvec cosh() const { return coshd4(v); }
- realvec exp() const { return expd4(v); }
- realvec exp10() const { return exp10d4(v); }
- realvec exp2() const { return exp2d4(v); }
- realvec expm1() const { return expm1d4(v); }
- realvec fabs() const { return vec_abs(v); }
- realvec fdim(realvec y) const { return MF::vml_fdim(*this, y); }
- realvec floor() const { return vec_floor(v); }
- realvec fma(realvec y, realvec z) const
- {
- return vec_madd(v, y.v, z.v);
- }
- realvec fmax(realvec y) const { return MF::vml_fmax(v, y.v); }
- realvec fmin(realvec y) const { return MF::vml_fmin(v, y.v); }
- realvec fmod(realvec y) const { return MF::vml_fmod(*this, y); }
- realvec frexp(intvec_t* r) const { return MF::vml_frexp(*this, r); }
- realvec hypot(realvec y) const { return hypotd4(v, y.v); }
- intvec_t ilogb() const
- {
- // int_t ilogb_[] = {
- // ::ilogb((*this)[0]),
- // ::ilogb((*this)[1]),
- // ::ilogb((*this)[2]),
- // ::ilogb((*this)[3])
- // };
- // return intvec_t(ilogb_);
- return MF::vml_ilogb(v);
- }
- boolvec_t isfinite() const { return MF::vml_isfinite(*this); }
- boolvec_t isinf() const { return MF::vml_isinf(*this); }
- boolvec_t isnan() const
- {
+ }
+
+ realvec acos() const { return acosd4(v); }
+ realvec acosh() const { return acoshd4(v); }
+ realvec asin() const { return asind4(v); }
+ realvec asinh() const { return asinhd4(v); }
+ realvec atan() const { return atand4(v); }
+ realvec atan2(realvec y) const { return atan2d4(v, y.v); }
+ realvec atanh() const { return atanhd4(v); }
+ realvec cbrt() const { return cbrtd4(v); }
+ realvec ceil() const { return vec_ceil(v); }
+ realvec copysign(realvec y) const { return vec_cpsgn(y.v, v); }
+ realvec cos() const { return cosd4(v); }
+ realvec cosh() const { return coshd4(v); }
+ realvec exp() const { return expd4(v); }
+ realvec exp10() const { return exp10d4(v); }
+ realvec exp2() const { return exp2d4(v); }
+ realvec expm1() const { return expm1d4(v); }
+ realvec fabs() const { return vec_abs(v); }
+ realvec fdim(realvec y) const { return MF::vml_fdim(*this, y); }
+ realvec floor() const { return vec_floor(v); }
+ realvec fma(realvec y, realvec z) const { return vec_madd(v, y.v, z.v); }
+ realvec fmax(realvec y) const { return MF::vml_fmax(v, y.v); }
+ realvec fmin(realvec y) const { return MF::vml_fmin(v, y.v); }
+ realvec fmod(realvec y) const { return MF::vml_fmod(*this, y); }
+ realvec frexp(intvec_t *r) const { return MF::vml_frexp(*this, r); }
+ realvec hypot(realvec y) const { return hypotd4(v, y.v); }
+ intvec_t ilogb() const {
+ // int_t ilogb_[] = {
+ // ::ilogb((*this)[0]),
+ // ::ilogb((*this)[1]),
+ // ::ilogb((*this)[2]),
+ // ::ilogb((*this)[3])
+ // };
+ // return intvec_t(ilogb_);
+ return MF::vml_ilogb(v);
+ }
+ boolvec_t isfinite() const { return MF::vml_isfinite(*this); }
+ boolvec_t isinf() const { return MF::vml_isinf(*this); }
+ boolvec_t isnan() const {
#ifdef VML_HAVE_NAN
- return vec_tstnan(v, v);
+ return vec_tstnan(v, v);
#else
- return BV(false);
+ return BV(false);
#endif
- }
- boolvec_t isnormal() const { return MF::vml_isnormal(*this); }
- realvec ldexp(int_t n) const { return ldexp(intvec_t(n)); }
- realvec ldexp(intvec_t n) const
- {
- real_t ldexp_[] = {
- vml_std::ldexp((*this)[0], n[0]),
- vml_std::ldexp((*this)[1], n[1]),
- vml_std::ldexp((*this)[2], n[2]),
- vml_std::ldexp((*this)[3], n[3])
- };
- return realvec_t(ldexp_);
- }
- realvec log() const { return logd4(v); }
- realvec log10() const { return log10d4(v); }
- realvec log1p() const { return log1pd4(v); }
- realvec log2() const { return log2d4(v); }
- realvec_t mad(realvec_t y, realvec_t z) const
- {
- return MF::vml_mad(*this, y, z);
- }
- realvec nextafter(realvec y) const
- {
- return MF::vml_nextafter(*this, y);
- }
- realvec pow(realvec y) const { return powd4(v, y.v); }
- realvec rcp() const { return recip_fastd4(v); }
- realvec remainder(realvec y) const
- {
- return MF::vml_remainder(*this, y);
- }
- realvec rint() const
- {
- return MF::vml_rint(*this);
- // This is tempting, but seems too invasive
- // #ifdef VML_HAVE_FP_CONTRACT
- // return MF::vml_rint(*this);
- // #else
- // return vec_round(v); // use round instead of rint
- // #endif
- }
- realvec round() const { return vec_round(v); }
- realvec rsqrt() const
- {
- realvec x = *this;
- realvec r = vec_rsqrte(x.v); // this is only an approximation
- // TODO: use fma
- // two Newton iterations (see vml_rsqrt)
- r += RV(0.5)*r * (RV(1.0) - x * r*r);
- r += RV(0.5)*r * (RV(1.0) - x * r*r);
- return r;
- }
- boolvec_t signbit() const
- {
- return !RV(1.0).copysign(*this).as_int().as_bool();
- }
- realvec sin() const { return sind4(v); }
- realvec sinh() const { return sinhd4(v); }
- realvec sqrt() const
- {
- // return vec_sqrtsw_nochk(v);
- return *this * rsqrt();
- }
- realvec tan() const { return tand4(v); }
- realvec tanh() const { return tanhd4(v); }
- realvec trunc() const { return vec_trunc(v); }
- };
-
-
-
- // boolvec definitions
-
- inline intvec<double,4> boolvec<double,4>::as_int() const
- {
- return v;
- }
-
- inline intvec<double,4> boolvec<double,4>::convert_int() const
- {
- return ifthen(IV(I(1)), IV(I(0)));
- }
-
- inline
- boolvec<double,4>
- boolvec<double,4>::ifthen(boolvec_t x, boolvec_t y) const
- {
- return ifthen(x.as_int(), y.as_int()).as_bool();
- }
-
- inline
- intvec<double,4>
- boolvec<double,4>::ifthen(intvec_t x, intvec_t y) const
- {
- return ifthen(x.as_float(), y.as_float()).as_int();
- }
-
- inline
- realvec<double,4>
- boolvec<double,4>::ifthen(realvec_t x, realvec_t y) const
- {
- return vec_sel(y.v, x.v, v);
- }
-
-
-
- // intvec definitions
-
- inline intvec<double,4> intvec<double,4>::abs() const
- {
- return MF::vml_abs(*this);
- }
-
- inline realvec<double,4> intvec<double,4>::as_float() const
- {
- return v;
- }
-
- inline intvec<double,4> intvec<double,4>::bitifthen(intvec_t x,
- intvec_t y) const
- {
- return MF::vml_bitifthen(*this, x, y);
- }
-
- inline intvec<double,4> intvec<double,4>::clz() const
- {
- return MF::vml_clz(*this);
- }
-
- inline realvec<double,4> intvec<double,4>::convert_float() const
- {
- return vec_cfid(v);
- }
-
- inline boolvec<double,4> intvec<double,4>::isignbit() const
- {
- return MF::vml_isignbit(*this);
- }
-
- inline intvec<double,4> intvec<double,4>::max(intvec_t x) const
- {
- return MF::vml_max(*this, x);
- }
-
- inline intvec<double,4> intvec<double,4>::min(intvec_t x) const
- {
- return MF::vml_min(*this, x);
- }
-
- inline intvec<double,4> intvec<double,4>::popcount() const
- {
- return MF::vml_popcount(*this);
- }
-
- inline intvec<double,4> intvec<double,4>::rotate(int_t n) const
- {
- return MF::vml_rotate(*this, n);
- }
-
- inline intvec<double,4> intvec<double,4>::rotate(intvec_t n) const
- {
- return MF::vml_rotate(*this, n);
- }
-
+ }
+ boolvec_t isnormal() const { return MF::vml_isnormal(*this); }
+ realvec ldexp(int_t n) const { return ldexp(intvec_t(n)); }
+ realvec ldexp(intvec_t n) const {
+ real_t ldexp_[] = {
+ vml_std::ldexp((*this)[0], n[0]), vml_std::ldexp((*this)[1], n[1]),
+ vml_std::ldexp((*this)[2], n[2]), vml_std::ldexp((*this)[3], n[3])};
+ return realvec_t(ldexp_);
+ }
+ realvec log() const { return logd4(v); }
+ realvec log10() const { return log10d4(v); }
+ realvec log1p() const { return log1pd4(v); }
+ realvec log2() const { return log2d4(v); }
+ realvec_t mad(realvec_t y, realvec_t z) const {
+ return MF::vml_mad(*this, y, z);
+ }
+ realvec nextafter(realvec y) const { return MF::vml_nextafter(*this, y); }
+ realvec pow(realvec y) const { return powd4(v, y.v); }
+ realvec rcp() const { return recip_fastd4(v); }
+ realvec remainder(realvec y) const { return MF::vml_remainder(*this, y); }
+ realvec rint() const {
+ return MF::vml_rint(*this);
+ // This is tempting, but seems too invasive
+ // #ifdef VML_HAVE_FP_CONTRACT
+ // return MF::vml_rint(*this);
+ // #else
+ // return vec_round(v); // use round instead of rint
+ // #endif
+ }
+ realvec round() const { return vec_round(v); }
+ realvec rsqrt() const {
+ realvec x = *this;
+ realvec r = vec_rsqrte(x.v); // this is only an approximation
+ // TODO: use fma
+ // two Newton iterations (see vml_rsqrt)
+ r += RV(0.5) * r * (RV(1.0) - x * r * r);
+ r += RV(0.5) * r * (RV(1.0) - x * r * r);
+ return r;
+ }
+ boolvec_t signbit() const {
+ return !RV(1.0).copysign(*this).as_int().as_bool();
+ }
+ realvec sin() const { return sind4(v); }
+ realvec sinh() const { return sinhd4(v); }
+ realvec sqrt() const {
+ // return vec_sqrtsw_nochk(v);
+ return *this * rsqrt();
+ }
+ realvec tan() const { return tand4(v); }
+ realvec tanh() const { return tanhd4(v); }
+ realvec trunc() const { return vec_trunc(v); }
+};
+
+// boolvec definitions
+
+inline intvec<double, 4> boolvec<double, 4>::as_int() const { return v; }
+
+inline intvec<double, 4> boolvec<double, 4>::convert_int() const {
+ return ifthen(IV(I(1)), IV(I(0)));
+}
+
+inline boolvec<double, 4> boolvec<double, 4>::ifthen(boolvec_t x,
+ boolvec_t y) const {
+ return ifthen(x.as_int(), y.as_int()).as_bool();
+}
+
+inline intvec<double, 4> boolvec<double, 4>::ifthen(intvec_t x,
+ intvec_t y) const {
+ return ifthen(x.as_float(), y.as_float()).as_int();
+}
+
+inline realvec<double, 4> boolvec<double, 4>::ifthen(realvec_t x,
+ realvec_t y) const {
+ return vec_sel(y.v, x.v, v);
+}
+
+// intvec definitions
+
+inline intvec<double, 4> intvec<double, 4>::abs() const {
+ return MF::vml_abs(*this);
+}
+
+inline realvec<double, 4> intvec<double, 4>::as_float() const { return v; }
+
+inline intvec<double, 4> intvec<double, 4>::bitifthen(intvec_t x,
+ intvec_t y) const {
+ return MF::vml_bitifthen(*this, x, y);
+}
+
+inline intvec<double, 4> intvec<double, 4>::clz() const {
+ return MF::vml_clz(*this);
+}
+
+inline realvec<double, 4> intvec<double, 4>::convert_float() const {
+ return vec_cfid(v);
+}
+
+inline boolvec<double, 4> intvec<double, 4>::isignbit() const {
+ return MF::vml_isignbit(*this);
+}
+
+inline intvec<double, 4> intvec<double, 4>::max(intvec_t x) const {
+ return MF::vml_max(*this, x);
+}
+
+inline intvec<double, 4> intvec<double, 4>::min(intvec_t x) const {
+ return MF::vml_min(*this, x);
+}
+
+inline intvec<double, 4> intvec<double, 4>::popcount() const {
+ return MF::vml_popcount(*this);
+}
+
+inline intvec<double, 4> intvec<double, 4>::rotate(int_t n) const {
+ return MF::vml_rotate(*this, n);
+}
+
+inline intvec<double, 4> intvec<double, 4>::rotate(intvec_t n) const {
+ return MF::vml_rotate(*this, n);
+}
+
} // namespace vecmathlib
-#endif // #ifndef VEC_QPX_DOUBLE4_H
+#endif // #ifndef VEC_QPX_DOUBLE4_H
OpenPOWER on IntegriCloud