timshen created this revision.
timshen added reviewers: mclow.lists, EricWF.
Herald added a subscriber: sanjoy.

This patch completes the implementation of simd<> and related operations.


https://reviews.llvm.org/D41422

Files:
  libcxx/include/experimental/simd
  libcxx/test/std/experimental/simd/simd.elementwise/clamp.pass.cpp
  libcxx/test/std/experimental/simd/simd.elementwise/max.pass.cpp
  libcxx/test/std/experimental/simd/simd.elementwise/min.pass.cpp
  libcxx/test/std/experimental/simd/simd.elementwise/minmax.pass.cpp
  libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
  libcxx/test/std/experimental/simd/simd.horizontal/hmax.pass.cpp
  libcxx/test/std/experimental/simd/simd.horizontal/hmin.pass.cpp
  libcxx/test/std/experimental/simd/simd.horizontal/reduce.pass.cpp

Index: libcxx/test/std/experimental/simd/simd.horizontal/reduce.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.horizontal/reduce.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// // reductions [simd.reductions]
+// template <class T, class Abi, class BinaryOperation = std::plus<>>
+// T reduce(const simd<T, Abi>&, BinaryOperation = BinaryOperation());
+//
+// template <class M, class V, class BinaryOperation>
+// typename V::value_type reduce(const const_where_expression<M, V>& x,
+// typename V::value_type neutral_element, BinaryOperation binary_op);
+//
+// template <class M, class V>
+// typename V::value_type reduce(const const_where_expression<M, V>& x, plus<> binary_op = plus<>());
+//
+// template <class M, class V>
+// typename V::value_type reduce(const const_where_expression<M, V>& x, multiplies<> binary_op);
+//
+// template <class M, class V>
+// typename V::value_type reduce(const const_where_expression<M, V>& x, bit_and<> binary_op);
+//
+// template <class M, class V>
+// typename V::value_type reduce(const const_where_expression<M, V>& x, bit_or<> binary_op);
+//
+// template <class M, class V>
+// typename V::value_type reduce(const const_where_expression<M, V>& x, bit_xor<> binary_op);
+
+#include <cassert>
+#include <cstdint>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+inline int factorial(int n) { return n == 1 ? 1 : n * factorial(n - 1); }
+
+void test_reduce() {
+  int n = (int)native_simd<int>::size();
+  assert(reduce(native_simd<int>([](int i) { return i; })) == n * (n - 1) / 2);
+  assert(reduce(native_simd<int>([](int i) { return i; }), std::plus<int>()) ==
+         n * (n - 1) / 2);
+  assert(reduce(native_simd<int>([](int i) { return i + 1; }),
+                std::multiplies<int>()) == factorial(n));
+}
+
+int main() { test_reduce(); }
Index: libcxx/test/std/experimental/simd/simd.horizontal/hmin.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.horizontal/hmin.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class Abi> T hmin(const simd<T, Abi>&);
+// template <class M, class V> T hmin(const const_where_expression<M, V>&);
+
+#include <experimental/simd>
+#include <cassert>
+#include <cstdint>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_hmin() {
+  {
+    int a[] = {2, 5, -4, 6};
+    assert(hmin(fixed_size_simd<int, 4>(a, element_aligned_tag())) == -4);
+  }
+  {
+    int a[] = {6, 2, 5, -4};
+    assert(hmin(fixed_size_simd<int, 4>(a, element_aligned_tag())) == -4);
+  }
+  {
+    int a[] = {-4, 6, 2, 5};
+    assert(hmin(fixed_size_simd<int, 4>(a, element_aligned_tag())) == -4);
+  }
+  {
+    int a[] = {5, -4, 6, 2};
+    assert(hmin(fixed_size_simd<int, 4>(a, element_aligned_tag())) == -4);
+  }
+}
+
+int main() { test_hmin(); }
Index: libcxx/test/std/experimental/simd/simd.horizontal/hmax.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.horizontal/hmax.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class Abi> T hmax(const simd<T, Abi>&);
+// template <class M, class V> T hmax(const const_where_expression<M, V>&);
+
+#include <experimental/simd>
+#include <cassert>
+#include <cstdint>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_hmax() {
+  {
+    int a[] = {2, 5, -4, 6};
+    assert(hmax(fixed_size_simd<int, 4>(a, element_aligned_tag())) == 6);
+  }
+  {
+    int a[] = {6, 2, 5, -4};
+    assert(hmax(fixed_size_simd<int, 4>(a, element_aligned_tag())) == 6);
+  }
+  {
+    int a[] = {-4, 6, 2, 5};
+    assert(hmax(fixed_size_simd<int, 4>(a, element_aligned_tag())) == 6);
+  }
+  {
+    int a[] = {5, -4, 6, 2};
+    assert(hmax(fixed_size_simd<int, 4>(a, element_aligned_tag())) == 6);
+  }
+}
+
+int main() { test_hmax(); }
Index: libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
@@ -0,0 +1,200 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// // unary operators [simd.unary]
+// simd& operator++();
+// simd operator++(int);
+// simd& operator--();
+// simd operator--(int);
+// mask_type operator!() const;
+// simd operator~() const; // see below
+// simd operator+() const;
+// simd operator-() const;
+//
+// // binary operators [simd.binary]
+// friend simd operator+ (const simd&, const simd&);
+// friend simd operator- (const simd&, const simd&);
+// friend simd operator* (const simd&, const simd&);
+// friend simd operator/ (const simd&, const simd&);
+// friend simd operator% (const simd&, const simd&);
+// friend simd operator& (const simd&, const simd&);
+// friend simd operator| (const simd&, const simd&);
+// friend simd operator^ (const simd&, const simd&);
+// friend simd operator<<(const simd&, const simd&);
+// friend simd operator>>(const simd&, const simd&);
+// friend simd operator<<(const simd&, int);
+// friend simd operator>>(const simd&, int);
+//
+// // compound assignment [simd.cassign]
+// friend simd& operator+= (simd&, const simd&);
+// friend simd& operator-= (simd&, const simd&);
+// friend simd& operator*= (simd&, const simd&);
+// friend simd& operator/= (simd&, const simd&);
+// friend simd& operator%= (simd&, const simd&);
+//
+// friend simd& operator&= (simd&, const simd&);
+// friend simd& operator|= (simd&, const simd&);
+// friend simd& operator^= (simd&, const simd&);
+// friend simd& operator<<=(simd&, const simd&);
+// friend simd& operator>>=(simd&, const simd&);
+// friend simd& operator<<=(simd&, int);
+// friend simd& operator>>=(simd&, int);
+
+#include <cassert>
+#include <cstdint>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+template <typename T, typename Abi>
+bool equal(simd<T, Abi> a, simd<T, Abi> b) {
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void test_pure_operators() {
+  {
+    native_simd<int> a(42), b(4);
+
+    assert(equal(~a, native_simd<int>(~42)));
+    assert(equal(+a, a));
+    assert(equal(-a, native_simd<int>(-42)));
+    assert(equal(a + b, native_simd<int>(42 + 4)));
+    assert(equal(a - b, native_simd<int>(42 - 4)));
+    assert(equal(a * b, native_simd<int>(42 * 4)));
+    assert(equal(a / b, native_simd<int>(42 / 4)));
+    assert(equal(a % b, native_simd<int>(42 % 4)));
+    assert(equal(a & b, native_simd<int>(42 & 4)));
+    assert(equal(a | b, native_simd<int>(42 | 4)));
+    assert(equal(a ^ b, native_simd<int>(42 ^ 4)));
+    assert(equal(a << b, native_simd<int>(42 << 4)));
+    assert(equal(a >> b, native_simd<int>(42 >> 4)));
+    assert(equal(a << 4, native_simd<int>(42 << 4)));
+    assert(equal(a >> 4, native_simd<int>(42 >> 4)));
+  }
+  {
+    native_simd<int> a([](int i) { return 2 * i + 1; }),
+        b([](int i) { return i + 1; });
+
+    assert(equal(~a, native_simd<int>([](int i) { return ~(2 * i + 1); })));
+    assert(equal(+a, a));
+    assert(equal(-a, native_simd<int>([](int i) { return -(2 * i + 1); })));
+    assert(equal(a + b, native_simd<int>([](int i) { return 3 * i + 2; })));
+    assert(equal(a - b, native_simd<int>([](int i) { return i; })));
+    assert(equal(
+        a * b, native_simd<int>([](int i) { return (2 * i + 1) * (i + 1); })));
+    assert(equal(
+        a / b, native_simd<int>([](int i) { return (2 * i + 1) / (i + 1); })));
+    assert(equal(
+        a % b, native_simd<int>([](int i) { return (2 * i + 1) % (i + 1); })));
+    assert(equal(
+        a & b, native_simd<int>([](int i) { return (2 * i + 1) & (i + 1); })));
+    assert(equal(
+        a | b, native_simd<int>([](int i) { return (2 * i + 1) | (i + 1); })));
+    assert(equal(
+        a ^ b, native_simd<int>([](int i) { return (2 * i + 1) ^ (i + 1); })));
+  }
+}
+
+void test_mutating_opreators() {
+  native_simd<int> b(4);
+  {
+    native_simd<int> a(42);
+    assert(equal(++a, native_simd<int>(43)));
+    assert(equal(a, native_simd<int>(43)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a++, native_simd<int>(42)));
+    assert(equal(a, native_simd<int>(43)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(--a, native_simd<int>(41)));
+    assert(equal(a, native_simd<int>(41)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a--, native_simd<int>(42)));
+    assert(equal(a, native_simd<int>(41)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a += b, native_simd<int>(42 + 4)));
+    assert(equal(a, native_simd<int>(42 + 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a -= b, native_simd<int>(42 - 4)));
+    assert(equal(a, native_simd<int>(42 - 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a *= b, native_simd<int>(42 * 4)));
+    assert(equal(a, native_simd<int>(42 * 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a /= b, native_simd<int>(42 / 4)));
+    assert(equal(a, native_simd<int>(42 / 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a %= b, native_simd<int>(42 % 4)));
+    assert(equal(a, native_simd<int>(42 % 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a &= b, native_simd<int>(42 & 4)));
+    assert(equal(a, native_simd<int>(42 & 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a |= b, native_simd<int>(42 | 4)));
+    assert(equal(a, native_simd<int>(42 | 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a ^= b, native_simd<int>(42 ^ 4)));
+    assert(equal(a, native_simd<int>(42 ^ 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a <<= b, native_simd<int>(42 << 4)));
+    assert(equal(a, native_simd<int>(42 << 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a >>= b, native_simd<int>(42 >> 4)));
+    assert(equal(a, native_simd<int>(42 >> 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a <<= 4, native_simd<int>(42 << 4)));
+    assert(equal(a, native_simd<int>(42 << 4)));
+  }
+  {
+    native_simd<int> a(42);
+    assert(equal(a >>= 4, native_simd<int>(42 >> 4)));
+    assert(equal(a, native_simd<int>(42 >> 4)));
+  }
+}
+
+int main() {
+  test_pure_operators();
+  test_mutating_opreators();
+}
Index: libcxx/test/std/experimental/simd/simd.elementwise/minmax.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.elementwise/minmax.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class Abi>
+// std::pair<simd<T, Abi>, simd<T, Abi>>
+// minmax(const simd<T, Abi>&, const simd<T, Abi>&) noexcept;
+
+#include <cassert>
+#include <cstdint>
+#include <algorithm>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+template <typename T, typename Abi>
+bool equal(simd<T, Abi> a, simd<T, Abi> b) {
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void test_minmax() {
+  int n = (int)native_simd<int>::size();
+  native_simd<int> mi, mx;
+  std::tie(mi, mx) = minmax(native_simd<int>([](int i) { return i; }),
+                            native_simd<int>([n](int i) { return n - 1 - i; })),
+               assert(equal(mi, native_simd<int>([n](int i) {
+                              return std::min(i, n - 1 - i);
+                            })));
+  assert(equal(
+      mx, native_simd<int>([n](int i) { return std::max(i, n - 1 - i); })));
+}
+
+int main() { test_minmax(); }
Index: libcxx/test/std/experimental/simd/simd.elementwise/min.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.elementwise/min.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class Abi>
+// simd<T, Abi>
+// min(const simd<T, Abi>&, const simd<T, Abi>&) noexcept;
+
+#include <cassert>
+#include <cstdint>
+#include <algorithm>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+template <typename T, typename Abi>
+bool equal(simd<T, Abi> a, simd<T, Abi> b) {
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void test_min() {
+  int n = (int)native_simd<int>::size();
+  assert(
+      equal(min(native_simd<int>([](int i) { return i; }),
+                native_simd<int>([n](int i) { return n - 1 - i; })),
+            native_simd<int>([n](int i) { return std::min(i, n - 1 - i); })));
+}
+
+int main() { test_min(); }
Index: libcxx/test/std/experimental/simd/simd.elementwise/max.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.elementwise/max.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class Abi>
+// simd<T, Abi>
+// max(const simd<T, Abi>&, const simd<T, Abi>&) noexcept;
+
+#include <cassert>
+#include <cstdint>
+#include <algorithm>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+template <typename T, typename Abi>
+bool equal(simd<T, Abi> a, simd<T, Abi> b) {
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void test_max() {
+  int n = (int)native_simd<int>::size();
+  assert(
+      equal(max(native_simd<int>([](int i) { return i; }),
+                native_simd<int>([n](int i) { return n - 1 - i; })),
+            native_simd<int>([n](int i) { return std::max(i, n - 1 - i); })));
+}
+
+int main() { test_max(); }
Index: libcxx/test/std/experimental/simd/simd.elementwise/clamp.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.elementwise/clamp.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/simd>
+//
+// template <class T, class Abi>
+// simd<T, Abi>
+// clamp(const simd<T, Abi>& v, const simd<T, Abi>& lo, const simd<T, Abi>& hi);
+
+#include <cassert>
+#include <cstdint>
+#include <algorithm>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+template <typename T, typename Abi>
+bool equal(simd<T, Abi> a, simd<T, Abi> b) {
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void test_clamp() {
+  auto actual = clamp(fixed_size_simd<int, 16>([](int i) { return i - 8; }),
+                      fixed_size_simd<int, 16>([](int) { return 0; }),
+                      fixed_size_simd<int, 16>([](int) { return 5; }));
+
+  int expected[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5};
+
+  assert(
+      equal(fixed_size_simd<int, 16>(expected, element_aligned_tag()), actual));
+}
+
+int main() { test_clamp(); }
Index: libcxx/include/experimental/simd
===================================================================
--- libcxx/include/experimental/simd
+++ libcxx/include/experimental/simd
@@ -1273,7 +1273,13 @@
 
 // reductions [simd.reductions]
 template <class _Tp, class _Abi, class _BinaryOp = std::plus<_Tp>>
-_Tp reduce(const simd<_Tp, _Abi>&, _BinaryOp = _BinaryOp());
+_Tp reduce(const simd<_Tp, _Abi>& __v, _BinaryOp __op = _BinaryOp()) {
+  _Tp __acc = __v[0];
+  for (size_t __i = 1; __i < __v.size(); __i++) {
+    __acc = __op(__acc, __v[__i]);
+  }
+  return __acc;
+}
 
 template <class _MaskType, class _SimdType, class _BinaryOp>
 typename _SimdType::value_type
@@ -1306,30 +1312,63 @@
        bit_xor<typename _SimdType::value_type> binary_op);
 
 template <class _Tp, class _Abi>
-_Tp hmin(const simd<_Tp, _Abi>&);
+_Tp hmin(const simd<_Tp, _Abi>& __v) {
+  _Tp __acc = __v[0];
+  for (size_t __i = 1; __i < __v.size(); __i++) {
+    __acc = __acc > __v[__i] ? __v[__i] : __acc;
+  }
+  return __acc;
+}
+
 template <class _MaskType, class _SimdType>
 typename _SimdType::value_type
 hmin(const const_where_expression<_MaskType, _SimdType>&);
+
 template <class _Tp, class _Abi>
-_Tp hmax(const simd<_Tp, _Abi>&);
+_Tp hmax(const simd<_Tp, _Abi>& __v) {
+  _Tp __acc = __v[0];
+  for (size_t __i = 1; __i < __v.size(); __i++) {
+    __acc = __acc < __v[__i] ? __v[__i] : __acc;
+  }
+  return __acc;
+}
+
 template <class _MaskType, class _SimdType>
 typename _SimdType::value_type
 hmax(const const_where_expression<_MaskType, _SimdType>&);
 
 // algorithms [simd.alg]
 template <class _Tp, class _Abi>
-simd<_Tp, _Abi> min(const simd<_Tp, _Abi>&, const simd<_Tp, _Abi>&) noexcept;
+simd<_Tp, _Abi> min(const simd<_Tp, _Abi>& __a,
+                    const simd<_Tp, _Abi>& __b) noexcept {
+  simd<_Tp, _Abi> __v;
+  for (size_t __i = 0; __i < __v.size(); __i++) {
+    __v[__i] = std::min(__a[__i], __b[__i]);
+  }
+  return __v;
+}
 
 template <class _Tp, class _Abi>
-simd<_Tp, _Abi> max(const simd<_Tp, _Abi>&, const simd<_Tp, _Abi>&) noexcept;
+simd<_Tp, _Abi> max(const simd<_Tp, _Abi>& __a,
+                    const simd<_Tp, _Abi>& __b) noexcept {
+  simd<_Tp, _Abi> __v;
+  for (size_t __i = 0; __i < __v.size(); __i++) {
+    __v[__i] = std::max(__a[__i], __b[__i]);
+  }
+  return __v;
+}
 
 template <class _Tp, class _Abi>
 std::pair<simd<_Tp, _Abi>, simd<_Tp, _Abi>>
-minmax(const simd<_Tp, _Abi>&, const simd<_Tp, _Abi>&) noexcept;
+minmax(const simd<_Tp, _Abi>& __a, const simd<_Tp, _Abi>& __b) noexcept {
+  return std::make_pair(min(__a, __b), max(__a, __b));
+}
 
 template <class _Tp, class _Abi>
-simd<_Tp, _Abi> clamp(const simd<_Tp, _Abi>&, const simd<_Tp, _Abi>&,
-                      const simd<_Tp, _Abi>&);
+simd<_Tp, _Abi> clamp(const simd<_Tp, _Abi>& __v, const simd<_Tp, _Abi>& __lo,
+                      const simd<_Tp, _Abi>& __hi) {
+  return min(max(__v, __lo), __hi);
+}
 
 // [simd.whereexpr]
 // TODO implement where expressions.
@@ -1379,7 +1418,6 @@
 };
 
 // [simd.class]
-// TODO: implement simd
 template <class _Tp, class _Abi>
 class simd {
 public:
@@ -1504,43 +1542,180 @@
   value_type operator[](size_t __i) const { return __s_.__get(__i); }
 
   // unary operators [simd.unary]
-  simd& operator++();
-  simd operator++(int);
-  simd& operator--();
-  simd operator--(int);
+  simd& operator++() {
+    *this += simd(1);
+    return *this;
+  }
+
+  simd operator++(int) {
+    auto __tmp = *this;
+    ++*this;
+    return __tmp;
+  }
+
+  simd& operator--() {
+    *this -= simd(1);
+    return *this;
+  }
+
+  simd operator--(int) {
+    auto __tmp = *this;
+    --*this;
+    return __tmp;
+  }
+
   mask_type operator!() const;
-  simd operator~() const;
-  simd operator+() const;
-  simd operator-() const;
+
+  simd operator~() const {
+    simd __v;
+    for (size_t __i = 0; __i < size(); __i++) {
+      __v[__i] = ~(*this)[__i];
+    }
+    return __v;
+  }
+
+  simd operator+() const { return *this; }
+
+  simd operator-() const { return simd(0) - *this; }
 
   // binary operators [simd.binary]
-  friend simd operator+(const simd&, const simd&);
-  friend simd operator-(const simd&, const simd&);
-  friend simd operator*(const simd&, const simd&);
-  friend simd operator/(const simd&, const simd&);
-  friend simd operator%(const simd&, const simd&);
-  friend simd operator&(const simd&, const simd&);
-  friend simd operator|(const simd&, const simd&);
-  friend simd operator^(const simd&, const simd&);
-  friend simd operator<<(const simd&, const simd&);
-  friend simd operator>>(const simd&, const simd&);
-  friend simd operator<<(const simd&, int);
-  friend simd operator>>(const simd&, int);
+  // 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;
+  }
 
-  // compound assignment [simd.cassign]
-  friend simd& operator+=(simd&, const simd&);
-  friend simd& operator-=(simd&, const simd&);
-  friend simd& operator*=(simd&, const simd&);
-  friend simd& operator/=(simd&, const simd&);
-  friend simd& operator%=(simd&, const simd&);
-
-  friend simd& operator&=(simd&, const simd&);
-  friend simd& operator|=(simd&, const simd&);
-  friend simd& operator^=(simd&, const simd&);
-  friend simd& operator<<=(simd&, const simd&);
-  friend simd& operator>>=(simd&, const simd&);
-  friend simd& operator<<=(simd&, int);
-  friend simd& operator>>=(simd&, int);
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  friend simd operator<<(const simd& __a, int __offset) {
+    return __a << simd(__offset);
+  }
+
+  friend simd operator>>(const simd& __a, int __offset) {
+    return __a >> simd(__offset);
+  }
+
+  friend simd& operator+=(simd& __a, const simd& __b) {
+    return __a = __a + __b;
+  }
+
+  friend simd& operator-=(simd& __a, const simd& __b) {
+    return __a = __a - __b;
+  }
+
+  friend simd& operator*=(simd& __a, const simd& __b) {
+    return __a = __a * __b;
+  }
+
+  friend simd& operator/=(simd& __a, const simd& __b) {
+    return __a = __a / __b;
+  }
+
+  friend simd& operator%=(simd& __a, const simd& __b) {
+    return __a = __a % __b;
+  }
+
+  friend simd& operator&=(simd& __a, const simd& __b) {
+    return __a = __a & __b;
+  }
+
+  friend simd& operator|=(simd& __a, const simd& __b) {
+    return __a = __a | __b;
+  }
+
+  friend simd& operator^=(simd& __a, const simd& __b) {
+    return __a = __a ^ __b;
+  }
+
+  friend simd& operator<<=(simd& __a, const simd& __b) {
+    return __a = __a << __b;
+  }
+
+  friend simd& operator>>=(simd& __a, const simd& __b) {
+    return __a = __a >> __b;
+  }
+
+  friend simd& operator<<=(simd& __a, int __offset) {
+    return __a = __a << __offset;
+  }
+
+  friend simd& operator>>=(simd& __a, int __offset) {
+    return __a = __a >> __offset;
+  }
 
   // compares [simd.comparison]
   friend mask_type operator==(const simd&, const simd&);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to