timshen updated this revision to Diff 129012.
timshen added a comment.

Rebased.


https://reviews.llvm.org/D41747

Files:
  libcxx/include/experimental/simd
  libcxx/test/std/experimental/simd/simd.elementwise/operators.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.access/default.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.cons/broadcast.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.cons/default.pass.cpp
  
libcxx/test/std/experimental/simd/simd.mask.cons/fixed_size_conversion.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.cons/load.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.elementwise/operators.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.mem/load.pass.cpp
  libcxx/test/std/experimental/simd/simd.mask.mem/store.pass.cpp

Index: libcxx/test/std/experimental/simd/simd.mask.mem/store.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.mem/store.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// loads [simd.mask.copy]
+// template <class Flags> void copy_to(value_type* mem, Flags) const;
+
+#include <experimental/simd>
+
+#include "test_macros.h"
+
+using namespace std::experimental::parallelism_v2;
+
+void test_store() {
+  fixed_size_simd_mask<int, 4> a;
+  a[0] = false;
+  a[1] = true;
+  a[2] = true;
+  a[3] = false;
+  {
+    alignas(32) bool buffer[4] = {0};
+    a.copy_to(buffer, element_aligned_tag());
+    assert(!buffer[0]);
+    assert(buffer[1]);
+    assert(buffer[2]);
+    assert(!buffer[3]);
+  }
+  {
+    alignas(32) bool buffer[4] = {0};
+    a.copy_to(buffer, vector_aligned_tag());
+    assert(!buffer[0]);
+    assert(buffer[1]);
+    assert(buffer[2]);
+    assert(!buffer[3]);
+  }
+  {
+    alignas(32) bool buffer[4] = {0};
+    a.copy_to(buffer, overaligned_tag<32>());
+    assert(!buffer[0]);
+    assert(buffer[1]);
+    assert(buffer[2]);
+    assert(!buffer[3]);
+  }
+
+#if TEST_STD_VER > 14
+  {
+    alignas(32) bool buffer[4] = {0};
+    a.copy_to(buffer, element_aligned);
+    assert(!buffer[0]);
+    assert(buffer[1]);
+    assert(buffer[2]);
+    assert(!buffer[3]);
+  }
+  {
+    alignas(32) bool buffer[4] = {0};
+    a.copy_to(buffer, vector_aligned);
+    assert(!buffer[0]);
+    assert(buffer[1]);
+    assert(buffer[2]);
+    assert(!buffer[3]);
+  }
+  {
+    alignas(32) bool buffer[4] = {0};
+    a.copy_to(buffer, overaligned<32>);
+    assert(!buffer[0]);
+    assert(buffer[1]);
+    assert(buffer[2]);
+    assert(!buffer[3]);
+  }
+#endif
+}
+
+int main() { test_store(); }
Index: libcxx/test/std/experimental/simd/simd.mask.mem/load.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.mem/load.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// loads [simd.mask.copy]
+// template <class Flags> void copy_from(const value_type* mem, Flags);
+
+#include <experimental/simd>
+#include <cstdint>
+
+#include "test_macros.h"
+
+using namespace std::experimental::parallelism_v2;
+
+template <class T, class... Args>
+auto not_supported_load(Args&&... args) -> decltype(
+    std::declval<native_simd_mask<T>>().copy_from(std::forward<Args>(args)...),
+    void()) = delete;
+
+template <class T>
+void not_supported_load(...) {}
+
+template <class T, class... Args>
+auto supported_load(Args&&... args) -> decltype(
+    std::declval<native_simd_mask<T>>().copy_from(std::forward<Args>(args)...),
+    void()) {}
+
+template <class T>
+void supported_load(...) = delete;
+
+void compile_load() {
+  supported_load<int>((bool*)nullptr, element_aligned_tag());
+  supported_load<uint32_t>((bool*)nullptr, element_aligned_tag());
+  supported_load<double>((bool*)nullptr, element_aligned_tag());
+  supported_load<uint16_t>((bool*)nullptr, element_aligned_tag());
+  supported_load<uint32_t>((bool*)nullptr, element_aligned_tag());
+
+  not_supported_load<int>((bool*)nullptr, int());
+}
+
+void test_load() {
+  alignas(32) bool buffer[] = {false, true, true, false};
+  {
+    fixed_size_simd_mask<int32_t, 4> a;
+    a.copy_from(buffer, element_aligned_tag());
+    assert(!a[0]);
+    assert(a[1]);
+    assert(a[2]);
+    assert(!a[3]);
+  }
+  {
+    fixed_size_simd_mask<int32_t, 4> a;
+    a.copy_from(buffer, vector_aligned_tag());
+    assert(!a[0]);
+    assert(a[1]);
+    assert(a[2]);
+    assert(!a[3]);
+  }
+  {
+    fixed_size_simd_mask<int32_t, 4> a;
+    a.copy_from(buffer, overaligned_tag<32>());
+    assert(!a[0]);
+    assert(a[1]);
+    assert(a[2]);
+    assert(!a[3]);
+  }
+
+#if TEST_STD_VER > 14
+  {
+    fixed_size_simd_mask<int32_t, 4> a;
+    a.copy_from(buffer, element_aligned);
+    assert(!a[0]);
+    assert(a[1]);
+    assert(a[2]);
+    assert(!a[3]);
+  }
+  {
+    fixed_size_simd_mask<int32_t, 4> a;
+    a.copy_from(buffer, vector_aligned);
+    assert(!a[0]);
+    assert(a[1]);
+    assert(a[2]);
+    assert(!a[3]);
+  }
+  {
+    fixed_size_simd_mask<int32_t, 4> a;
+    a.copy_from(buffer, overaligned<32>);
+    assert(!a[0]);
+    assert(a[1]);
+    assert(a[2]);
+    assert(!a[3]);
+  }
+#endif
+}
+
+int main() { test_load(); }
Index: libcxx/test/std/experimental/simd/simd.mask.elementwise/operators.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.elementwise/operators.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// [simd.mask.class]
+// // unary operators [simd.mask.unary]
+// simd_mask operator!() const noexcept;
+//
+// // simd_mask binary operators [simd.mask.binary]
+// friend simd_mask operator&&(const simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask operator||(const simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask operator& (const simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask operator| (const simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask operator^ (const simd_mask&, const simd_mask&) noexcept;
+//
+// // simd_mask compound assignment [simd.mask.cassign]
+// friend simd_mask& operator&=(simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask& operator|=(simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask& operator^=(simd_mask&, const simd_mask&) noexcept;
+//
+// // simd_mask compares [simd.mask.comparison]
+// friend simd_mask operator==(const simd_mask&, const simd_mask&) noexcept;
+// friend simd_mask operator!=(const simd_mask&, const simd_mask&) noexcept;
+
+#include <cstdint>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_pure_operators() {
+  assert(all_of(!simd_mask<int>(false)));
+  assert(all_of(simd_mask<int>(false) ==
+                (simd_mask<int>(false) && simd_mask<int>(true))));
+  assert(all_of(simd_mask<int>(true) ==
+                (simd_mask<int>(false) || simd_mask<int>(true))));
+  assert(all_of(simd_mask<int>(false) ==
+                (simd_mask<int>(false) & simd_mask<int>(true))));
+  assert(all_of(simd_mask<int>(true) ==
+                (simd_mask<int>(false) | simd_mask<int>(true))));
+  assert(all_of(simd_mask<int>(true) ==
+                (simd_mask<int>(false) ^ simd_mask<int>(true))));
+  assert(all_of(simd_mask<int>(false) ==
+                (simd_mask<int>(true) ^ simd_mask<int>(true))));
+}
+
+void test_mutating_opreators() {
+  {
+    simd_mask<int> a(true);
+    a &= simd_mask<int>(false);
+    assert(all_of(simd_mask<int>(false) == a));
+  }
+  {
+    simd_mask<int> a(true);
+    a |= simd_mask<int>(false);
+    assert(all_of(simd_mask<int>(true) == a));
+  }
+  {
+    simd_mask<int> a(true);
+    a ^= simd_mask<int>(false);
+    assert(all_of(simd_mask<int>(true) == a));
+  }
+  {
+    simd_mask<int> a(true);
+    a ^= simd_mask<int>(true);
+    assert(all_of(simd_mask<int>(false) == a));
+  }
+}
+
+void test_relational_operators() {
+  assert(all_of(!(simd_mask<int>(false) == simd_mask<int>(true))));
+  assert(all_of(simd_mask<int>(false) != simd_mask<int>(true)));
+  assert(all_of(simd_mask<int>(false) == simd_mask<int>(false)));
+  assert(all_of(!(simd_mask<int>(false) != simd_mask<int>(false))));
+  assert(all_of(simd_mask<int>(true) == simd_mask<int>(true)));
+  assert(all_of(!(simd_mask<int>(true) != simd_mask<int>(true))));
+}
+
+int main() {
+  test_pure_operators();
+  test_mutating_opreators();
+  test_relational_operators();
+}
Index: libcxx/test/std/experimental/simd/simd.mask.cons/load.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.cons/load.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// [simd.mask.class]
+// load constructor
+// template <class Flags> simd_mask(const value_type* mem, Flags);
+
+#include <experimental/simd>
+
+#include "test_macros.h"
+
+using namespace std::experimental::parallelism_v2;
+
+void test_load_ctor() {
+  {
+    bool buf[] = {false, true, true, false};
+    fixed_size_simd_mask<int, 4> m(buf, element_aligned_tag());
+    assert(buf[0] == m[0]);
+    assert(buf[1] == m[1]);
+    assert(buf[2] == m[2]);
+    assert(buf[3] == m[3]);
+  }
+  {
+    bool buf[] = {false, true, true, false};
+    fixed_size_simd_mask<int, 4> m(buf, vector_aligned_tag());
+    assert(buf[0] == m[0]);
+    assert(buf[1] == m[1]);
+    assert(buf[2] == m[2]);
+    assert(buf[3] == m[3]);
+  }
+  {
+    bool buf[] = {false, true, true, false};
+    fixed_size_simd_mask<int, 4> m(buf, overaligned_tag<32>());
+    assert(buf[0] == m[0]);
+    assert(buf[1] == m[1]);
+    assert(buf[2] == m[2]);
+    assert(buf[3] == m[3]);
+  }
+#if TEST_STD_VER > 14
+  {
+    bool buf[] = {false, true, true, false};
+    fixed_size_simd_mask<int, 4> m(buf, element_aligned);
+    assert(buf[0] == m[0]);
+    assert(buf[1] == m[1]);
+    assert(buf[2] == m[2]);
+    assert(buf[3] == m[3]);
+  }
+  {
+    bool buf[] = {false, true, true, false};
+    fixed_size_simd_mask<int, 4> m(buf, vector_aligned);
+    assert(buf[0] == m[0]);
+    assert(buf[1] == m[1]);
+    assert(buf[2] == m[2]);
+    assert(buf[3] == m[3]);
+  }
+  {
+    bool buf[] = {false, true, true, false};
+    fixed_size_simd_mask<int, 4> m(buf, overaligned<32>);
+    assert(buf[0] == m[0]);
+    assert(buf[1] == m[1]);
+    assert(buf[2] == m[2]);
+    assert(buf[3] == m[3]);
+  }
+#endif
+}
+
+int main() { test_load_ctor(); }
Index: libcxx/test/std/experimental/simd/simd.mask.cons/fixed_size_conversion.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.cons/fixed_size_conversion.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// [simd.mask.class]
+// implicit type conversion constructor
+// template <class U> simd(const simd<U, simd_abi::fixed_size<size()>>&);
+
+#include <cstdint>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_fixed_size_conversion() {
+  {
+    fixed_size_simd_mask<float, 4> m = fixed_size_simd_mask<int, 4>(false);
+    for (size_t i = 0; i < m.size(); i++) {
+      assert(!m[i]);
+    }
+  }
+  {
+    fixed_size_simd_mask<float, 4> m = fixed_size_simd_mask<int, 4>(true);
+    for (size_t i = 0; i < m.size(); i++) {
+      assert(m[i]);
+    }
+  }
+}
+
+int main() { test_fixed_size_conversion(); }
Index: libcxx/test/std/experimental/simd/simd.mask.cons/default.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.cons/default.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// [simd.mask.class]
+// simd() = default;
+
+#include <cstdint>
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+int main() { (void)native_simd_mask<int32_t>(); }
Index: libcxx/test/std/experimental/simd/simd.mask.cons/broadcast.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.cons/broadcast.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// [simd.mask.class]
+// broadcast constructor
+// explicit simd_mask(value_type) noexcept;
+
+#include <experimental/simd>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_broadcast() {
+  {
+    native_simd_mask<int> m(false);
+    for (size_t i = 0; i < m.size(); i++) {
+      assert(!m[i]);
+    }
+  }
+  {
+    native_simd_mask<int> m(true);
+    for (size_t i = 0; i < m.size(); i++) {
+      assert(m[i]);
+    }
+  }
+}
+
+int main() { test_broadcast(); }
Index: libcxx/test/std/experimental/simd/simd.mask.access/default.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/experimental/simd/simd.mask.access/default.pass.cpp
@@ -0,0 +1,210 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+//
+// scalar access [simd.mask.subscr]
+// reference operator[](size_t);
+// value_type operator[](size_t) const;
+
+#include <experimental/simd>
+#include <cassert>
+#include <cstdint>
+
+using namespace std::experimental::parallelism_v2;
+
+void test_access() {
+  {
+    fixed_size_simd_mask<int, 2> a(false), b(true);
+
+    assert(bool(a[0]) == false);
+    assert(bool(!a[0]) == true);
+    assert(bool(~a[0]) == true);
+    assert(bool(+a[0]) == false);
+    assert(bool(-a[0]) == false);
+    assert(bool(a[0] + b[0]) == true);
+    assert(bool(a[0] - b[0]) == true);
+    assert(bool(a[0] * b[0]) == false);
+    assert(bool(a[0] / b[0]) == false);
+    assert(bool(a[0] % b[0]) == false);
+    assert(bool(a[0] << b[0]) == false);
+    assert(bool(a[0] >> b[0]) == false);
+    assert(bool(a[0] < b[0]) == true);
+    assert(bool(a[0] <= b[0]) == true);
+    assert(bool(a[0] > b[0]) == false);
+    assert(bool(a[0] >= b[0]) == false);
+    assert(bool(a[0] == b[0]) == false);
+    assert(bool(a[0] != b[0]) == true);
+    assert(bool((a[0] & b[0])) == false);
+    assert(bool((a[0] | b[0])) == true);
+    assert(bool((a[0] ^ b[0])) == true);
+    assert(bool((a[0] && b[0])) == false);
+    assert(bool((a[0] || b[0])) == true);
+
+    {
+      auto c = a;
+      ++c[0];
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      auto ret = c[0]++;
+      assert(ret == false);
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      --c[0];
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      auto ret = c[0]--;
+      assert(ret == false);
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+
+    {
+      auto c = a;
+      c[0] += b[0];
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] -= b[0];
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = b;
+      c[0] *= a[0];
+      assert(bool(c[0]) == false);
+      assert(bool(c[1]) == true);
+    }
+    {
+      auto c = a;
+      c[0] /= b[0];
+      assert(bool(c[0]) == false);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] %= b[0];
+      assert(bool(c[0]) == false);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] >>= b[0];
+      assert(bool(c[0]) == false);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] <<= b[0];
+      assert(bool(c[0]) == false);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] &= b[0];
+      assert(bool(c[0]) == false);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] |= b[0];
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+    {
+      auto c = a;
+      c[0] ^= b[0];
+      assert(bool(c[0]) == true);
+      assert(bool(c[1]) == false);
+    }
+
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] += a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] -= a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] *= a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] /= b[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] %= b[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] >>= a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] <<= a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] &= a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] |= a[0]));
+    }
+    {
+      auto c = a;
+      (void)(a[0] + (c[0] ^= a[0]));
+    }
+  }
+  {
+    const fixed_size_simd_mask<int, 2> a(false), b(true);
+
+    assert(bool(a[0]) == false);
+    assert(bool(!a[0]) == true);
+    assert(bool(~a[0]) == true);
+    assert(bool(+a[0]) == false);
+    assert(bool(-a[0]) == false);
+    assert(bool(a[0] + b[0]) == true);
+    assert(bool(a[0] - b[0]) == true);
+    assert(bool(a[0] * b[0]) == false);
+    assert(bool(a[0] / b[0]) == false);
+    assert(bool(a[0] % b[0]) == false);
+    assert(bool(a[0] << b[0]) == false);
+    assert(bool(a[0] >> b[0]) == false);
+    assert(bool(a[0] < b[0]) == true);
+    assert(bool(a[0] <= b[0]) == true);
+    assert(bool(a[0] > b[0]) == false);
+    assert(bool(a[0] >= b[0]) == false);
+    assert(bool(a[0] == b[0]) == false);
+    assert(bool(a[0] != b[0]) == true);
+    assert(bool((a[0] & b[0])) == false);
+    assert(bool((a[0] | b[0])) == true);
+    assert(bool((a[0] ^ b[0])) == true);
+    assert(bool((a[0] && b[0])) == false);
+    assert(bool((a[0] || b[0])) == true);
+  }
+}
+
+int main() { test_access(); }
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
@@ -49,6 +49,14 @@
 // friend simd& operator>>=(simd&, const simd&);
 // friend simd& operator<<=(simd&, int);
 // friend simd& operator>>=(simd&, int);
