timshen created this revision.
timshen added a reviewer: mclow.lists.
Herald added subscribers: christof, sanjoy.
Herald added a reviewer: EricWF.

When vector extension (__attribute__((vector_size(...)))) is available
use its operators, instead of generating loops of scalar operations.


https://reviews.llvm.org/D44659

Files:
  libcxx/include/experimental/simd
  libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp

Index: libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
===================================================================
--- libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
+++ libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
@@ -64,136 +64,138 @@
 
 using namespace std::experimental::parallelism_v2;
 
+template <class SimdType>
 void test_pure_operators() {
   {
-    native_simd<int> a(42), b(4);
+    SimdType a(42), b(4);
 
-    assert(all_of(~a == native_simd<int>(~42)));
+    assert(all_of(~a == SimdType(~42)));
     assert(all_of(+a == a));
-    assert(all_of(-a == native_simd<int>(-42)));
-    assert(all_of(a + b == native_simd<int>(42 + 4)));
-    assert(all_of(a - b == native_simd<int>(42 - 4)));
-    assert(all_of(a * b == native_simd<int>(42 * 4)));
-    assert(all_of(a / b == native_simd<int>(42 / 4)));
-    assert(all_of(a % b == native_simd<int>(42 % 4)));
-    assert(all_of((a & b) == native_simd<int>(42 & 4)));
-    assert(all_of((a | b) == native_simd<int>(42 | 4)));
-    assert(all_of((a ^ b) == native_simd<int>(42 ^ 4)));
-    assert(all_of((a << b) == native_simd<int>(42 << 4)));
-    assert(all_of((a >> b) == native_simd<int>(42 >> 4)));
-    assert(all_of((a << 4) == native_simd<int>(42 << 4)));
-    assert(all_of((a >> 4) == native_simd<int>(42 >> 4)));
+    assert(all_of(-a == SimdType(-42)));
+    assert(all_of(a + b == SimdType(42 + 4)));
+    assert(all_of(a - b == SimdType(42 - 4)));
+    assert(all_of(a * b == SimdType(42 * 4)));
+    assert(all_of(a / b == SimdType(42 / 4)));
+    assert(all_of(a % b == SimdType(42 % 4)));
+    assert(all_of((a & b) == SimdType(42 & 4)));
+    assert(all_of((a | b) == SimdType(42 | 4)));
+    assert(all_of((a ^ b) == SimdType(42 ^ 4)));
+    assert(all_of((a << b) == SimdType(42 << 4)));
+    assert(all_of((a >> b) == SimdType(42 >> 4)));
+    assert(all_of((a << 4) == SimdType(42 << 4)));
+    assert(all_of((a >> 4) == SimdType(42 >> 4)));
   }
   {
-    native_simd<int> a([](int i) { return 2 * i + 1; }),
-        b([](int i) { return i + 1; });
+    SimdType a([](int i) { return 2 * i + 1; }), b([](int i) { return i + 1; });
 
-    assert(all_of(~a == native_simd<int>([](int i) { return ~(2 * i + 1); })));
+    assert(all_of(~a == SimdType([](int i) { return ~(2 * i + 1); })));
     assert(all_of(+a == a));
-    assert(all_of(-a == native_simd<int>([](int i) { return -(2 * i + 1); })));
-    assert(all_of(a + b == native_simd<int>([](int i) { return 3 * i + 2; })));
-    assert(all_of(a - b == native_simd<int>([](int i) { return i; })));
-    assert(all_of(a * b == native_simd<int>(
-                               [](int i) { return (2 * i + 1) * (i + 1); })));
-    assert(all_of(a / b == native_simd<int>(
-                               [](int i) { return (2 * i + 1) / (i + 1); })));
-    assert(all_of(a % b == native_simd<int>(
-                               [](int i) { return (2 * i + 1) % (i + 1); })));
-    assert(all_of((a & b) == native_simd<int>(
-                                 [](int i) { return (2 * i + 1) & (i + 1); })));
-    assert(all_of((a | b) == native_simd<int>(
-                                 [](int i) { return (2 * i + 1) | (i + 1); })));
-    assert(all_of((a ^ b) == native_simd<int>(
-                                 [](int i) { return (2 * i + 1) ^ (i + 1); })));
+    assert(all_of(-a == SimdType([](int i) { return -(2 * i + 1); })));
+    assert(all_of(a + b == SimdType([](int i) { return 3 * i + 2; })));
+    assert(all_of(a - b == SimdType([](int i) { return i; })));
+    assert(
+        all_of(a * b == SimdType([](int i) { return (2 * i + 1) * (i + 1); })));
+    assert(
+        all_of(a / b == SimdType([](int i) { return (2 * i + 1) / (i + 1); })));
+    assert(
+        all_of(a % b == SimdType([](int i) { return (2 * i + 1) % (i + 1); })));
+    assert(all_of((a & b) ==
+                  SimdType([](int i) { return (2 * i + 1) & (i + 1); })));
+    assert(all_of((a | b) ==
+                  SimdType([](int i) { return (2 * i + 1) | (i + 1); })));
+    assert(all_of((a ^ b) ==
+                  SimdType([](int i) { return (2 * i + 1) ^ (i + 1); })));
   }
 }
 
