Index: libcxx/include/experimental/simd =================================================================== --- libcxx/include/experimental/simd +++ libcxx/include/experimental/simd @@ -1273,7 +1273,13 @@ // reductions [simd.reductions] template > -_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 typename _SimdType::value_type @@ -1306,30 +1312,63 @@ bit_xor binary_op); template -_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 typename _SimdType::value_type hmin(const const_where_expression<_MaskType, _SimdType>&); + template -_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 typename _SimdType::value_type hmax(const const_where_expression<_MaskType, _SimdType>&); // algorithms [simd.alg] template -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 -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 std::pair, 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 -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 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&); 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 + +// +// +// template T hmax(const simd&); +// template T hmax(const const_where_expression&); + +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_hmax() { + { + int a[] = {2, 5, -4, 6}; + assert(hmax(fixed_size_simd(a, element_aligned_tag())) == 6); + } + { + int a[] = {6, 2, 5, -4}; + assert(hmax(fixed_size_simd(a, element_aligned_tag())) == 6); + } + { + int a[] = {-4, 6, 2, 5}; + assert(hmax(fixed_size_simd(a, element_aligned_tag())) == 6); + } + { + int a[] = {5, -4, 6, 2}; + assert(hmax(fixed_size_simd(a, element_aligned_tag())) == 6); + } +} + +int main() { test_hmax(); } 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 + +// +// +// template T hmin(const simd&); +// template T hmin(const const_where_expression&); + +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_hmin() { + { + int a[] = {2, 5, -4, 6}; + assert(hmin(fixed_size_simd(a, element_aligned_tag())) == -4); + } + { + int a[] = {6, 2, 5, -4}; + assert(hmin(fixed_size_simd(a, element_aligned_tag())) == -4); + } + { + int a[] = {-4, 6, 2, 5}; + assert(hmin(fixed_size_simd(a, element_aligned_tag())) == -4); + } + { + int a[] = {5, -4, 6, 2}; + assert(hmin(fixed_size_simd(a, element_aligned_tag())) == -4); + } +} + +int main() { test_hmin(); } 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 + +// +// +// // reductions [simd.reductions] +// template > +// T reduce(const simd&, BinaryOperation = BinaryOperation()); +// +// template +// typename V::value_type reduce(const const_where_expression& x, +// typename V::value_type neutral_element, BinaryOperation binary_op); +// +// template +// typename V::value_type reduce(const const_where_expression& x, plus<> binary_op = plus<>()); +// +// template +// typename V::value_type reduce(const const_where_expression& x, multiplies<> binary_op); +// +// template +// typename V::value_type reduce(const const_where_expression& x, bit_and<> binary_op); +// +// template +// typename V::value_type reduce(const const_where_expression& x, bit_or<> binary_op); +// +// template +// typename V::value_type reduce(const const_where_expression& x, bit_xor<> binary_op); + +#include +#include +#include + +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::size(); + assert(reduce(native_simd([](int i) { return i; })) == n * (n - 1) / 2); + assert(reduce(native_simd([](int i) { return i; }), std::plus()) == + n * (n - 1) / 2); + assert(reduce(native_simd([](int i) { return i + 1; }), + std::multiplies()) == factorial(n)); +} + +int main() { test_reduce(); } 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 + +// +// +// template +// simd +// clamp(const simd& v, const simd& lo, const simd& hi); + +#include +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +template +bool equal(simd a, simd 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 i) { return i - 8; }), + fixed_size_simd([](int) { return 0; }), + fixed_size_simd([](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(expected, element_aligned_tag()), actual)); +} + +int main() { test_clamp(); } 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 + +// +// +// template +// simd +// max(const simd&, const simd&) noexcept; + +#include +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +template +bool equal(simd a, simd 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::size(); + assert( + equal(max(native_simd([](int i) { return i; }), + native_simd([n](int i) { return n - 1 - i; })), + native_simd([n](int i) { return std::max(i, n - 1 - i); }))); +} + +int main() { test_max(); } 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 + +// +// +// template +// simd +// min(const simd&, const simd&) noexcept; + +#include +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +template +bool equal(simd a, simd 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::size(); + assert( + equal(min(native_simd([](int i) { return i; }), + native_simd([n](int i) { return n - 1 - i; })), + native_simd([n](int i) { return std::min(i, n - 1 - i); }))); +} + +int main() { test_min(); } 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 + +// +// +// template +// std::pair, simd> +// minmax(const simd&, const simd&) noexcept; + +#include +#include +#include +#include + +using namespace std::experimental::parallelism_v2; + +template +bool equal(simd a, simd 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::size(); + native_simd mi, mx; + std::tie(mi, mx) = minmax(native_simd([](int i) { return i; }), + native_simd([n](int i) { return n - 1 - i; })), + assert(equal(mi, native_simd([n](int i) { + return std::min(i, n - 1 - i); + }))); + assert(equal( + mx, native_simd([n](int i) { return std::max(i, n - 1 - i); }))); +} + +int main() { test_minmax(); } 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 + +// +// +// // 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 +#include +#include + +using namespace std::experimental::parallelism_v2; + +template +bool equal(simd a, simd 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 a(42), b(4); + + assert(equal(~a, native_simd(~42))); + assert(equal(+a, a)); + assert(equal(-a, native_simd(-42))); + assert(equal(a + b, native_simd(42 + 4))); + assert(equal(a - b, native_simd(42 - 4))); + assert(equal(a * b, native_simd(42 * 4))); + assert(equal(a / b, native_simd(42 / 4))); + assert(equal(a % b, native_simd(42 % 4))); + assert(equal(a & b, native_simd(42 & 4))); + assert(equal(a | b, native_simd(42 | 4))); + assert(equal(a ^ b, native_simd(42 ^ 4))); + assert(equal(a << b, native_simd(42 << 4))); + assert(equal(a >> b, native_simd(42 >> 4))); + assert(equal(a << 4, native_simd(42 << 4))); + assert(equal(a >> 4, native_simd(42 >> 4))); + } + { + native_simd a([](int i) { return 2 * i + 1; }), + b([](int i) { return i + 1; }); + + assert(equal(~a, native_simd([](int i) { return ~(2 * i + 1); }))); + assert(equal(+a, a)); + assert(equal(-a, native_simd([](int i) { return -(2 * i + 1); }))); + assert(equal(a + b, native_simd([](int i) { return 3 * i + 2; }))); + assert(equal(a - b, native_simd([](int i) { return i; }))); + assert(equal( + a * b, native_simd([](int i) { return (2 * i + 1) * (i + 1); }))); + assert(equal( + a / b, native_simd([](int i) { return (2 * i + 1) / (i + 1); }))); + assert(equal( + a % b, native_simd([](int i) { return (2 * i + 1) % (i + 1); }))); + assert(equal( + a & b, native_simd([](int i) { return (2 * i + 1) & (i + 1); }))); + assert(equal( + a | b, native_simd([](int i) { return (2 * i + 1) | (i + 1); }))); + assert(equal( + a ^ b, native_simd([](int i) { return (2 * i + 1) ^ (i + 1); }))); + } +} + +void test_mutating_opreators() { + native_simd b(4); + { + native_simd a(42); + assert(equal(++a, native_simd(43))); + assert(equal(a, native_simd(43))); + } + { + native_simd a(42); + assert(equal(a++, native_simd(42))); + assert(equal(a, native_simd(43))); + } + { + native_simd a(42); + assert(equal(--a, native_simd(41))); + assert(equal(a, native_simd(41))); + } + { + native_simd a(42); + assert(equal(a--, native_simd(42))); + assert(equal(a, native_simd(41))); + } + { + native_simd a(42); + assert(equal(a += b, native_simd(42 + 4))); + assert(equal(a, native_simd(42 + 4))); + } + { + native_simd a(42); + assert(equal(a -= b, native_simd(42 - 4))); + assert(equal(a, native_simd(42 - 4))); + } + { + native_simd a(42); + assert(equal(a *= b, native_simd(42 * 4))); + assert(equal(a, native_simd(42 * 4))); + } + { + native_simd a(42); + assert(equal(a /= b, native_simd(42 / 4))); + assert(equal(a, native_simd(42 / 4))); + } + { + native_simd a(42); + assert(equal(a %= b, native_simd(42 % 4))); + assert(equal(a, native_simd(42 % 4))); + } + { + native_simd a(42); + assert(equal(a &= b, native_simd(42 & 4))); + assert(equal(a, native_simd(42 & 4))); + } + { + native_simd a(42); + assert(equal(a |= b, native_simd(42 | 4))); + assert(equal(a, native_simd(42 | 4))); + } + { + native_simd a(42); + assert(equal(a ^= b, native_simd(42 ^ 4))); + assert(equal(a, native_simd(42 ^ 4))); + } + { + native_simd a(42); + assert(equal(a <<= b, native_simd(42 << 4))); + assert(equal(a, native_simd(42 << 4))); + } + { + native_simd a(42); + assert(equal(a >>= b, native_simd(42 >> 4))); + assert(equal(a, native_simd(42 >> 4))); + } + { + native_simd a(42); + assert(equal(a <<= 4, native_simd(42 << 4))); + assert(equal(a, native_simd(42 << 4))); + } + { + native_simd a(42); + assert(equal(a >>= 4, native_simd(42 >> 4))); + assert(equal(a, native_simd(42 >> 4))); + } +} + +int main() { + test_pure_operators(); + test_mutating_opreators(); +}