+//
+// // compares [simd.comparison]
+// friend mask_type operator==(const simd&, const simd&);
+// friend mask_type operator!=(const simd&, const simd&);
+// friend mask_type operator>=(const simd&, const simd&);
+// friend mask_type operator<=(const simd&, const simd&);
+// friend mask_type operator> (const simd&, const simd&);
+// friend mask_type operator< (const simd&, const simd&);
 
 #include <cassert>
 #include <cstdint>
@@ -194,7 +202,74 @@
   }
 }
 
+void test_relational_operators() {
+  fixed_size_simd<int, 9> a, b;
+  {
+    int buf[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
+    a.copy_from(buf, element_aligned_tag());
+  }
+  {
+    int buf[] = {1, 2, 3, 1, 2, 3, 1, 2, 3};
+    b.copy_from(buf, element_aligned_tag());
+  }
+  {
+    bool expected[] = {
+      true, false, false,
+      false, true, false,
+      false, false, true,
+    };
+    assert(all_of((a == b) == fixed_size_simd_mask<int, 9>(
+                                  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>(
+                                  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>(
+                                 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>(
+                                  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>(
+                                 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>(
+                                  expected, element_aligned_tag())));
+  }
+}
+
 int main() {
   test_pure_operators();
   test_mutating_opreators();
+  test_relational_operators();
 }
Index: libcxx/include/experimental/simd
===================================================================
--- libcxx/include/experimental/simd
+++ libcxx/include/experimental/simd
@@ -706,30 +706,45 @@
 
 template <class _Vp, class _Tp, class _Abi>
 class __simd_reference {
-  static_assert(std::is_same<_Vp, _Tp>::value, "");
+  static_assert(std::is_same<_Vp, _Tp>::value ||
+                    (std::is_same<_Vp, bool>::value &&
+                     std::is_unsigned<_Tp>::value),
+                "");
 
   template <class, class, class>
   friend struct __simd_ref_traits;
 
   template <class, class>
   friend class simd;
 
+  template <class, class>
+  friend class simd_mask;
+
   __simd_storage<_Tp, _Abi>* __ptr_;
   size_t __index_;
 
   __simd_reference(__simd_storage<_Tp, _Abi>* __ptr, size_t __index)
       : __ptr_(__ptr), __index_(__index) {}
 
   __simd_reference(const __simd_reference&) = default;
 
+  static _Vp __to_value_type(_Tp __val) { return __val; }
+
+  static _Tp __from_value_type(_Vp __val) {
+    if (std::is_same<_Vp, bool>::value) {
+      return __val ? -1 : 0;
+    }
+    return __val;
+  }
+
 public:
   __simd_reference() = delete;
   __simd_reference& operator=(const __simd_reference&) = delete;
 
-  operator _Vp() const { return __ptr_->__get(__index_); }
+  operator _Vp() const { return __to_value_type(__ptr_->__get(__index_)); }
 
-  __simd_reference operator=(_Vp __value) && {
-    __ptr_->__set(__index_, __value);
+  __simd_reference operator=(_Vp __val) && {
+    __ptr_->__set(__index_, __from_value_type(__val));
     return *this;
   }
 
@@ -740,7 +755,7 @@
   _Vp operator++(int) && {
     auto __val = __ptr_->__get(__index_);
     __ptr_->__set(__index_, __val + 1);
-    return __val;
+    return __to_value_type(__val);
   }
 
   __simd_reference operator--() && {
@@ -750,47 +765,57 @@
   _Vp operator--(int) && {
     auto __val = __ptr_->__get(__index_);
     __ptr_->__set(__index_, __val - 1);
-    return __val;
+    return __to_value_type(__val);
   }
 
-  __simd_reference operator+=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) + __value;
+  __simd_reference operator+=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) + __from_value_type(__val);
   }
 
-  __simd_reference operator-=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) - __value;
+  __simd_reference operator-=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) - __from_value_type(__val);
   }
 
-  __simd_reference operator*=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) * __value;
+  __simd_reference operator*=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) * __from_value_type(__val);
   }
 