+template <class SimdType>
 void test_mutating_opreators() {
-  native_simd<int> b(4);
+  SimdType b(4);
   {
-    native_simd<int> a(42);
-    assert(all_of(++a == native_simd<int>(43)));
-    assert(all_of(a == native_simd<int>(43)));
+    SimdType a(42);
+    assert(all_of(++a == SimdType(43)));
+    assert(all_of(a == SimdType(43)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of(a++ == native_simd<int>(42)));
-    assert(all_of(a == native_simd<int>(43)));
+    SimdType a(42);
+    assert(all_of(a++ == SimdType(42)));
+    assert(all_of(a == SimdType(43)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of(--a == native_simd<int>(41)));
-    assert(all_of(a == native_simd<int>(41)));
+    SimdType a(42);
+    assert(all_of(--a == SimdType(41)));
+    assert(all_of(a == SimdType(41)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of(a-- == native_simd<int>(42)));
-    assert(all_of(a == native_simd<int>(41)));
+    SimdType a(42);
+    assert(all_of(a-- == SimdType(42)));
+    assert(all_of(a == SimdType(41)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a += b) == native_simd<int>(42 + 4)));
-    assert(all_of(a == native_simd<int>(42 + 4)));
+    SimdType a(42);
+    assert(all_of((a += b) == SimdType(42 + 4)));
+    assert(all_of(a == SimdType(42 + 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a -= b) == native_simd<int>(42 - 4)));
-    assert(all_of(a == native_simd<int>(42 - 4)));
+    SimdType a(42);
+    assert(all_of((a -= b) == SimdType(42 - 4)));
+    assert(all_of(a == SimdType(42 - 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a *= b) == native_simd<int>(42 * 4)));
-    assert(all_of(a == native_simd<int>(42 * 4)));
+    SimdType a(42);
+    assert(all_of((a *= b) == SimdType(42 * 4)));
+    assert(all_of(a == SimdType(42 * 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a /= b) == native_simd<int>(42 / 4)));
-    assert(all_of(a == native_simd<int>(42 / 4)));
+    SimdType a(42);
+    assert(all_of((a /= b) == SimdType(42 / 4)));
+    assert(all_of(a == SimdType(42 / 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a %= b) == native_simd<int>(42 % 4)));
-    assert(all_of(a == native_simd<int>(42 % 4)));
+    SimdType a(42);
+    assert(all_of((a %= b) == SimdType(42 % 4)));
+    assert(all_of(a == SimdType(42 % 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a &= b) == native_simd<int>(42 & 4)));
-    assert(all_of(a == native_simd<int>(42 & 4)));
+    SimdType a(42);
+    assert(all_of((a &= b) == SimdType(42 & 4)));
+    assert(all_of(a == SimdType(42 & 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a |= b) == native_simd<int>(42 | 4)));
-    assert(all_of(a == native_simd<int>(42 | 4)));
+    SimdType a(42);
+    assert(all_of((a |= b) == SimdType(42 | 4)));
+    assert(all_of(a == SimdType(42 | 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a ^= b) == native_simd<int>(42 ^ 4)));
-    assert(all_of(a == native_simd<int>(42 ^ 4)));
+    SimdType a(42);
+    assert(all_of((a ^= b) == SimdType(42 ^ 4)));
+    assert(all_of(a == SimdType(42 ^ 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a <<= b) == native_simd<int>(42 << 4)));
-    assert(all_of(a == native_simd<int>(42 << 4)));
+    SimdType a(42);
+    assert(all_of((a <<= b) == SimdType(42 << 4)));
+    assert(all_of(a == SimdType(42 << 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a >>= b) == native_simd<int>(42 >> 4)));
-    assert(all_of(a == native_simd<int>(42 >> 4)));
+    SimdType a(42);
+    assert(all_of((a >>= b) == SimdType(42 >> 4)));
+    assert(all_of(a == SimdType(42 >> 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a <<= 4) == native_simd<int>(42 << 4)));
-    assert(all_of(a == native_simd<int>(42 << 4)));
+    SimdType a(42);
+    assert(all_of((a <<= 4) == SimdType(42 << 4)));
+    assert(all_of(a == SimdType(42 << 4)));
   }
   {
-    native_simd<int> a(42);
-    assert(all_of((a >>= 4) == native_simd<int>(42 >> 4)));
-    assert(all_of(a == native_simd<int>(42 >> 4)));
+    SimdType a(42);
+    assert(all_of((a >>= 4) == SimdType(42 >> 4)));
+    assert(all_of(a == SimdType(42 >> 4)));
   }
 }
 
+template <class SimdType>
 void test_relational_operators() {
-  fixed_size_simd<int, 9> a, b;
+  SimdType a, b;
   {
     int buf[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
     a.copy_from(buf, element_aligned_tag());
@@ -208,58 +210,62 @@
       false, true, false,
       false, false, true,
     };
-    assert(all_of((a == b) == fixed_size_simd_mask<int, 9>(
+    assert(all_of((a == b) == typename SimdType::mask_type(
                                   expected, element_aligned_tag())));
   }
   {
     bool expected[] = {
       false, true, true,
       true, false, true,
       true, true, false,
     };
-    assert(all_of((a != b) == fixed_size_simd_mask<int, 9>(
+    assert(all_of((a != b) == typename SimdType::mask_type(
                                   expected, element_aligned_tag())));
   }
   {
     bool expected[] = {
       false, true, true,
       false, false, true,
       false, false, false,
     };
-    assert(all_of((a < b) == fixed_size_simd_mask<int, 9>(
+    assert(all_of((a < b) == typename SimdType::mask_type(
                                  expected, element_aligned_tag())));
   }
   {
     bool expected[] = {
       true, true, true,
       false, true, true,
       false, false, true,
     };
-    assert(all_of((a <= b) == fixed_size_simd_mask<int, 9>(
+    assert(all_of((a <= b) == typename SimdType::mask_type(
                                   expected, element_aligned_tag())));
   }
   {
     bool expected[] = {
       false, false, false,
       true, false, false,
       true, true, false,
     };
-    assert(all_of((a > b) == fixed_size_simd_mask<int, 9>(
+    assert(all_of((a > b) == typename SimdType::mask_type(
                                  expected, element_aligned_tag())));
   }
   {
     bool expected[] = {
       true, false, false,
       true, true, false,
       true, true, true,
     };
-    assert(all_of((a >= b) == fixed_size_simd_mask<int, 9>(
+    assert(all_of((a >= b) == typename SimdType::mask_type(
                                   expected, element_aligned_tag())));
   }
 }
 
 int main() {
-  test_pure_operators();
-  test_mutating_opreators();
-  test_relational_operators();
+  test_pure_operators<native_simd<int>>();
+  test_pure_operators<fixed_size_simd<int, 4>>();
+  test_mutating_opreators<native_simd<int>>();
+  test_mutating_opreators<fixed_size_simd<int, 4>>();
+  test_relational_operators<
+      simd<int, rebind_abi_t<int, 9, simd_abi::native<int>>>>();
+  test_relational_operators<fixed_size_simd<int, 9>>();
 }
Index: libcxx/include/experimental/simd
===================================================================
--- libcxx/include/experimental/simd
+++ libcxx/include/experimental/simd
@@ -622,11 +622,166 @@
 template <_StorageKind __kind, int _Np>
 struct __simd_abi {};
 
+template <class _Derived>
+struct __simd_storage_base {
+  static _Derived __neg(const _Derived& __a) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, -__a.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __add(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) + __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __sub(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) - __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __mul(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) * __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __div(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) / __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __mod(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) % __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __and(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) & __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __or(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) | __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __not(const _Derived& __a) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, ~__a.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __xor(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) ^ __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __shl(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) << __b.__get(__i));
+    }
+    return __v;
+  }
+
+  static _Derived __shr(const _Derived& __a, const _Derived& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) >> __b.__get(__i));
+    }
+    return __v;
+  }
+
+  template <class _InputSimd>
+  static _Derived __cmp_eq(const _InputSimd& __a, const _InputSimd& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) == __b.__get(__i) ? -1 : 0);
+    }
+    return __v;
+  }
+
+  template <class _InputSimd>
+  static _Derived __cmp_ne(const _InputSimd& __a, const _InputSimd& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) != __b.__get(__i) ? -1 : 0);
+    }
+    return __v;
+  }
+
+  template <class _InputSimd>
+  static _Derived __cmp_le(const _InputSimd& __a, const _InputSimd& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) <= __b.__get(__i) ? -1 : 0);
+    }
+    return __v;
+  }
+
+  template <class _InputSimd>
+  static _Derived __cmp_ge(const _InputSimd& __a, const _InputSimd& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) >= __b.__get(__i) ? -1 : 0);
+    }
+    return __v;
+  }
+
+  template <class _InputSimd>
+  static _Derived __cmp_lt(const _InputSimd& __a, const _InputSimd& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) < __b.__get(__i) ? -1 : 0);
+    }
+    return __v;
+  }
+
+  template <class _InputSimd>
+  static _Derived __cmp_gt(const _InputSimd& __a, const _InputSimd& __b) {
+    _Derived __v;
+    for (size_t __i = 0; __i < _Derived::__size(); __i++) {
+      __v.__set(__i, __a.__get(__i) > __b.__get(__i) ? -1 : 0);
+    }
+    return __v;
+  }
+};
+
 template <class _Tp, class _Abi>
 class __simd_storage {};
 
 template <class _Tp, int __num_element>
-class __simd_storage<_Tp, __simd_abi<_StorageKind::_Array, __num_element>> {
+class __simd_storage<_Tp, __simd_abi<_StorageKind::_Array, __num_element>>
+    : public __simd_storage_base<__simd_storage<
+          _Tp, __simd_abi<_StorageKind::_Array, __num_element>>> {
   std::array<_Tp, __num_element> __storage_;
 
   template <class, class>
@@ -638,15 +793,19 @@
 public:
   using __raw_type = std::array<_Tp, __num_element>;
 
+  static constexpr size_t __size() { return __num_element; }
+
   __simd_storage() = default;
   void __assign(__raw_type __raw) { __storage_ = __raw; }
   __raw_type __raw() const { return __storage_; }
   _Tp __get(size_t __index) const { return __storage_[__index]; };
   void __set(size_t __index, _Tp __val) { __storage_[__index] = __val; }
 };
 
 template <class _Tp>
-class __simd_storage<_Tp, __simd_abi<_StorageKind::_Scalar, 1>> {
+class __simd_storage<_Tp, __simd_abi<_StorageKind::_Scalar, 1>>
+    : public __simd_storage_base<
+          __simd_storage<_Tp, __simd_abi<_StorageKind::_Scalar, 1>>> {
   _Tp __storage_;
 
   template <class, class>
@@ -658,6 +817,8 @@
 public:
   using __raw_type = _Tp;
 
+  static constexpr size_t __size() { return 1; }
+
   __simd_storage() = default;
   void __assign(__raw_type __raw) { __storage_ = __raw; }
   __raw_type __raw() const { return __storage_; }
@@ -780,7 +941,9 @@
 #endif
 
 template <class _Tp, int __num_element>
-class __simd_storage<_Tp, __simd_abi<_StorageKind::_VecExt, __num_element>> {
+class __simd_storage<_Tp, __simd_abi<_StorageKind::_VecExt, __num_element>>
+    : public __simd_storage_base<__simd_storage<
+          _Tp, __simd_abi<_StorageKind::_VecExt, __num_element>>> {
   using _StorageType =
       typename __vec_ext_traits<_Tp, sizeof(_Tp) * __num_element>::type;
 
@@ -792,14 +955,107 @@
   template <class, class>
   friend struct simd_mask;
 
+  __simd_storage(_StorageType __s) : __storage_(__s) {}
+
 public:
   using __raw_type = _StorageType;
 
+  static constexpr size_t __size() { return __num_element; }
+
   __simd_storage() = default;
   void __assign(__raw_type __raw) { __storage_ = __raw; }
   __raw_type __raw() const { return __storage_; }
+
   _Tp __get(size_t __index) const { return __storage_[__index]; };
   void __set(size_t __index, _Tp __val) { __storage_[__index] = __val; }
+
+  static __simd_storage __neg(const __simd_storage& __a) {
+    return __simd_storage(-__a.__storage_);
+  }
+
+  static __simd_storage __add(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ + __b.__storage_);
+  }
+
+  static __simd_storage __sub(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ - __b.__storage_);
+  }
+
+  static __simd_storage __mul(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ * __b.__storage_);
+  }
+
+  static __simd_storage __div(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ / __b.__storage_);
+  }
+
+  static __simd_storage __mod(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ % __b.__storage_);
+  }
+
+  static __simd_storage __and(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ & __b.__storage_);
+  }
+
+  static __simd_storage __or(const __simd_storage& __a,
+                             const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ | __b.__storage_);
+  }
+
+  static __simd_storage __xor(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ ^ __b.__storage_);
+  }
+
+  static __simd_storage __not(const __simd_storage& __a) {
+    return __simd_storage(~__a.__storage_);
+  }
+
+  static __simd_storage __shl(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ << __b.__storage_);
+  }
+
+  static __simd_storage __shr(const __simd_storage& __a,
+                              const __simd_storage& __b) {
+    return __simd_storage(__a.__storage_ >> __b.__storage_);
+  }
+
+  template <class _InputSimd>
+  static __simd_storage __cmp_eq(const _InputSimd& __a, const _InputSimd& __b) {
+    return __simd_storage(__a.__raw() == __b.__raw());
+  }
+
+  template <class _InputSimd>
+  static __simd_storage __cmp_ne(const _InputSimd& __a, const _InputSimd& __b) {
+    return __simd_storage(__a.__raw() != __b.__raw());
+  }
+
+  template <class _InputSimd>
+  static __simd_storage __cmp_le(const _InputSimd& __a, const _InputSimd& __b) {
+    return __simd_storage(__a.__raw() <= __b.__raw());
+  }
+
+  template <class _InputSimd>
+  static __simd_storage __cmp_ge(const _InputSimd& __a, const _InputSimd& __b) {
+    return __simd_storage(__a.__raw() >= __b.__raw());
+  }
+
+  template <class _InputSimd>
+  static __simd_storage __cmp_lt(const _InputSimd& __a, const _InputSimd& __b) {
+    return __simd_storage(__a.__raw() < __b.__raw());
+  }
+
+  template <class _InputSimd>
+  static __simd_storage __cmp_gt(const _InputSimd& __a, const _InputSimd& __b) {
+    return __simd_storage(__a.__raw() > __b.__raw());
+  }
 };
 
 #endif // _LIBCPP_HAS_NO_VECTOR_EXTENSION
