timshen created this revision. timshen added reviewers: mclow.lists, EricWF. Herald added a subscriber: sanjoy.
This patch also changed all simd size-related types to size_t. Before the change, as P0214 proposed, they are half-int, half-size_t in different places. The inconsistency of size types cause to_compatible to fail to deduce the template arguments. https://reviews.llvm.org/D41415 Files: libcxx/include/experimental/simd libcxx/test/std/experimental/simd/simd.casts/simd_cast.pass.cpp libcxx/test/std/experimental/simd/simd.casts/static_simd_cast.pass.cpp libcxx/test/std/experimental/simd/simd.casts/to_compatible.pass.cpp libcxx/test/std/experimental/simd/simd.casts/to_fixed_size.pass.cpp libcxx/test/std/experimental/simd/simd.casts/to_native.pass.cpp
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(); +} 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_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/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/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/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 _Tp, class _Abi> class __simd_storage {}; -template <class _Tp, int __num_element> +template <class _Tp, size_t __num_element> 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 <class _Tp, int __num_element> +template <class _Tp, size_t __num_element> 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 <int _Np> +template <size_t _Np> 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 <class _Tp> -inline constexpr int max_fixed_size = 32; +inline 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 = #ifdef _LIBCPP_HAS_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 +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 @@ -889,7 +894,7 @@ template <class _Tp> struct is_abi_tag : std::integral_constant<bool, false> {}; -template <_StorageKind __kind, int _Np> +template <_StorageKind __kind, size_t _Np> struct is_abi_tag<__simd_abi<__kind, _Np>> : std::integral_constant<bool, true> {}; @@ -940,7 +945,7 @@ using type = simd_abi::fixed_size<_Np>; }; -template <class _Tp, size_t _Np, _StorageKind __kind, int... __old_size> +template <class _Tp, size_t _Np, _StorageKind __kind, size_t... __old_size> struct abi_for_size<_Tp, _Np, __simd_abi<__kind, __old_size>...> { using type = __simd_abi<__kind, _Np>; }; @@ -954,7 +959,7 @@ template <class _Tp, class _Abi = simd_abi::compatible<_Tp>> struct simd_size; -template <class _Tp, _StorageKind __kind, int _Np> +template <class _Tp, _StorageKind __kind, size_t _Np> struct simd_size<_Tp, __simd_abi<__kind, _Np>> : std::integral_constant<size_t, _Np> { static_assert( @@ -979,39 +984,49 @@ // class template simd [simd.class] template <class _Tp> using native_simd = simd<_Tp, simd_abi::native<_Tp>>; -template <class _Tp, int _Np> +template <class _Tp, size_t _Np> using fixed_size_simd = simd<_Tp, simd_abi::fixed_size<_Np>>; // class template simd_mask [simd.mask.class] template <class _Tp> using native_simd_mask = simd_mask<_Tp, simd_abi::native<_Tp>>; -template <class _Tp, int _Np> +template <class _Tp, size_t _Np> using fixed_size_simd_mask = simd_mask<_Tp, simd_abi::fixed_size<_Np>>; // casts [simd.casts] 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> struct __static_simd_cast_traits<simd<_Tp, _NewAbi>> { template <class _Up, class _Abi> 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> struct __simd_cast_traits { template <class _Up, class _Abi> 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> @@ -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<simd<_Tp, _NewAbi>>::__apply(__v); + } }; template <class _Tp, class _Up, class _Abi> @@ -1038,20 +1055,32 @@ 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; +// NOTE: As an extension, allow transforming to a native type with a size +// that's not native_simd<T>::size(). template <class _Tp, size_t _Np> -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<simd<_Tp, simd_abi::__native<_Tp, _Np>>>(__v); +} template <class _Tp, size_t _Np> 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<T>::size(). template <class _Tp, size_t _Np> -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<simd<_Tp, simd_abi::__compatible<_Tp, _Np>>>(__v); +} template <class _Tp, size_t _Np> simd_mask<_Tp> to_compatible(const fixed_size_simd_mask<_Tp, _Np>&) noexcept;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits