Index: libcxx/include/experimental/simd =================================================================== --- libcxx/include/experimental/simd +++ libcxx/include/experimental/simd @@ -910,18 +910,23 @@ _LIBCPP_INLINE_VAR constexpr size_t max_fixed_size = 32; #endif -template <class _Tp> -using compatible = fixed_size<16 / sizeof(_Tp)>; +template <class _Tp, size_t _Np> +using __compatible = fixed_size<_Np>; -template <class _Tp> -using native = +template <class _Tp, size_t _Np> +using __native = #ifndef _LIBCPP_HAS_NO_VECTOR_EXTENSION - __simd_abi<_StorageKind::_VecExt, - _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES / sizeof(_Tp)>; + __simd_abi<_StorageKind::_VecExt, _Np>; #else - fixed_size<_Tp, _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES / sizeof(_Tp)>; + __simd_abi<_StorageKind::_Array, _Np>; #endif // _LIBCPP_HAS_NO_VECTOR_EXTENSION +template <class _Tp> +using compatible = __compatible<_Tp, 16 / sizeof(_Tp)>; + +template <class _Tp> +using native = __native<_Tp, _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES / sizeof(_Tp)>; + _LIBCPP_END_NAMESPACE_EXPERIMENTAL_SIMD_ABI _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_SIMD @@ -1051,7 +1056,9 @@ template <class _Tp> struct __static_simd_cast_traits { template <class _Up, class _Abi> - static simd<_Tp, _Abi> __apply(const simd<_Up, _Abi>& __v); + static simd<_Tp, _Abi> __apply(const simd<_Up, _Abi>& __v) { + return __static_simd_cast_traits<simd<_Tp, _Abi>>::__apply(__v); + } }; template <class _Tp, class _NewAbi> @@ -1060,7 +1067,13 @@ static typename std::enable_if<simd<_Up, _Abi>::size() == simd<_Tp, _NewAbi>::size(), simd<_Tp, _NewAbi>>::type - __apply(const simd<_Up, _Abi>& __v); + __apply(const simd<_Up, _Abi>& __v) { + simd<_Tp, _NewAbi> __ret; + for (size_t __i = 0; __i < __v.size(); __i++) { + __ret[__i] = static_cast<_Tp>(__v[__i]); + } + return __ret; + } }; template <class _Tp> @@ -1069,7 +1082,9 @@ static typename std::enable_if< __is_non_narrowing_arithmetic_convertible<_Up, _Tp>(), simd<_Tp, _Abi>>::type - __apply(const simd<_Up, _Abi>& __v); + __apply(const simd<_Up, _Abi>& __v) { + return __static_simd_cast_traits<_Tp>::__apply(__v); + } }; template <class _Tp, class _NewAbi> @@ -1079,7 +1094,9 @@ __is_non_narrowing_arithmetic_convertible<_Up, _Tp>() && simd<_Up, _Abi>::size() == simd<_Tp, _NewAbi>::size(), simd<_Tp, _NewAbi>>::type - __apply(const simd<_Up, _Abi>& __v); + __apply(const simd<_Up, _Abi>& __v) { + return __static_simd_cast_traits<simd<_Tp, _NewAbi>>::__apply(__v); + } }; template <class _Tp, class _Up, class _Abi> @@ -1096,22 +1113,34 @@ template <class _Tp, class _Abi> fixed_size_simd<_Tp, simd_size<_Tp, _Abi>::value> -to_fixed_size(const simd<_Tp, _Abi>&) noexcept; +to_fixed_size(const simd<_Tp, _Abi>& __v) noexcept { + return simd_cast<fixed_size_simd<_Tp, simd_size<_Tp, _Abi>::value>>(__v); +} template <class _Tp, class _Abi> fixed_size_simd_mask<_Tp, simd_size<_Tp, _Abi>::value> to_fixed_size(const simd_mask<_Tp, _Abi>&) noexcept; -template <class _Tp, size_t _Np> -native_simd<_Tp> to_native(const fixed_size_simd<_Tp, _Np>&) noexcept; +// NOTE: As an extension, allow transforming to a native type with a size +// that's not native_simd<T>::size(). +template <class _Tp, int _Np> +simd<_Tp, simd_abi::__native<_Tp, _Np>> +to_native(const fixed_size_simd<_Tp, _Np>& __v) noexcept { + return simd_cast<simd<_Tp, simd_abi::__native<_Tp, _Np>>>(__v); +} -template <class _Tp, size_t _Np> +template <class _Tp, int _Np> native_simd_mask<_Tp> to_native(const fixed_size_simd_mask<_Tp, _Np>&) noexcept; -template <class _Tp, size_t _Np> -simd<_Tp> to_compatible(const fixed_size_simd<_Tp, _Np>&) noexcept; +// NOTE: As an extension, allow transforming to a compatible type with a size +// that's not simd<T>::size(). +template <class _Tp, int _Np> +simd<_Tp, simd_abi::__compatible<_Tp, _Np>> +to_compatible(const fixed_size_simd<_Tp, _Np>& __v) noexcept { + return simd_cast<simd<_Tp, simd_abi::__compatible<_Tp, _Np>>>(__v); +} -template <class _Tp, size_t _Np> +template <class _Tp, int _Np> simd_mask<_Tp> to_compatible(const fixed_size_simd_mask<_Tp, _Np>&) noexcept; template <class _TupleType, class _Tp, size_t... __indices> Index: libcxx/test/std/experimental/simd/simd.casts/simd_cast.pass.cpp =================================================================== --- libcxx/test/std/experimental/simd/simd.casts/simd_cast.pass.cpp +++ libcxx/test/std/experimental/simd/simd.casts/simd_cast.pass.cpp @@ -19,6 +19,10 @@ using namespace std::experimental::parallelism_v2; +template <class T, class... Args> +auto unsupported_cast(Args&&... args) + -> decltype(simd_cast<T>(std::forward<Args>(args)...), void()) = delete; + static_assert(std::is_same<decltype(simd_cast<int32_t>(native_simd<int32_t>())), native_simd<int32_t>>::value, ""); @@ -38,4 +42,25 @@ simd<int64_t, simd_abi::scalar>>::value, ""); +template <class T> +void unsupported_cast(...) {} + +void compile_narrowing_convert() { + unsupported_cast<float>(native_simd<int>()); + unsupported_cast<int>(native_simd<float>()); + unsupported_cast<int8_t>(native_simd<int32_t>()); + unsupported_cast<bool>(native_simd<int32_t>()); + unsupported_cast<fixed_size_simd<int, 2>>(fixed_size_simd<int, 4>()); +} + +void compile_abi_convert() { + constexpr size_t ratio = native_simd<int>::size() / simd<int>::size(); + std::array<simd<int>, ratio> arr; + + auto res = concat(arr); + static_assert(!std::is_same<decltype(res), native_simd<int>>::value, ""); + + (void)simd_cast<native_simd<int>>(res); +} + int main() {} Index: libcxx/test/std/experimental/simd/simd.casts/static_simd_cast.pass.cpp =================================================================== --- libcxx/test/std/experimental/simd/simd.casts/static_simd_cast.pass.cpp +++ libcxx/test/std/experimental/simd/simd.casts/static_simd_cast.pass.cpp @@ -35,4 +35,27 @@ simd<float, simd_abi::scalar>>::value, ""); -int main() {} +void test_int_float_convert() { + assert(static_simd_cast<float>(native_simd<int>(16))[0] == 16.); + assert(static_simd_cast<int>(native_simd<float>(15.2f))[0] == 15); + assert(static_simd_cast<int>(native_simd<float>(15.9f))[0] == 15); +} + +void test_narrowing_convert() { + assert(static_simd_cast<unsigned char>(native_simd<signed char>(-10))[0] == + 246); + assert(static_simd_cast<signed char>(native_simd<unsigned char>(246))[0] == + -10); + assert(static_simd_cast<unsigned char>(native_simd<signed char>(127))[0] == + 127); + assert(static_simd_cast<signed char>(native_simd<unsigned char>(127))[0] == + 127); + assert(static_simd_cast<unsigned char>(native_simd<unsigned int>(257))[0] == + 1); + assert(static_simd_cast<signed char>(native_simd<signed int>(254))[0] == -2); +} + +int main() { + test_int_float_convert(); + test_narrowing_convert(); +} Index: libcxx/test/std/experimental/simd/simd.casts/to_compatible.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/experimental/simd/simd.casts/to_compatible.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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.casts] +// +// template <class T, size_t N> simd<T> +// to_compatible(const fixed_size_simd<T, N>&) noexcept; +// +// template <class T, size_t N> simd_mask<T> +// to_compatible(const fixed_size_simd_mask<T, N>&) noexcept; + +#include <experimental/simd> +#include <cstdint> + +using namespace std::experimental::parallelism_v2; + +void test_to_compatible() { + auto v = to_compatible( + fixed_size_simd<int, simd<int>::size()>([](int i) { return i; })); + simd<int> w([](int i) { return i; }); + + static_assert(std::is_same<decltype(v), decltype(w)>::value, ""); + + for (size_t i = 0; i < v.size(); i++) { + assert(v[i] == w[i]); + } +} + +void test_to_compatible_extension() { + auto arr = split_by<32 / simd<int>::size()>( + to_compatible(fixed_size_simd<int, 32>([](int i) { return i; }))); + static_assert(std::is_same<decltype(arr)::value_type, simd<int>>::value, ""); + int v = 0; + for (size_t i = 0; i < arr.size(); i++) { + for (size_t j = 0; j < arr[0].size(); j++) { + assert(arr[i][j] == v); + v++; + } + } +} + +int main() { + test_to_compatible(); + test_to_compatible_extension(); +} Index: libcxx/test/std/experimental/simd/simd.casts/to_fixed_size.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/experimental/simd/simd.casts/to_fixed_size.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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.casts] +// +// template <class T, class Abi> +// fixed_size_simd<T, simd_size_v<T, Abi>> +// to_fixed_size(const simd<T, Abi>&) noexcept; +// +// template <class T, class Abi> +// fixed_size_simd_mask<T, simd_size_v<T, Abi>> +// to_fixed_size(const simd_mask<T, Abi>&) noexcept; + +#include <experimental/simd> +#include <cstdint> + +using namespace std::experimental::parallelism_v2; + +void test_to_fixed_size() { + auto v = to_fixed_size(native_simd<int>([](int i) { return i; })); + static_assert(std::is_same<fixed_size_simd<int, native_simd<int>::size()>, + decltype(v)>::value, + ""); + + for (size_t i = 0; i < v.size(); i++) { + assert(v[i] == (int)i); + } +} + +int main() { test_to_fixed_size(); } Index: libcxx/test/std/experimental/simd/simd.casts/to_native.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/experimental/simd/simd.casts/to_native.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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.casts] +// +// template <class T, size_t N> +// native_simd<T> to_native(const fixed_size_simd<T, N>&) noexcept; +// +// template <class T, size_t N> +// native_simd_mask<T> to_native(const fixed_size_simd_mask<T, N>&) noexcept; + +#include <experimental/simd> +#include <cstdint> + +using namespace std::experimental::parallelism_v2; + +void test_to_native() { + auto v = to_native( + fixed_size_simd<int, native_simd<int>::size()>([](int i) { return i; })); + native_simd<int> w([](int i) { return i; }); + + static_assert(std::is_same<decltype(v), decltype(w)>::value, ""); + + for (size_t i = 0; i < v.size(); i++) { + assert(v[i] == w[i]); + } +} + +void test_to_native_extension() { + auto arr = split_by<32 / native_simd<int>::size()>( + to_native(fixed_size_simd<int, 32>([](int i) { return i; }))); + static_assert( + std::is_same<decltype(arr)::value_type, native_simd<int>>::value, ""); + int v = 0; + for (size_t i = 0; i < arr.size(); i++) { + for (size_t j = 0; j < arr[0].size(); j++) { + assert(arr[i][j] == v); + v++; + } + } +} + +int main() { + test_to_native(); + test_to_native_extension(); +}