@@ -1901,6 +2157,9 @@
     return simd_size<_Tp, _Abi>::value;
   }
 
+  template <class, class>
+  friend class simd;
+
   template <class, class>
   friend class simd_mask;
 
@@ -1959,6 +2218,50 @@
     }
   }
 
+  static simd __from_storage(__simd_storage<_Tp, _Abi> __s) {
+    simd __v;
+    __v.__s_ = __s;
+    return __v;
+  }
+
+  // The actual implementation for all relational operators due to how `friend`
+  // works. See CWG 1699.
+  static mask_type __cmp_eq_impl(const simd& __a, const simd& __b) {
+    using __element = typename __unsigned_traits<sizeof(_Tp)>::type;
+    return mask_type(simd<__element, _Abi>::__from_storage(
+        __simd_storage<__element, _Abi>::__cmp_eq(__a.__s_, __b.__s_)));
+  }
+
+  static mask_type __cmp_ne_impl(const simd& __a, const simd& __b) {
+    using __element = typename __unsigned_traits<sizeof(_Tp)>::type;
+    return mask_type(simd<__element, _Abi>::__from_storage(
+        __simd_storage<__element, _Abi>::__cmp_ne(__a.__s_, __b.__s_)));
+  }
+
+  static mask_type __cmp_ge_impl(const simd& __a, const simd& __b) {
+    using __element = typename __unsigned_traits<sizeof(_Tp)>::type;
+    return mask_type(simd<__element, _Abi>::__from_storage(
+        __simd_storage<__element, _Abi>::__cmp_ge(__a.__s_, __b.__s_)));
+  }
+
+  static mask_type __cmp_le_impl(const simd& __a, const simd& __b) {
+    using __element = typename __unsigned_traits<sizeof(_Tp)>::type;
+    return mask_type(simd<__element, _Abi>::__from_storage(
+        __simd_storage<__element, _Abi>::__cmp_le(__a.__s_, __b.__s_)));
+  }
+
+  static mask_type __cmp_gt_impl(const simd& __a, const simd& __b) {
+    using __element = typename __unsigned_traits<sizeof(_Tp)>::type;
+    return mask_type(simd<__element, _Abi>::__from_storage(
+        __simd_storage<__element, _Abi>::__cmp_gt(__a.__s_, __b.__s_)));
+  }
+
+  static mask_type __cmp_lt_impl(const simd& __a, const simd& __b) {
+    using __element = typename __unsigned_traits<sizeof(_Tp)>::type;
+    return mask_type(simd<__element, _Abi>::__from_storage(
+        __simd_storage<__element, _Abi>::__cmp_lt(__a.__s_, __b.__s_)));
+  }
+
 public:
   // implicit type conversion constructor
   template <class _Up,
