diff --git a/libcxx/include/experimental/simd b/libcxx/include/experimental/simd --- a/libcxx/include/experimental/simd +++ b/libcxx/include/experimental/simd @@ -670,14 +670,17 @@ }; template <_StorageKind __kind, int _Np> -struct __simd_abi {}; +struct __simd_abi { + static constexpr _StorageKind kind = __kind; +}; template class __simd_storage {}; template class __simd_storage<_Tp, __simd_abi<_StorageKind::_Array, __num_element>> { - std::array<_Tp, __num_element> __storage_; + using _StorageType = std::array<_Tp, __num_element>; + _StorageType __storage_; template friend struct simd; @@ -694,7 +697,8 @@ template class __simd_storage<_Tp, __simd_abi<_StorageKind::_Scalar, 1>> { - _Tp __storage_; + using _StorageType = _Tp; + _StorageType __storage_; template friend struct simd; @@ -1356,6 +1360,14 @@ private: __simd_storage<_Tp, _Abi> __s_; + const typename __simd_storage<_Tp, _Abi>::_StorageType &__raw_storage() const { + return __s_.__storage_; + } + + typename __simd_storage<_Tp, _Abi>::_StorageType &__raw_storage() { + return __s_.__storage_; + } + template static constexpr bool __can_broadcast() { return (std::is_arithmetic<_Up>::value && @@ -1471,18 +1483,32 @@ 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); + template + friend simd<_Tp2, _Abi2> operator+(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator-(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator*(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator-(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator/(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator%(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator&(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator|(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator^(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator<<(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator>>(const simd<_Tp2, _Abi2> &, const simd<_Tp2, _Abi2>&); + template + friend simd<_Tp2, _Abi2> operator<<(const simd<_Tp2, _Abi2> &, int); + template + friend simd<_Tp2, _Abi2> operator>>(const simd<_Tp2, _Abi2> &, int); // compound assignment [simd.cassign] friend simd& operator+=(simd&, const simd&); @@ -1508,6 +1534,141 @@ friend mask_type operator<(const simd&, const simd&); }; +template +simd<_Tp, _Abi> operator+(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + + if constexpr (_Abi::kind == _StorageKind::_VecExt) { + res.__raw_storage() = A.__raw_storage() + B.__raw_storage(); + } else { + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] + B[i]; + } + + return res; +} + +template +simd<_Tp, _Abi> operator-(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() - B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] - B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator*(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() * B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] * B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator/(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() / B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] / B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator%(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() % B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] % B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator&(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() & B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] & B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator|(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() | B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] | B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator^(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() ^ B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] ^ B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator<<(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() << B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] << B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator<<(const simd<_Tp, _Abi> &A, int B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() << B; + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] << B; + return res; +} + +template +simd<_Tp, _Abi> operator>>(const simd<_Tp, _Abi> &A, const simd<_Tp, _Abi> &B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() >> B.__raw_storage(); + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] >> B[i]; + return res; +} + +template +simd<_Tp, _Abi> operator>>(const simd<_Tp, _Abi> &A, int B) { + simd<_Tp, _Abi> res; + if constexpr (_Abi::kind == _StorageKind::_VecExt) + res.__raw_storage() = A.__raw_storage() >> B; + else + for (size_t i = 0; i < A.size(); i++) + res[i] = A[i] >> B; + return res; +} + // [simd.mask.class] template // TODO: implement simd_mask diff --git a/libcxx/test/std/experimental/simd/simd.operand/default.pass.cpp b/libcxx/test/std/experimental/simd/simd.operand/default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.operand/default.pass.cpp @@ -0,0 +1,111 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// +// +// simd operator+(simd, simd); +// simd operator-(simd, simd); +// simd operator*(simd, simd); +// simd operator/(simd, simd); +// simd operator%(simd, simd); +// simd operator&(simd, simd); +// simd operator|(simd, simd); +// simd operator^(simd, simd); +// simd operator<<(simd, simd); +// simd operator>>(simd, simd); +// simd operator<<(simd, int); +// simd operator>>(simd, int); + +#include +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental::parallelism_v2; + +template +void test_operand() { + SimdType a, b; + + for (size_t i = 0; i < a.size(); i++) { + a[i] = 1 + 7 * i; + b[i] = 2 + i; + } + + { + auto c = a + b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == a[i] + b[i]); + } + { + auto c = a - b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == a[i] - b[i]); + } + { + auto c = a * b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == a[i] * b[i]); + } + { + auto c = a / b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == a[i] / b[i]); + } + { + auto c = a % b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == a[i] % b[i]); + } + { + auto c = a & b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] & b[i])); + } + { + auto c = a | b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] | b[i])); + } + { + auto c = a ^ b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] ^ b[i])); + } + { + auto c = a << b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] << b[i])); + } + { + auto c = a >> b; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] >> b[i])); + } + { + auto c = a << 1; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] << 1)); + } + { + auto c = a >> 1; + for (size_t i = 0; i < a.size(); i++) + assert(c[i] == (a[i] >> 1)); + } +} + +int main(int, char**) { + test_operand>(); + test_operand>(); + test_operand>(); + + return 0; +}