-  __simd_reference operator/=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) / __value;
+  __simd_reference operator/=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) / __from_value_type(__val);
   }
 
-  __simd_reference operator%=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) % __value;
+  __simd_reference operator%=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) % __from_value_type(__val);
   }
 
-  __simd_reference operator>>=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) >> __value;
+  __simd_reference operator>>=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) >> __from_value_type(__val);
   }
 
-  __simd_reference operator<<=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) << __value;
+  __simd_reference operator<<=(_Vp __val) && {
+    return std::move(*this) = __ptr_->__get(__index_)
+                              << __from_value_type(__val);
   }
 
-  __simd_reference operator&=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) & __value;
+  __simd_reference operator&=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) & __from_value_type(__val);
   }
 
-  __simd_reference operator|=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) | __value;
+  __simd_reference operator|=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) | __from_value_type(__val);
   }
 
-  __simd_reference operator^=(_Vp __value) && {
-    return std::move(*this) = __ptr_->__get(__index_) ^ __value;
+  __simd_reference operator^=(_Vp __val) && {
+    return std::move(*this) =
+               __ptr_->__get(__index_) ^ __from_value_type(__val);
   }
 };
 
@@ -875,6 +900,36 @@
          !std::is_volatile<_Tp>::value && !std::is_same<_Tp, bool>::value;
 }
 
