Matthias Kretz dad9abd7da libstdc++: Add missing constexpr to simd
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)
2023-05-25 09:03:39 +02:00

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>();
}