| // Copyright (C) 2020-2021 Free Software Foundation, Inc. |
| // |
| // This file is part of the GNU ISO C++ Library. This library is free |
| // software; you can redistribute it and/or modify it under the |
| // terms of the GNU General Public License as published by the |
| // Free Software Foundation; either version 3, or (at your option) |
| // any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License along |
| // with this library; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| |
| // expensive: * [1-9] * * |
| #include "bits/verify.h" |
| #include "bits/metahelpers.h" |
| #include "bits/conversions.h" |
| |
| using std::experimental::simd_cast; |
| |
| template <typename V, bool ConstProp, typename F> |
| auto |
| gen(const F& fun) |
| { |
| if constexpr (ConstProp) |
| return V(fun); |
| else |
| return make_value_unknown(V(fun)); |
| } |
| |
| template <typename V, bool ConstProp> |
| void |
| split_concat() |
| { |
| using T = typename V::value_type; |
| if constexpr (V::size() * 3 |
| <= std::experimental::simd_abi::max_fixed_size<T>) |
| { |
| V a(0), b(1), c(2); |
| auto x = concat(a, b, c); |
| COMPARE(x.size(), a.size() * 3); |
| std::size_t i = 0; |
| for (; i < a.size(); ++i) |
| { |
| COMPARE(x[i], T(0)); |
| } |
| for (; i < 2 * a.size(); ++i) |
| { |
| COMPARE(x[i], T(1)); |
| } |
| for (; i < 3 * a.size(); ++i) |
| { |
| COMPARE(x[i], T(2)); |
| } |
| } |
| |
| if constexpr (V::size() >= 4) |
| { |
| const V a = gen<V, ConstProp>([](auto i) -> T { return i; }); |
| constexpr auto N0 = V::size() / 4u; |
| constexpr auto N1 = V::size() - 2 * N0; |
| using V0 = std::experimental::simd< |
| T, std::experimental::simd_abi::deduce_t<T, N0>>; |
| using V1 = std::experimental::simd< |
| T, std::experimental::simd_abi::deduce_t<T, N1>>; |
| { |
| auto x = std::experimental::split<N0, N0, N1>(a); |
| COMPARE(std::tuple_size<decltype(x)>::value, 3u); |
| COMPARE(std::get<0>(x), V0([](auto i) -> T { return i; })); |
| COMPARE(std::get<1>(x), V0([](auto i) -> T { return i + N0; })); |
| COMPARE(std::get<2>(x), V1([](auto i) -> T { return i + 2 * N0; })); |
| auto b = concat(std::get<1>(x), std::get<2>(x), std::get<0>(x)); |
| // a and b may have different types if a was fixed_size<N> such that |
| // another ABI tag exists with equal N, then b will have the |
| // non-fixed-size ABI tag. |
| COMPARE(a.size(), b.size()); |
| COMPARE( |
| b, decltype(b)([](auto i) -> T { return (N0 + i) % V::size(); })); |
| } |
| { |
| auto x = std::experimental::split<N0, N1, N0>(a); |
| COMPARE(std::tuple_size<decltype(x)>::value, 3u); |
| COMPARE(std::get<0>(x), V0([](auto i) -> T { return i; })); |
| COMPARE(std::get<1>(x), V1([](auto i) -> T { return i + N0; })); |
| COMPARE(std::get<2>(x), V0([](auto i) -> T { return i + N0 + N1; })); |
| auto b = concat(std::get<1>(x), std::get<2>(x), std::get<0>(x)); |
| // a and b may have different types if a was fixed_size<N> such that |
| // another ABI tag exists with equal N, then b will have the |
| // non-fixed-size ABI tag. |
| COMPARE(a.size(), b.size()); |
| COMPARE( |
| b, decltype(b)([](auto i) -> T { return (N0 + i) % V::size(); })); |
| } |
| { |
| auto x = std::experimental::split<N1, N0, N0>(a); |
| COMPARE(std::tuple_size<decltype(x)>::value, 3u); |
| COMPARE(std::get<0>(x), V1([](auto i) -> T { return i; })); |
| COMPARE(std::get<1>(x), V0([](auto i) -> T { return i + N1; })); |
| COMPARE(std::get<2>(x), V0([](auto i) -> T { return i + N0 + N1; })); |
| auto b = concat(std::get<1>(x), std::get<2>(x), std::get<0>(x)); |
| // a and b may have different types if a was fixed_size<N> such that |
| // another ABI tag exists with equal N, then b will have the |
| // non-fixed-size ABI tag. |
| COMPARE(a.size(), b.size()); |
| COMPARE( |
| b, decltype(b)([](auto i) -> T { return (N1 + i) % V::size(); })); |
| } |
| } |
| |
| if constexpr (V::size() % 3 == 0) |
| { |
| const V a = gen<V, ConstProp>([](auto i) -> T { return i; }); |
| constexpr auto N0 = V::size() / 3; |
| using V0 = std::experimental::simd< |
| T, std::experimental::simd_abi::deduce_t<T, N0>>; |
| using V1 = std::experimental::simd< |
| T, std::experimental::simd_abi::deduce_t<T, 2 * N0>>; |
| { |
| auto [x, y, z] = std::experimental::split<N0, N0, N0>(a); |
| COMPARE(x, V0([](auto i) -> T { return i; })); |
| COMPARE(y, V0([](auto i) -> T { return i + N0; })); |
| COMPARE(z, V0([](auto i) -> T { return i + N0 * 2; })); |
| auto b = concat(x, y, z); |
| COMPARE(a.size(), b.size()); |
| COMPARE(b, simd_cast<decltype(b)>(a)); |
| COMPARE(simd_cast<V>(b), a); |
| } |
| { |
| auto [x, y] = std::experimental::split<N0, 2 * N0>(a); |
| COMPARE(x, V0([](auto i) -> T { return i; })); |
| COMPARE(y, V1([](auto i) -> T { return i + N0; })); |
| auto b = concat(x, y); |
| COMPARE(a.size(), b.size()); |
| COMPARE(b, simd_cast<decltype(b)>(a)); |
| COMPARE(simd_cast<V>(b), a); |
| } |
| { |
| auto [x, y] = std::experimental::split<2 * N0, N0>(a); |
| COMPARE(x, V1([](auto i) -> T { return i; })); |
| COMPARE(y, V0([](auto i) -> T { return i + 2 * N0; })); |
| auto b = concat(x, y); |
| COMPARE(a.size(), b.size()); |
| COMPARE(b, simd_cast<decltype(b)>(a)); |
| COMPARE(simd_cast<V>(b), a); |
| } |
| } |
| |
| if constexpr ((V::size() & 1) == 0) |
| { |
| using std::experimental::simd; |
| using std::experimental::simd_abi::deduce_t; |
| using V0 = simd<T, deduce_t<T, V::size()>>; |
| using V2 = simd<T, deduce_t<T, 2>>; |
| using V3 = simd<T, deduce_t<T, V::size() / 2>>; |
| |
| const V a = gen<V, ConstProp>([](auto i) -> T { return i; }); |
| |
| std::array<V2, V::size() / 2> v2s = std::experimental::split<V2>(a); |
| int offset = 0; |
| for (V2 test : v2s) |
| { |
| COMPARE(test, V2([&](auto i) -> T { return i + offset; })); |
| offset += 2; |
| } |
| COMPARE(concat(v2s), simd_cast<V0>(a)); |
| |
| std::array<V3, 2> v3s = std::experimental::split<V3>(a); |
| COMPARE(v3s[0], V3([](auto i) -> T { return i; })); |
| COMPARE(v3s[1], V3([](auto i) -> T { return i + V3::size(); })); |
| COMPARE(concat(v3s), simd_cast<V0>(a)); |
| } |
| } |
| |
| template <typename V> |
| void |
| test() |
| { |
| split_concat<V, true>(); |
| split_concat<V, false>(); |
| } |