+template <size_t __num_bytes>
+struct __unsigned_traits {};
+
+template <>
+struct __unsigned_traits<1> {
+  using type = uint8_t;
+};
+
+template <>
+struct __unsigned_traits<2> {
+  using type = uint16_t;
+};
+
+template <>
+struct __unsigned_traits<4> {
+  using type = uint32_t;
+};
+
+template <>
+struct __unsigned_traits<8> {
+  using type = uint64_t;
+};
+
+#if !defined(_LIBCPP_HAS_NO_INT128)
+template <>
+struct __unsigned_traits<16> {
+  using type = __uint128_t;
+};
+#endif // !defined(_LIBCPP_HAS_NO_INT128)
+
 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_SIMD
 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_SIMD_ABI
 
@@ -1254,7 +1309,13 @@
 
 // reductions [simd.mask.reductions]
 template <class _Tp, class _Abi>
-bool all_of(const simd_mask<_Tp, _Abi>&) noexcept;
+bool all_of(const simd_mask<_Tp, _Abi>& __m) noexcept {
+  bool __ret = true;
+  for (size_t __i = 0; __i < __m.size(); __i++) {
+    __ret &= __m[__i];
+  }
+  return __ret;
+}
 template <class _Tp, class _Abi>
 bool any_of(const simd_mask<_Tp, _Abi>&) noexcept;
 template <class _Tp, class _Abi>
