Index: libcxx/include/experimental/simd =================================================================== --- libcxx/include/experimental/simd +++ libcxx/include/experimental/simd @@ -606,13 +606,13 @@ _VecExt, }; -template <_StorageKind __kind, int _Np> +template <_StorageKind __kind, size_t _Np> struct __simd_abi {}; template class __simd_storage {}; -template +template class __simd_storage<_Tp, __simd_abi<_StorageKind::_Array, __num_element>> { std::array<_Tp, __num_element> __storage_; @@ -684,7 +684,7 @@ #undef _SPECIALIZE_VEC_EXT_32 #undef _SPECIALIZE_VEC_EXT -template +template class __simd_storage<_Tp, __simd_abi<_StorageKind::_VecExt, __num_element>> { using _StorageType = typename __vec_ext_traits<_Tp, __ceil_pow_of_2(sizeof(_Tp) * @@ -841,27 +841,32 @@ using scalar = __simd_abi<_StorageKind::_Scalar, 1>; -template +template using fixed_size = __simd_abi<_StorageKind::_Array, _Np>; #if _LIBCPP_STD_VER > 14 && !defined(_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && \ !defined(_LIBCPP_HAS_NO_INLINE_VARIABLES) template -inline constexpr int max_fixed_size = 32; +inline constexpr size_t max_fixed_size = 32; #endif -template -using compatible = fixed_size<16 / sizeof(_Tp)>; +template +using __compatible = fixed_size<_Np>; -template -using native = +template +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 +using compatible = __compatible<_Tp, 16 / sizeof(_Tp)>; + +template +using native = __native<_Tp, _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES / sizeof(_Tp)>; + _LIBCPP_END_NAMESPACE_EXPERIMENTAL_SIMD_ABI _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_SIMD @@ -889,7 +894,7 @@ template struct is_abi_tag : std::integral_constant {}; -template <_StorageKind __kind, int _Np> +template <_StorageKind __kind, size_t _Np> struct is_abi_tag<__simd_abi<__kind, _Np>> : std::integral_constant {}; @@ -940,7 +945,7 @@ using type = simd_abi::fixed_size<_Np>; }; -template +template struct abi_for_size<_Tp, _Np, __simd_abi<__kind, __old_size>...> { using type = __simd_abi<__kind, _Np>; }; @@ -954,7 +959,7 @@ template > struct simd_size; -template +template struct simd_size<_Tp, __simd_abi<__kind, _Np>> : std::integral_constant { static_assert( @@ -979,21 +984,23 @@ // class template simd [simd.class] template using native_simd = simd<_Tp, simd_abi::native<_Tp>>; -template +template using fixed_size_simd = simd<_Tp, simd_abi::fixed_size<_Np>>; // class template simd_mask [simd.mask.class] template using native_simd_mask = simd_mask<_Tp, simd_abi::native<_Tp>>; -template +template using fixed_size_simd_mask = simd_mask<_Tp, simd_abi::fixed_size<_Np>>; // casts [simd.casts] template struct __static_simd_cast_traits { template - 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>::__apply(__v); + } }; template @@ -1002,7 +1009,13 @@ static typename std::enable_if::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 @@ -1011,7 +1024,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 @@ -1021,7 +1036,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>::__apply(__v); + } }; template @@ -1038,20 +1055,32 @@ template 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::value>>(__v); +} template fixed_size_simd_mask<_Tp, simd_size<_Tp, _Abi>::value> to_fixed_size(const simd_mask<_Tp, _Abi>&) noexcept; +// NOTE: As an extension, allow transforming to a native type with a size +// that's not native_simd::size(). template -native_simd<_Tp> to_native(const fixed_size_simd<_Tp, _Np>&) noexcept; +simd<_Tp, simd_abi::__native<_Tp, _Np>> +to_native(const fixed_size_simd<_Tp, _Np>& __v) noexcept { + return simd_cast>>(__v); +} template native_simd_mask<_Tp> to_native(const fixed_size_simd_mask<_Tp, _Np>&) noexcept; +// NOTE: As an extension, allow transforming to a compatible type with a size +// that's not simd::size(). template -simd<_Tp> to_compatible(const fixed_size_simd<_Tp, _Np>&) noexcept; +simd<_Tp, simd_abi::__compatible<_Tp, _Np>> +to_compatible(const fixed_size_simd<_Tp, _Np>& __v) noexcept { + return simd_cast>>(__v); +} template simd_mask<_Tp> to_compatible(const fixed_size_simd_mask<_Tp, _Np>&) noexcept; 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 +auto unsupported_cast(Args&&... args) + -> decltype(simd_cast(std::forward(args)...), void()) = delete; + static_assert(std::is_same(native_simd())), native_simd>::value, ""); @@ -38,4 +42,25 @@ simd>::value, ""); +template +void unsupported_cast(...) {} + +void compile_narrowing_convert() { + unsupported_cast(native_simd()); + unsupported_cast(native_simd()); + unsupported_cast(native_simd()); + unsupported_cast(native_simd()); + unsupported_cast>(fixed_size_simd()); +} + +void compile_abi_convert() { + constexpr size_t ratio = native_simd::size() / simd::size(); + std::array, ratio> arr; + + auto res = concat(arr); + static_assert(!std::is_same>::value, ""); + + (void)simd_cast>(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>::value, ""); -int main() {} +void test_int_float_convert() { + assert(static_simd_cast(native_simd(16))[0] == 16.); + assert(static_simd_cast(native_simd(15.2f))[0] == 15); + assert(static_simd_cast(native_simd(15.9f))[0] == 15); +} + +void test_narrowing_convert() { + assert(static_simd_cast(native_simd(-10))[0] == + 246); + assert(static_simd_cast(native_simd(246))[0] == + -10); + assert(static_simd_cast(native_simd(127))[0] == + 127); + assert(static_simd_cast(native_simd(127))[0] == + 127); + assert(static_simd_cast(native_simd(257))[0] == + 1); + assert(static_simd_cast(native_simd(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 + +// +// +// [simd.casts] +// +// template simd +// to_compatible(const fixed_size_simd&) noexcept; +// +// template simd_mask +// to_compatible(const fixed_size_simd_mask&) noexcept; + +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_to_compatible() { + auto v = to_compatible( + fixed_size_simd::size()>([](int i) { return i; })); + simd w([](int i) { return i; }); + + static_assert(std::is_same::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::size()>( + to_compatible(fixed_size_simd([](int i) { return i; }))); + static_assert(std::is_same>::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 + +// +// +// [simd.casts] +// +// template +// fixed_size_simd> +// to_fixed_size(const simd&) noexcept; +// +// template +// fixed_size_simd_mask> +// to_fixed_size(const simd_mask&) noexcept; + +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_to_fixed_size() { + auto v = to_fixed_size(native_simd([](int i) { return i; })); + static_assert(std::is_same::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 + +// +// +// [simd.casts] +// +// template +// native_simd to_native(const fixed_size_simd&) noexcept; +// +// template +// native_simd_mask to_native(const fixed_size_simd_mask&) noexcept; + +#include +#include + +using namespace std::experimental::parallelism_v2; + +void test_to_native() { + auto v = to_native( + fixed_size_simd::size()>([](int i) { return i; })); + native_simd w([](int i) { return i; }); + + static_assert(std::is_same::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::size()>( + to_native(fixed_size_simd([](int i) { return i; }))); + static_assert( + std::is_same>::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(); +}