@@ -2067,98 +2370,56 @@
   mask_type operator!() const { return *this == simd(0); }
 
   simd operator~() const {
-    simd __v;
-    for (size_t __i = 0; __i < size(); __i++) {
-      __v[__i] = ~(*this)[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__not(this->__s_));
   }
 
   simd operator+() const { return *this; }
 
-  simd operator-() const { return simd(0) - *this; }
+  simd operator-() const {
+    return __from_storage(__simd_storage<_Tp, _Abi>::__neg(this->__s_));
+  }
 
   // binary operators [simd.binary]
   // TODO: regarding NOTE 9, the implementationn chooses not to SFINAE,
   // but causes a hard error when the operator can't work on _Tp.
   friend simd operator+(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] + __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__add(__a.__s_, __b.__s_));
   }
 
   friend simd operator-(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] - __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__sub(__a.__s_, __b.__s_));
   }
 
   friend simd operator*(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] * __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__mul(__a.__s_, __b.__s_));
   }
 
   friend simd operator/(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] / __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__div(__a.__s_, __b.__s_));
   }
 
   friend simd operator%(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] % __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__mod(__a.__s_, __b.__s_));
   }
 
   friend simd operator&(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] & __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__and(__a.__s_, __b.__s_));
   }
 
   friend simd operator|(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] | __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__or(__a.__s_, __b.__s_));
   }
 
   friend simd operator^(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] ^ __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__xor(__a.__s_, __b.__s_));
   }
 
   friend simd operator<<(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] << __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__shl(__a.__s_, __b.__s_));
   }
 
   friend simd operator>>(const simd& __a, const simd& __b) {
-    simd __v;
-    for (size_t __i = 0; __i < __v.size(); __i++) {
-      __v[__i] = __a[__i] >> __b[__i];
-    }
-    return __v;
+    return __from_storage(__simd_storage<_Tp, _Abi>::__shr(__a.__s_, __b.__s_));
   }
 
   friend simd operator<<(const simd& __a, int __offset) {
@@ -2219,51 +2480,27 @@
 
   // compares [simd.comparison]
   friend mask_type operator==(const simd& __a, const simd& __b) {
-    mask_type __mask;
-    for (size_t __i = 0; __i < __a.size(); __i++) {
-      __mask[__i] = __a[__i] == __b[__i];
-    }
-    return __mask;
+    return __cmp_eq_impl(__a, __b);
   }
 
   friend mask_type operator!=(const simd& __a, const simd& __b) {
-    mask_type __mask;
-    for (size_t __i = 0; __i < __a.size(); __i++) {
-      __mask[__i] = __a[__i] != __b[__i];
-    }
-    return __mask;
+    return __cmp_ne_impl(__a, __b);
   }
 
   friend mask_type operator>=(const simd& __a, const simd& __b) {
-    mask_type __mask;
-    for (size_t __i = 0; __i < __a.size(); __i++) {
-      __mask[__i] = __a[__i] >= __b[__i];
-    }
-    return __mask;
+    return __cmp_ge_impl(__a, __b);
   }
 
   friend mask_type operator<=(const simd& __a, const simd& __b) {
-    mask_type __mask;
-    for (size_t __i = 0; __i < __a.size(); __i++) {
-      __mask[__i] = __a[__i] <= __b[__i];
-    }
-    return __mask;
+    return __cmp_le_impl(__a, __b);
   }
 
   friend mask_type operator>(const simd& __a, const simd& __b) {
-    mask_type __mask;
-    for (size_t __i = 0; __i < __a.size(); __i++) {
-      __mask[__i] = __a[__i] > __b[__i];
-    }
-    return __mask;
+    return __cmp_gt_impl(__a, __b);
   }
 
   friend mask_type operator<(const simd& __a, const simd& __b) {
-    mask_type __mask;
-    for (size_t __i = 0; __i < __a.size(); __i++) {
-      __mask[__i] = __a[__i] < __b[__i];
-    }
-    return __mask;
+    return __cmp_lt_impl(__a, __b);
   }
 
 #if !defined(_LIBCPP_HAS_NO_VECTOR_EXTENSION) && defined(_LIBCPP_COMPILER_CLANG)
@@ -2287,6 +2524,9 @@
 
   friend struct __simd_mask_friend;
 
+  template <class, class>
+  friend class simd;
+
   // Use a non-member function, only because Clang 3.8 crashes with a member function.
   template <size_t __alignment>
   static void __copy_from_impl(simd_mask* __mask, const bool* __buffer
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to