@@ -1470,6 +1531,9 @@
     return simd_size<_Tp, _Abi>::value;
   }
 
+  template <class, class>
+  friend class simd_mask;
+
 private:
   __simd_storage<_Tp, _Abi> __s_;
 
@@ -1757,66 +1821,179 @@
   }
 
   // compares [simd.comparison]
-  friend mask_type operator==(const simd&, const simd&);
-  friend mask_type operator!=(const simd&, const simd&);
-  friend mask_type operator>=(const simd&, const simd&);
-  friend mask_type operator<=(const simd&, const simd&);
-  friend mask_type operator>(const simd&, const simd&);
-  friend mask_type operator<(const simd&, const simd&);
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
+
+  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;
+  }
 };
 
 // [simd.mask.class]
 template <class _Tp, class _Abi>
-// TODO: implement simd_mask
 class simd_mask {
+  using __element_type = typename __unsigned_traits<sizeof(_Tp)>::type;
+  using __ref_traits = __simd_ref_traits<bool, __element_type, _Abi>;
+
+  simd<__element_type, _Abi> __s_;
+
+  explicit simd_mask(const simd<__element_type, _Abi>& __mask) : __s_(__mask) {}
+
 public:
   using value_type = bool;
-  // TODO: this is strawman implementation. Turn it into a proxy type.
-  using reference = bool&;
+  using reference = typename __ref_traits::type;
   using simd_type = simd<_Tp, _Abi>;
   using abi_type = _Abi;
-  static constexpr size_t size() noexcept;
+
+  static constexpr size_t size() noexcept {
+    return simd<__element_type, _Abi>::size();
+  }
+
   simd_mask() = default;
 
   // broadcast constructor
-  explicit simd_mask(value_type) noexcept;
+  explicit simd_mask(value_type __value) noexcept {
+    for (size_t __i = 0; __i < size(); __i++) {
+      (*this)[__i] = __value;
+    }
+  }
 
   // implicit type conversion constructor
-  template <class _Up>
-  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>&) noexcept;
+  template <
+      class _Up,
+      class = typename std::enable_if<
+          !std::is_void<_Up>::value &&
+          std::is_same<abi_type, simd_abi::fixed_size<size()>>::value>::type>
+  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __v) noexcept {
+    for (size_t __i = 0; __i < size(); __i++) {
+      (*this)[__i] = __v[__i];
+    }
+  }
 
   // load constructor
