Index: libcxx/include/experimental/simd =================================================================== --- libcxx/include/experimental/simd +++ libcxx/include/experimental/simd @@ -761,7 +761,10 @@ template 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 friend struct simd; @@ -769,6 +772,9 @@ template friend struct simd_mask; + template + friend class simd_mask; + __simd_storage<_Tp, _Abi>* __ptr_; size_t __index_; @@ -777,14 +783,23 @@ __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; } @@ -795,7 +810,7 @@ _Vp operator++(int) && { auto __val = __ptr_->__get(__index_); __ptr_->__set(__index_, __val + 1); - return __val; + return __to_value_type(__val); } __simd_reference operator--() && { @@ -805,47 +820,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); } }; @@ -897,6 +922,36 @@ !std::is_volatile<_Tp>::value && !std::is_same<_Tp, bool>::value; } +template +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 @@ -1324,7 +1379,13 @@ // reductions [simd.mask.reductions] template -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 bool any_of(const simd_mask<_Tp, _Abi>&) noexcept; template @@ -1540,6 +1601,9 @@ return simd_size<_Tp, _Abi>::value; } + template + friend class simd_mask; + private: __simd_storage<_Tp, _Abi> __s_; @@ -1824,12 +1888,53 @@ } // 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; + } #if !defined(_LIBCPP_HAS_NO_VECTOR_EXTENSION) && defined(_LIBCPP_COMPILER_CLANG) template @@ -1843,56 +1948,125 @@ // [simd.mask.class] template -// TODO: implement simd_mask class simd_mask { + using __element_type = typename __unsigned_traits::type; + + 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 = __simd_reference; 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 - simd_mask(const simd_mask<_Up, simd_abi::fixed_size>&) noexcept; + template < + class _Up, + class = typename std::enable_if< + !std::is_void<_Up>::value && + std::is_same>::value>::type> + simd_mask(const simd_mask<_Up, simd_abi::fixed_size>& __v) noexcept { + for (size_t __i = 0; __i < size(); __i++) { + (*this)[__i] = __v[__i]; + } + } // load constructor - template - simd_mask(const value_type*, _Flags); + template ::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 - void copy_from(const value_type*, _Flags); + typename std::enable_if::value>::type + copy_from(const value_type* __buffer, _Flags) { + *this = simd_mask(__buffer, _Flags()); + } + template - void copy_to(value_type*, _Flags) const; + typename std::enable_if::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 reference(&__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 !(__a ^ __b); + } + + friend simd_mask operator!=(const simd_mask& __a, + const simd_mask& __b) noexcept { + return __a ^ __b; + } }; _LIBCPP_END_NAMESPACE_EXPERIMENTAL_SIMD 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 #include @@ -194,7 +202,74 @@ } } +void test_relational_operators() { + fixed_size_simd 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( + expected, element_aligned_tag()))); + } + { + bool expected[] = { + false, true, true, + true, false, true, + true, true, false, + }; + assert(all_of((a != b) == fixed_size_simd_mask( + expected, element_aligned_tag()))); + } + { + bool expected[] = { + false, true, true, + false, false, true, + false, false, false, + }; + assert(all_of((a < b) == fixed_size_simd_mask( + expected, element_aligned_tag()))); + } + { + bool expected[] = { + true, true, true, + false, true, true, + false, false, true, + }; + assert(all_of((a <= b) == fixed_size_simd_mask( + expected, element_aligned_tag()))); + } + { + bool expected[] = { + false, false, false, + true, false, false, + true, true, false, + }; + assert(all_of((a > b) == fixed_size_simd_mask( + expected, element_aligned_tag()))); + } + { + bool expected[] = { + true, false, false, + true, true, false, + true, true, true, + }; + assert(all_of((a >= b) == fixed_size_simd_mask( + expected, element_aligned_tag()))); + } +} + int main() { test_pure_operators(); test_mutating_opreators(); + test_relational_operators(); } 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 + +// +// +// scalar access [simd.mask.subscr] +// reference operator[](size_t); +// value_type operator[](size_t) const; + +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_access() { + { + fixed_size_simd_mask 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 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.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 + +// +// +// [simd.mask.class] +// broadcast constructor +// explicit simd_mask(value_type) noexcept; + +#include + +using namespace std::experimental::parallelism_v2; + +void test_broadcast() { + { + native_simd_mask m(false); + for (size_t i = 0; i < m.size(); i++) { + assert(!m[i]); + } + } + { + native_simd_mask 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.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 + +// +// +// [simd.mask.class] +// simd() = default; + +#include +#include + +using namespace std::experimental::parallelism_v2; + +int main() { (void)native_simd_mask(); } 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 + +// +// +// [simd.mask.class] +// implicit type conversion constructor +// template simd(const simd>&); + +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_fixed_size_conversion() { + { + fixed_size_simd_mask m = fixed_size_simd_mask(false); + for (size_t i = 0; i < m.size(); i++) { + assert(!m[i]); + } + } + { + fixed_size_simd_mask m = fixed_size_simd_mask(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/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 + +// +// +// [simd.mask.class] +// load constructor +// template simd_mask(const value_type* mem, Flags); + +#include + +#include "test_macros.h" + +using namespace std::experimental::parallelism_v2; + +void test_load_ctor() { + { + bool buf[] = {false, true, true, false}; + fixed_size_simd_mask 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 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 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 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 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 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.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 + +// +// +// [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 +#include + +using namespace std::experimental::parallelism_v2; + +void test_pure_operators() { + assert(all_of(!simd_mask(false))); + assert(all_of(simd_mask(false) == + (simd_mask(false) && simd_mask(true)))); + assert(all_of(simd_mask(true) == + (simd_mask(false) || simd_mask(true)))); + assert(all_of(simd_mask(false) == + (simd_mask(false) & simd_mask(true)))); + assert(all_of(simd_mask(true) == + (simd_mask(false) | simd_mask(true)))); + assert(all_of(simd_mask(true) == + (simd_mask(false) ^ simd_mask(true)))); + assert(all_of(simd_mask(false) == + (simd_mask(true) ^ simd_mask(true)))); +} + +void test_mutating_opreators() { + { + simd_mask a(true); + a &= simd_mask(false); + assert(all_of(simd_mask(false) == a)); + } + { + simd_mask a(true); + a |= simd_mask(false); + assert(all_of(simd_mask(true) == a)); + } + { + simd_mask a(true); + a ^= simd_mask(false); + assert(all_of(simd_mask(true) == a)); + } + { + simd_mask a(true); + a ^= simd_mask(true); + assert(all_of(simd_mask(false) == a)); + } +} + +void test_relational_operators() { + assert(all_of(!(simd_mask(false) == simd_mask(true)))); + assert(all_of(simd_mask(false) != simd_mask(true))); + assert(all_of(simd_mask(false) == simd_mask(false))); + assert(all_of(!(simd_mask(false) != simd_mask(false)))); + assert(all_of(simd_mask(true) == simd_mask(true))); + assert(all_of(!(simd_mask(true) != simd_mask(true)))); +} + +int main() { + test_pure_operators(); + test_mutating_opreators(); + test_relational_operators(); +} 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 + +// +// +// loads [simd.mask.copy] +// template void copy_from(const value_type* mem, Flags); + +#include +#include + +#include "test_macros.h" + +using namespace std::experimental::parallelism_v2; + +template +auto not_supported_load(Args&&... args) -> decltype( + std::declval>().copy_from(std::forward(args)...), + void()) = delete; + +template +void not_supported_load(...) {} + +template +auto supported_load(Args&&... args) -> decltype( + std::declval>().copy_from(std::forward(args)...), + void()) {} + +template +void supported_load(...) = delete; + +void compile_load() { + supported_load((bool*)nullptr, element_aligned_tag()); + supported_load((bool*)nullptr, element_aligned_tag()); + supported_load((bool*)nullptr, element_aligned_tag()); + supported_load((bool*)nullptr, element_aligned_tag()); + supported_load((bool*)nullptr, element_aligned_tag()); + + not_supported_load((bool*)nullptr, int()); +} + +void test_load() { + alignas(32) bool buffer[] = {false, true, true, false}; + { + fixed_size_simd_mask a; + a.copy_from(buffer, element_aligned_tag()); + assert(!a[0]); + assert(a[1]); + assert(a[2]); + assert(!a[3]); + } + { + fixed_size_simd_mask a; + a.copy_from(buffer, vector_aligned_tag()); + assert(!a[0]); + assert(a[1]); + assert(a[2]); + assert(!a[3]); + } + { + fixed_size_simd_mask 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 a; + a.copy_from(buffer, element_aligned); + assert(!a[0]); + assert(a[1]); + assert(a[2]); + assert(!a[3]); + } + { + fixed_size_simd_mask a; + a.copy_from(buffer, vector_aligned); + assert(!a[0]); + assert(a[1]); + assert(a[2]); + assert(!a[3]); + } + { + fixed_size_simd_mask 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.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 + +// +// +// loads [simd.mask.copy] +// template void copy_to(value_type* mem, Flags) const; + +#include + +#include "test_macros.h" + +using namespace std::experimental::parallelism_v2; + +void test_store() { + fixed_size_simd_mask 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(); }