The constexpr API is only available with -std=gnu++XX (and proposed for C++26). The proposal is to have the complete simd API usable in constant expressions. This patch resolves several issues with using simd in constant expressions. Issues why constant_evaluated branches are necessary: * subscripting vector builtins is not allowed in constant expressions * if the implementation needs/uses memcpy * if the implementation would otherwise call SIMD intrinsics/builtins Signed-off-by: Matthias Kretz <m.kretz@gsi.de> libstdc++-v3/ChangeLog: PR libstdc++/109261 * include/experimental/bits/simd.h (_SimdWrapper::_M_set): Avoid vector builtin subscripting in constant expressions. (resizing_simd_cast): Avoid memcpy if constant_evaluated. (const_where_expression, where_expression, where) (__extract_part, simd_mask, _SimdIntOperators, simd): Add either _GLIBCXX_SIMD_CONSTEXPR (on public APIs), or constexpr (on internal APIs). * include/experimental/bits/simd_builtin.h (__vector_permute) (__vector_shuffle, __extract_part, _GnuTraits::_SimdCastType1) (_GnuTraits::_SimdCastType2, _SimdImplBuiltin) (_MaskImplBuiltin::_S_store): Add constexpr. (_CommonImplBuiltin::_S_store_bool_array) (_SimdImplBuiltin::_S_load, _SimdImplBuiltin::_S_store) (_SimdImplBuiltin::_S_reduce, _MaskImplBuiltin::_S_load): Add constant_evaluated case. * include/experimental/bits/simd_fixed_size.h (_S_masked_load): Reword comment. (__tuple_element_meta, __make_meta, _SimdTuple::_M_apply_r) (_SimdTuple::_M_subscript_read, _SimdTuple::_M_subscript_write) (__make_simd_tuple, __optimize_simd_tuple, __extract_part) (__autocvt_to_simd, _Fixed::__traits::_SimdBase) (_Fixed::__traits::_SimdCastType, _SimdImplFixedSize): Add constexpr. (_SimdTuple::operator[], _M_set): Add constexpr and add constant_evaluated case. (_MaskImplFixedSize::_S_load): Add constant_evaluated case. * include/experimental/bits/simd_scalar.h: Add constexpr. * include/experimental/bits/simd_x86.h (_CommonImplX86): Add constexpr and add constant_evaluated case. (_SimdImplX86::_S_equal_to, _S_not_equal_to, _S_less) (_S_less_equal): Value-initialize to satisfy constexpr evaluation. (_MaskImplX86::_S_load): Add constant_evaluated case. (_MaskImplX86::_S_store): Add constexpr and constant_evaluated case. Value-initialize local variables. (_MaskImplX86::_S_logical_and, _S_logical_or, _S_bit_not) (_S_bit_and, _S_bit_or, _S_bit_xor): Add constant_evaluated case. * testsuite/experimental/simd/pr109261_constexpr_simd.cc: New test. (cherry picked from commit da579188807ede4ee9466d0b5bf51559c96a0b51)
93 lines
2.3 KiB
C++
93 lines
2.3 KiB
C++
// { dg-options "-std=gnu++17" }
|
|
// { dg-do compile { target c++17 } }
|
|
// { dg-require-cmath "" }
|
|
|
|
#include <experimental/simd>
|
|
|
|
namespace stdx = std::experimental;
|
|
|
|
template <typename T, typename V>
|
|
void
|
|
test01()
|
|
{
|
|
constexpr T data[V::size()] = {};
|
|
constexpr auto a = V(data, stdx::element_aligned);
|
|
|
|
constexpr auto b = []() constexpr {
|
|
V x = T(1);
|
|
where(x > T(), x) = T();
|
|
where(x < T(), x) += T();
|
|
where(x >= T(), x) -= T();
|
|
where(x <= T(), x) *= T();
|
|
where(x == T(), x) /= T(1);
|
|
where(x != T(), x) += T(1);
|
|
return x;
|
|
}();
|
|
|
|
constexpr T c = V()[0];
|
|
|
|
constexpr auto d = !V() && !!V() || !V() & !V() | !V() ^ !V();
|
|
|
|
constexpr auto e = []() constexpr {
|
|
T data[V::size()] = {};
|
|
V(T(1)).copy_to(data, stdx::element_aligned);
|
|
V x = T();
|
|
x[0] = T(1);
|
|
x.copy_from(data, stdx::element_aligned);
|
|
bool mask[V::size()] = {};
|
|
auto k = hmin(x + x - x * x) == x / x;
|
|
k.copy_to(mask, stdx::element_aligned);
|
|
mask[0] = false;
|
|
using M = typename V::mask_type;
|
|
return M(mask, stdx::element_aligned);
|
|
}();
|
|
|
|
static_assert(not e[0]);
|
|
static_assert(popcount(e) == V::size() - 1);
|
|
|
|
static_assert(all_of(V(T(1)) == []() constexpr {
|
|
float data[V::size()] = {};
|
|
V(T(1)).copy_to(data, stdx::element_aligned);
|
|
V x = T();
|
|
x.copy_from(data, stdx::element_aligned);
|
|
return x;
|
|
}()));
|
|
|
|
static_assert(hmin(V()) == T());
|
|
static_assert(hmax(V()) == T());
|
|
static_assert(reduce(V(1)) == T(V::size()));
|
|
}
|
|
|
|
template <typename T>
|
|
void
|
|
iterate_abis()
|
|
{
|
|
test01<T, stdx::simd<T, stdx::simd_abi::scalar>>();
|
|
test01<T, stdx::simd<T>>();
|
|
test01<T, stdx::native_simd<T>>();
|
|
test01<T, stdx::fixed_size_simd<T, 3>>();
|
|
test01<T, stdx::fixed_size_simd<T, stdx::simd_abi::max_fixed_size<T> - 4>>();
|
|
}
|
|
|
|
int main()
|
|
{
|
|
iterate_abis<char>();
|
|
iterate_abis<wchar_t>();
|
|
iterate_abis<char16_t>();
|
|
iterate_abis<char32_t>();
|
|
|
|
iterate_abis<signed char>();
|
|
iterate_abis<unsigned char>();
|
|
iterate_abis<short>();
|
|
iterate_abis<unsigned short>();
|
|
iterate_abis<int>();
|
|
iterate_abis<unsigned int>();
|
|
iterate_abis<long>();
|
|
iterate_abis<unsigned long>();
|
|
iterate_abis<long long>();
|
|
iterate_abis<unsigned long long>();
|
|
iterate_abis<float>();
|
|
iterate_abis<double>();
|
|
iterate_abis<long double>();
|
|
}
|