-  template <class _Flags>
-  simd_mask(const value_type*, _Flags);
+  template <class _Flags, class = typename std::enable_if<
+                              is_simd_flag_type<_Flags>::value>::type>
+  simd_mask(const value_type* __buffer, _Flags) {
+    for (size_t __i = 0; __i < size(); __i++) {
+      (*this)[__i] = __buffer[__i];
+    }
+  }
 
   // loads [simd.mask.copy]
   template <class _Flags>
-  void copy_from(const value_type*, _Flags);
+  typename std::enable_if<is_simd_flag_type<_Flags>::value>::type
+  copy_from(const value_type* __buffer, _Flags) {
+    *this = simd_mask(__buffer, _Flags());
+  }
+
   template <class _Flags>
-  void copy_to(value_type*, _Flags) const;
+  typename std::enable_if<is_simd_flag_type<_Flags>::value>::type
+  copy_to(value_type* __buffer, _Flags) const {
+    for (size_t __i = 0; __i < size(); __i++) {
+      __buffer[__i] = (*this)[__i];
+    }
+  }
 
   // scalar access [simd.mask.subscr]
-  reference operator[](size_t);
-  value_type operator[](size_t) const;
+  reference operator[](size_t __i) {
+    return __ref_traits::__ref(&__s_.__s_, __i);
+  }
+
+  value_type operator[](size_t __i) const { return __s_[__i]; }
 
   // unary operators [simd.mask.unary]
-  simd_mask operator!() const noexcept;
+  simd_mask operator!() const noexcept { return simd_mask(~__s_); }
 
   // simd_mask binary operators [simd.mask.binary]
-  friend simd_mask operator&&(const simd_mask&, const simd_mask&) noexcept;
-  friend simd_mask operator||(const simd_mask&, const simd_mask&) noexcept;
-  friend simd_mask operator&(const simd_mask&, const simd_mask&)noexcept;
-  friend simd_mask operator|(const simd_mask&, const simd_mask&) noexcept;
-  friend simd_mask operator^(const simd_mask&, const simd_mask&) noexcept;
+  friend simd_mask operator&&(const simd_mask& __a,
+                              const simd_mask& __b) noexcept {
+    return __a & __b;
+  }
+
+  friend simd_mask operator||(const simd_mask& __a,
+                              const simd_mask& __b) noexcept {
+    return __a | __b;
+  }
+
+  friend simd_mask operator&(const simd_mask& __a,
+                             const simd_mask& __b) noexcept {
+    return simd_mask(__a.__s_ & __b.__s_);
+  }
+
+  friend simd_mask operator|(const simd_mask& __a,
+                             const simd_mask& __b) noexcept {
+    return simd_mask(__a.__s_ | __b.__s_);
+  }
+
+  friend simd_mask operator^(const simd_mask& __a,
+                             const simd_mask& __b) noexcept {
+    return simd_mask(__a.__s_ ^ __b.__s_);
+  }
 
   // simd_mask compound assignment [simd.mask.cassign]
