182 lines
6 KiB
C++
182 lines
6 KiB
C++
// Copyright (C) 2020-2024 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/main.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>();
|
|
}
|