-  friend simd_mask& operator&=(simd_mask&, const simd_mask&) noexcept;
-  friend simd_mask& operator|=(simd_mask&, const simd_mask&) noexcept;
-  friend simd_mask& operator^=(simd_mask&, const simd_mask&) noexcept;
+  friend simd_mask& operator&=(simd_mask& __a, const simd_mask& __b) noexcept {
+    return __a = __a & __b;
+  }
+
+  friend simd_mask& operator|=(simd_mask& __a, const simd_mask& __b) noexcept {
+    return __a = __a | __b;
+  }
+
+  friend simd_mask& operator^=(simd_mask& __a, const simd_mask& __b) noexcept {
+    return __a = __a ^ __b;
+  }
 
   // simd_mask compares [simd.mask.comparison]
-  friend simd_mask operator==(const simd_mask&, const simd_mask&) noexcept;
-  friend simd_mask operator!=(const simd_mask&, const simd_mask&) noexcept;
+  friend simd_mask operator==(const simd_mask& __a,
+                              const simd_mask& __b) noexcept {
+    return simd_mask(__a.__s_ == __b.__s_);
+  }
+
+  friend simd_mask operator!=(const simd_mask& __a,
+                              const simd_mask& __b) noexcept {
+    return simd_mask(__a.__s_ != __b.__s_);
+  }
 };
 
 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_SIMD
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to