25#ifndef _GLIBCXX_SIMD_DETAILS_H
26#define _GLIBCXX_SIMD_DETAILS_H 1
29#pragma GCC system_header
32#if __cplusplus >= 202400L
47#error "<simd> is not supported for CHAR_BIT != 8"
51#pragma GCC diagnostic push
52#pragma GCC diagnostic ignored "-Wpsabi"
54#if defined __x86_64__ || defined __i386__
60#ifndef _GLIBCXX_SIMD_NOEXCEPT
64#define _GLIBCXX_SIMD_NOEXCEPT noexcept
67#define _GLIBCXX_SIMD_TOSTRING_IMPL(x) #x
68#define _GLIBCXX_SIMD_TOSTRING(x) _GLIBCXX_SIMD_TOSTRING_IMPL(x)
71#define __glibcxx_simd_precondition(expr, msg, ...) \
72 __glibcxx_assert(expr)
74namespace std _GLIBCXX_VISIBILITY(default)
76_GLIBCXX_BEGIN_NAMESPACE_VERSION
78 template<
typename>
class complex;
82 template <
typename _Tp>
84 __iota = [] {
static_assert(
false,
"invalid __iota specialization"); }();
87 template <
typename _Tp>
88 concept __complex_like_impl
89 = same_as<_Tp, complex<typename _Tp::value_type>>;
94 template <
typename _Tp>
95 concept __complex_like = __complex_like_impl<remove_cvref_t<_Tp>>;
97 template <
typename _Tp>
98 concept __vectorizable_scalar
99 = same_as<remove_cv_t<_Tp>, _Tp>
100#ifdef __STDCPP_BFLOAT16_T__
101 && !same_as<_Tp, __gnu_cxx::__bfloat16_t>
103 && ((integral<_Tp> &&
sizeof(_Tp) <=
sizeof(0ULL) && !same_as<_Tp, bool>)
104 || (floating_point<_Tp> &&
sizeof(_Tp) <=
sizeof(double)));
107 template <
typename _Tp>
108 concept __vectorizable
109 = __vectorizable_scalar<_Tp>
110 || (__complex_like_impl<_Tp> && __vectorizable_scalar<typename _Tp::value_type>
111 && floating_point<typename _Tp::value_type>);
116 enum class _AbiVariant :
unsigned long long
119 _MaskVariants = 0x0f,
124 _CxVariants = _CxIleav | _CxCtgus,
130 consteval _AbiVariant
131 __filter_abi_variant(_AbiVariant __in, same_as<_AbiVariant>
auto... __to_keep)
134 return static_cast<_AbiVariant
>(
static_cast<_Up
>(__in) & (
static_cast<_Up
>(__to_keep) | ...));
140 struct _InvalidInteger
148 template <
size_t _Bytes>
150 =
decltype([]
consteval {
151 if constexpr (
sizeof(
signed char) == _Bytes)
152 return static_cast<signed char>(0);
153 else if constexpr (
sizeof(
signed short) == _Bytes)
154 return static_cast<signed short>(0);
155 else if constexpr (
sizeof(
signed int) == _Bytes)
156 return static_cast<signed int>(0);
157 else if constexpr (
sizeof(
signed long long) == _Bytes)
158 return static_cast<signed long long>(0);
160 return _InvalidInteger();
163 template <
size_t _Bytes>
164 using __float_from =
decltype([]
consteval {
165 if constexpr (
sizeof(double) == _Bytes)
167 else if constexpr (
sizeof(float) == _Bytes)
169 else if constexpr (
sizeof(_Float16) == _Bytes)
176 template <
size_t _Bytes>
184 template <
typename _Tp>
186 __div_ceil(_Tp __x, _Tp __y)
187 {
return (__x + __y - 1) / __y; }
192 template <
int _NBits>
193 requires (_NBits > 0 && _NBits <= numeric_limits<unsigned long long>::digits)
194 using _Bitmask = _UInt<__div_ceil(__bit_ceil(
unsigned(_NBits)),
unsigned(__CHAR_BIT__))>;
202 template <
typename _Tp>
203 struct __canonical_vec_type
204 {
using type = _Tp; };
206 template <
typename _Tp>
207 using __canonical_vec_type_t =
typename __canonical_vec_type<_Tp>::type;
209#if __SIZEOF_INT__ == __SIZEOF_LONG__
211 struct __canonical_vec_type<long>
212 {
using type = int; };
215 struct __canonical_vec_type<unsigned long>
216 {
using type =
unsigned int; };
217#elif __SIZEOF_LONG_LONG__ == __SIZEOF_LONG__
219 struct __canonical_vec_type<long>
220 {
using type =
long long; };
223 struct __canonical_vec_type<unsigned long>
224 {
using type =
unsigned long long; };
227 template <
typename _Tp>
228 requires std::is_enum_v<_Tp>
229 struct __canonical_vec_type<_Tp>
230 {
using type = __canonical_vec_type<std::underlying_type_t<_Tp>>::type; };
233 struct __canonical_vec_type<char>
235 {
using type =
unsigned char; };
237 {
using type =
signed char; };
241 struct __canonical_vec_type<char8_t>
242 {
using type =
unsigned char; };
245 struct __canonical_vec_type<char16_t>
246 {
using type = uint_least16_t; };
249 struct __canonical_vec_type<char32_t>
250 {
using type = uint_least32_t; };
253 struct __canonical_vec_type<wchar_t>
255 using type = std::__conditional_t<std::is_signed_v<wchar_t>,
256 simd::__integer_from<
sizeof(wchar_t)>,
257 simd::_UInt<
sizeof(
wchar_t)>>;
260#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
262 struct __canonical_vec_type<_Float64>
263 {
using type = double; };
266#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
268 struct __canonical_vec_type<_Float32>
269 {
using type = float; };
294 template <
int _Np,
int _Nreg, underlying_type_t<_AbiVariant> _Var>
297 static constexpr int _S_size = _Np;
315 static constexpr int _S_nreg = _Nreg;
317 static_assert(_S_size > 0);
318 static_assert(_S_nreg > 0);
320 static constexpr _AbiVariant _S_variant =
static_cast<_AbiVariant
>(_Var);
322 static constexpr bool _S_is_cx_ileav
323 = __filter_abi_variant(_S_variant, _AbiVariant::_CxIleav) == _AbiVariant::_CxIleav;
325 static constexpr bool _S_is_cx_ctgus
326 = __filter_abi_variant(_S_variant, _AbiVariant::_CxCtgus) == _AbiVariant::_CxCtgus;
328 static_assert(!(_S_is_cx_ileav && _S_is_cx_ctgus));
330 static_assert(_S_size >= _S_nreg || (_S_is_cx_ileav && _S_size * 2 >= _S_nreg));
332 static constexpr bool _S_is_bitmask
333 = __filter_abi_variant(_S_variant, _AbiVariant::_BitMask) == _AbiVariant::_BitMask;
335 static constexpr bool _S_is_vecmask = !_S_is_bitmask;
337 template <
typename _Tp>
338 using _DataType =
decltype([] {
339 static_assert(_S_nreg == 1);
340 if constexpr (_S_size == 1)
341 return __canonical_vec_type_t<_Tp>();
344 constexpr int __n = __bit_ceil(
unsigned(_S_size));
345 using _Vp [[__gnu__::__vector_size__(
sizeof(_Tp) * __n)]]
346 = __canonical_vec_type_t<_Tp>;
351 template <
size_t _Bytes>
354 static_assert(_S_nreg == 1);
355 if constexpr (_S_size == 1)
357 else if constexpr (_S_is_vecmask)
359 constexpr unsigned __vbytes = _Bytes * __bit_ceil(
unsigned(_S_size));
360 using _Vp [[__gnu__::__vector_size__(__vbytes)]] = __integer_from<_Bytes>;
363 else if constexpr (_Nreg > 1)
364 return _InvalidInteger();
366 return _Bitmask<_S_size>();
369 template <
int _N2,
int _Nreg2 = __div_ceil(_N2, _S_size)>
370 static consteval auto
373 if constexpr (_N2 == 1)
374 return _Abi<1, 1, _Var>();
376 return _Abi<_N2, _Nreg2, _Var>();
392 template <
int _Np,
int _Nreg, _AbiVariant... _Vs>
399 {
static constexpr int _S_size = 0; };
405 template <
typename _Tp>
407 = same_as<
decltype(_Tp::_S_variant),
const _AbiVariant>
408 && (_Tp::_S_size >= _Tp::_S_nreg) && (_Tp::_S_nreg >= 1)
409 &&
requires(_Tp __x) {
410 { __x.template _S_resize<_Tp::_S_size, _Tp::_S_nreg>() } -> same_as<_Tp>;
417 template <
typename _Tp>
418 concept __scalar_abi_tag
419 = same_as<_Tp, _Abi_t<_Tp::_S_size, _Tp::_S_size, _Tp::_S_variant>> && __abi_tag<_Tp>;
428#ifdef math_errhandling
429 template <
int _ErrHandling = math_errhandling>
431 __handle_fpexcept_impl(
int)
432 {
return 0 != (_ErrHandling & MATH_ERREXCEPT); }
437 __handle_fpexcept_impl(
float)
447 _M_test(
int __bit)
const
448 {
return ((_M_build_flags >> __bit) & 1) == 1; }
452 _M_fp_may_signal()
const
453 {
return _M_test(0); }
457 _M_fp_may_raise()
const
458 {
return _M_test(12); }
462 {
return _M_test(1); }
465 _M_finite_math_only()
const
466 {
return _M_test(2); }
469 _M_no_signed_zeros()
const
470 {
return _M_test(3); }
473 _M_signed_zeros()
const
474 {
return !_M_test(3); }
477 _M_reciprocal_math()
const
478 {
return _M_test(4); }
481 _M_no_math_errno()
const
482 {
return _M_test(5); }
485 _M_math_errno()
const
486 {
return !_M_test(5); }
489 _M_associative_math()
const
490 {
return _M_test(6); }
493 _M_conforming_to_STDC_annex_G()
const
494 {
return _M_test(10) && !_M_finite_math_only(); }
497 _M_support_snan()
const
498 {
return _M_test(11); }
500 __UINT64_TYPE__ _M_build_flags
502#if !__NO_TRAPPING_MATH__
505 + (__handle_fpexcept_impl(0) << 12)
509#
if __FINITE_MATH_ONLY__
512#if __NO_SIGNED_ZEROS__
515#
if __RECIPROCAL_MATH__
521#
if __ASSOCIATIVE_MATH__
525#if __FLT_EVAL_METHOD__ == 1
527#elif __FLT_EVAL_METHOD__ == 2
529#elif __FLT_EVAL_METHOD__ != 0
540#
if defined __STDC_IEC_60559_COMPLEX__ || defined __STDC_IEC_559_COMPLEX__ \
541 || (defined __GCC_IEC_559_COMPLEX && __GCC_IEC_559_COMPLEX > 0) || defined _GLIBCXX_CLANG
554 __streq_to_1(
const char* __s)
555 {
return __s !=
nullptr && __s[0] ==
'1' && __s[1] ==
'\0'; }
561#define _GLIBCXX_SIMD_ARCH_FLAG(off, feat) \
562 (static_cast<__UINT64_TYPE__>(std::simd::__streq_to_1(_GLIBCXX_SIMD_TOSTRING_IMPL(feat))) << off)
566#define _GLIBCXX_SIMD_ARCH_TRAITS_INIT { \
567 _GLIBCXX_SIMD_ARCH_FLAG(0, __MMX__) \
568 | _GLIBCXX_SIMD_ARCH_FLAG( 1, __SSE__) \
569 | _GLIBCXX_SIMD_ARCH_FLAG( 2, __SSE2__) \
570 | _GLIBCXX_SIMD_ARCH_FLAG( 3, __SSE3__) \
571 | _GLIBCXX_SIMD_ARCH_FLAG( 4, __SSSE3__) \
572 | _GLIBCXX_SIMD_ARCH_FLAG( 5, __SSE4_1__) \
573 | _GLIBCXX_SIMD_ARCH_FLAG( 6, __SSE4_2__) \
574 | _GLIBCXX_SIMD_ARCH_FLAG( 7, __POPCNT__) \
575 | _GLIBCXX_SIMD_ARCH_FLAG( 8, __AVX__) \
576 | _GLIBCXX_SIMD_ARCH_FLAG( 9, __F16C__) \
577 | _GLIBCXX_SIMD_ARCH_FLAG(10, __BMI__) \
578 | _GLIBCXX_SIMD_ARCH_FLAG(11, __BMI2__) \
579 | _GLIBCXX_SIMD_ARCH_FLAG(12, __LZCNT__) \
580 | _GLIBCXX_SIMD_ARCH_FLAG(13, __AVX2__) \
581 | _GLIBCXX_SIMD_ARCH_FLAG(14, __FMA__) \
582 | _GLIBCXX_SIMD_ARCH_FLAG(15, __AVX512F__) \
583 | _GLIBCXX_SIMD_ARCH_FLAG(16, __AVX512CD__) \
584 | _GLIBCXX_SIMD_ARCH_FLAG(17, __AVX512DQ__) \
585 | _GLIBCXX_SIMD_ARCH_FLAG(18, __AVX512BW__) \
586 | _GLIBCXX_SIMD_ARCH_FLAG(19, __AVX512VL__) \
587 | _GLIBCXX_SIMD_ARCH_FLAG(20, __AVX512BITALG__) \
588 | _GLIBCXX_SIMD_ARCH_FLAG(21, __AVX512VBMI__) \
589 | _GLIBCXX_SIMD_ARCH_FLAG(22, __AVX512VBMI2__) \
590 | _GLIBCXX_SIMD_ARCH_FLAG(23, __AVX512IFMA__) \
591 | _GLIBCXX_SIMD_ARCH_FLAG(24, __AVX512VNNI__) \
592 | _GLIBCXX_SIMD_ARCH_FLAG(25, __AVX512VPOPCNTDQ__) \
593 | _GLIBCXX_SIMD_ARCH_FLAG(26, __AVX512FP16__) \
594 | _GLIBCXX_SIMD_ARCH_FLAG(27, __AVX512BF16__) \
595 | _GLIBCXX_SIMD_ARCH_FLAG(28, __AVXIFMA__) \
596 | _GLIBCXX_SIMD_ARCH_FLAG(29, __AVXNECONVERT__) \
597 | _GLIBCXX_SIMD_ARCH_FLAG(30, __AVXVNNI__) \
598 | _GLIBCXX_SIMD_ARCH_FLAG(31, __AVXVNNIINT8__) \
599 | _GLIBCXX_SIMD_ARCH_FLAG(32, __AVXVNNIINT16__) \
600 | _GLIBCXX_SIMD_ARCH_FLAG(33, __AVX10_1__) \
601 | _GLIBCXX_SIMD_ARCH_FLAG(34, __AVX10_2__) \
602 | _GLIBCXX_SIMD_ARCH_FLAG(35, __AVX512VP2INTERSECT__) \
603 | _GLIBCXX_SIMD_ARCH_FLAG(36, __SSE4A__) \
604 | _GLIBCXX_SIMD_ARCH_FLAG(37, __FMA4__) \
605 | _GLIBCXX_SIMD_ARCH_FLAG(38, __XOP__) \
613 __UINT64_TYPE__ _M_flags = _GLIBCXX_SIMD_ARCH_TRAITS_INIT;
616 _M_test(
int __bit)
const
617 {
return ((_M_flags >> __bit) & 1) == 1; }
621 {
return _M_test(0); }
625 {
return _M_test(1); }
629 {
return _M_test(2); }
633 {
return _M_test(3); }
636 _M_have_ssse3()
const
637 {
return _M_test(4); }
640 _M_have_sse4_1()
const
641 {
return _M_test(5); }
644 _M_have_sse4_2()
const
645 {
return _M_test(6); }
648 _M_have_popcnt()
const
649 {
return _M_test(7); }
653 {
return _M_test(8); }
657 {
return _M_test(9); }
661 {
return _M_test(10); }
665 {
return _M_test(11); }
668 _M_have_lzcnt()
const
669 {
return _M_test(12); }
673 {
return _M_test(13); }
677 {
return _M_test(14); }
680 _M_have_avx512f()
const
681 {
return _M_test(15); }
684 _M_have_avx512cd()
const
685 {
return _M_test(16); }
688 _M_have_avx512dq()
const
689 {
return _M_test(17); }
692 _M_have_avx512bw()
const
693 {
return _M_test(18); }
696 _M_have_avx512vl()
const
697 {
return _M_test(19); }
700 _M_have_avx512bitalg()
const
701 {
return _M_test(20); }
704 _M_have_avx512vbmi()
const
705 {
return _M_test(21); }
708 _M_have_avx512vbmi2()
const
709 {
return _M_test(22); }
712 _M_have_avx512ifma()
const
713 {
return _M_test(23); }
716 _M_have_avx512vnni()
const
717 {
return _M_test(24); }
720 _M_have_avx512vpopcntdq()
const
721 {
return _M_test(25); }
724 _M_have_avx512fp16()
const
725 {
return _M_test(26); }
728 _M_have_avx512bf16()
const
729 {
return _M_test(27); }
732 _M_have_avxifma()
const
733 {
return _M_test(28); }
736 _M_have_avxneconvert()
const
737 {
return _M_test(29); }
740 _M_have_avxvnni()
const
741 {
return _M_test(30); }
744 _M_have_avxvnniint8()
const
745 {
return _M_test(31); }
748 _M_have_avxvnniint16()
const
749 {
return _M_test(32); }
752 _M_have_avx10_1()
const
753 {
return _M_test(33); }
756 _M_have_avx10_2()
const
757 {
return _M_test(34); }
760 _M_have_avx512vp2intersect()
const
761 {
return _M_test(35); }
764 _M_have_sse4a()
const
765 {
return _M_test(36); }
769 {
return _M_test(37); }
773 {
return _M_test(38); }
775 template <
typename _Tp>
777 _M_eval_as_f32()
const
778 {
return is_same_v<_Tp, _Float16> && !_M_have_avx512fp16(); }
781 _M_have_addsub()
const
782 {
return _M_have_sse3(); }
785 template <
typename _Tp, _ArchTraits _Traits = {}>
789 constexpr int __adj_sizeof =
sizeof(_Tp) * (1 + is_same_v<_Tp, _Float16>);
790 if constexpr (!__vectorizable<_Tp>)
791 return _InvalidAbi();
792 else if constexpr (__complex_like<_Tp>)
794 constexpr auto __underlying = std::simd::__native_abi<typename _Tp::value_type>();
795 constexpr int __cx_size = __underlying._S_size / (__underlying._S_size == 1 ? 1 : 2);
796 return _Abi_t<__cx_size, 1, __underlying._S_variant, _AbiVariant::_CxIleav>();
798 else if constexpr (_Traits._M_have_avx512fp16())
799 return _Abi_t<64 /
sizeof(_Tp), 1, _AbiVariant::_BitMask>();
800 else if constexpr (_Traits._M_have_avx512f())
801 return _Abi_t<64 / __adj_sizeof, 1, _AbiVariant::_BitMask>();
802 else if constexpr (is_same_v<_Tp, _Float16> && !_Traits._M_have_f16c())
803 return _Abi_t<1, 1>();
804 else if constexpr (_Traits._M_have_avx2())
805 return _Abi_t<32 / __adj_sizeof, 1>();
806 else if constexpr (_Traits._M_have_avx() && is_floating_point_v<_Tp>)
807 return _Abi_t<32 / __adj_sizeof, 1>();
808 else if constexpr (_Traits._M_have_sse2())
809 return _Abi_t<16 / __adj_sizeof, 1>();
810 else if constexpr (_Traits._M_have_sse() && is_floating_point_v<_Tp>
811 &&
sizeof(_Tp) ==
sizeof(
float))
812 return _Abi_t<16 / __adj_sizeof, 1>();
815 return _Abi_t<1, 1>();
823 __UINT64_TYPE__ _M_flags = 0;
826 _M_test(
int __bit)
const
827 {
return ((_M_flags >> __bit) & 1) == 1; }
830 template <
typename _Tp>
834 if constexpr (!__vectorizable<_Tp>)
835 return _InvalidAbi();
836 else if constexpr (__complex_like<_Tp>)
837 return _Abi_t<1, 1, _AbiVariant::_CxIleav>();
839 return _Abi_t<1, 1>();
849 : _ArchTraits, _OptTraits
860 template <
typename _Tp>
861 using __native_abi_t =
decltype(std::simd::__native_abi<_Tp>());
863 template <
typename _Tp,
int _Np, _TargetTraits _Target = {}>
867 constexpr auto __native = std::simd::__native_abi<_Tp>();
868 if constexpr (0 == __native._S_size || _Np <= 0)
869 return _InvalidAbi();
870 else if constexpr (_Np == __native._S_size)
873 return __native.template _S_resize<_Np>();
881 template <
typename _Tp,
int _Np>
882 using __deduce_abi_t =
decltype(std::simd::__deduce_abi<_Tp, _Np>());
888 template <
typename _Tp,
int _Np, __abi_tag _A0, _ArchTraits = {}>
892 if constexpr (_Np <= 0 || !__vectorizable<_Tp>)
893 return _InvalidAbi();
897 using _Native = remove_const_t<decltype(std::simd::__native_abi<_Tp>())>;
898 static_assert(0 != _Native::_S_size);
899 constexpr int __nreg = __div_ceil(_Np, _Native::_S_size);
903 if constexpr (__scalar_abi_tag<_Native> || (__scalar_abi_tag<_A0> && _A0::_S_size >= 2))
905 constexpr bool __remove_cx
906 = __filter_abi_variant(_A0::_S_variant, _AbiVariant::_CxVariants) != _AbiVariant()
907 && !__complex_like<_Tp>;
908 constexpr bool __add_cx
909 = __filter_abi_variant(_A0::_S_variant, _AbiVariant::_CxVariants) == _AbiVariant()
910 && __complex_like<_Tp>;
912 if constexpr (__remove_cx)
913 return _Abi_t<_Np, _Np,
914 __filter_abi_variant(_A0::_S_variant, _AbiVariant::_MaskVariants)>();
915 else if constexpr (__add_cx)
916 return _Abi_t<_Np, _Np, _A0::_S_variant,
917 __filter_abi_variant(_Native::_S_variant, _AbiVariant::_CxVariants)>();
919 return _A0::template _S_resize<_Np, _Np>();
922 else if constexpr (__complex_like<_Tp> && _A0::_S_is_cx_ctgus && _Native::_S_is_cx_ileav)
925 return _A0::template _S_resize<_Np, __div_ceil(__nreg, 2)>();
927 else if constexpr (__complex_like<_Tp> && _A0::_S_is_cx_ileav && _Native::_S_is_cx_ctgus)
928 return _A0::template _S_resize<_Np, __nreg * 2>();
930 else if constexpr (__complex_like<_Tp> && (_A0::_S_is_cx_ctgus || _A0::_S_is_cx_ileav))
931 return _A0::template _S_resize<_Np, __nreg>();
933 else if constexpr (__complex_like<_Tp>)
935 return _Abi_t<_Native::_S_size, 1, _A0::_S_variant,
936 __filter_abi_variant(_Native::_S_variant, _AbiVariant::_CxVariants)>
937 ::template _S_resize<_Np, __nreg>();
940 return _Abi_t<_Native::_S_size, 1, __filter_abi_variant(_A0::_S_variant,
941 _AbiVariant::_MaskVariants)
942 >::template _S_resize<_Np, __nreg>();
956 template <
size_t _Bytes,
int _Np, __abi_tag _A0,
bool _IsOnlyResize, _ArchTraits _Traits = {}>
960 constexpr bool __from_cx = _A0::_S_is_cx_ctgus || _A0::_S_is_cx_ileav;
962 if constexpr (_Bytes == 0 || _Np <= 0)
963 return _InvalidAbi();
968 else if constexpr (__from_cx && _IsOnlyResize && _Bytes == 2 *
sizeof(double))
969 return __abi_rebind<complex<double>, _Np, _A0>();
970 else if constexpr (__from_cx && _IsOnlyResize && _Bytes == 2 *
sizeof(float))
971 return __abi_rebind<complex<float>, _Np, _A0>();
972 else if constexpr (__from_cx && _IsOnlyResize && _Bytes == 2 *
sizeof(_Float16))
973 return __abi_rebind<complex<_Float16>, _Np, _A0>();
980 else if constexpr (_IsOnlyResize
981 && _Traits._M_have_avx() && !_Traits._M_have_avx2()
982 && __bit_ceil(__div_ceil<unsigned>(
983 _A0::_S_size, _A0::_S_nreg)) * _Bytes == 32)
985 if constexpr (_Bytes ==
sizeof(double))
986 return __abi_rebind<double, _Np, _A0>();
987 else if constexpr (_Bytes ==
sizeof(float))
988 return __abi_rebind<float, _Np, _A0>();
989 else if constexpr (_Traits._M_have_f16c() && _Bytes ==
sizeof(_Float16))
990 return __abi_rebind<_Float16, _Np, _A0>();
992 static_assert(
false);
997 return __abi_rebind<__integer_from<_Bytes>, _Np, _A0>();
1013 template <
typename _To,
typename _From>
1015 __is_mask_conversion_explicit([[maybe_unused]]
size_t __b0, [[maybe_unused]]
size_t __b1)
1017 constexpr int __n = _To::_S_size;
1018 static_assert(__n == _From::_S_size);
1019#ifndef _GLIBCXX_SIMD_COND_EXPLICIT_MASK_CONVERSION
1027 else if constexpr (_To::_S_is_vecmask != _From::_S_is_vecmask)
1028 return _To::_S_is_vecmask;
1031 else if constexpr (_From::_S_nreg != _To::_S_nreg)
1032 return _From::_S_nreg < _To::_S_nreg;
1036 else if constexpr (_To::_S_is_cx_ileav)
1038 else if constexpr (_From::_S_is_cx_ileav)
1042 else if constexpr (_To::_S_is_cx_ctgus)
1044 else if constexpr (_From::_S_is_cx_ctgus)
1047 __builtin_unreachable();
1059 using __simd_size_type = int;
1062 template <__simd_
size_type _Xp>
1063 inline constexpr integral_constant<__simd_size_type, _Xp> __simd_size_c = {};
1066 template <
typename _Tp,
typename _Ap = __native_abi_t<_Tp>>
1069 template <typename _Tp, __simd_size_type _Np = __native_abi_t<_Tp>::_S_size>
1070 using vec = basic_vec<_Tp, __deduce_abi_t<_Tp, _Np>>;
1072 template <
size_t _Bytes,
typename _Ap = __native_abi_t<__
integer_from<_Bytes>>>
1075 template <typename _Tp, __simd_size_type _Np = __native_abi_t<_Tp>::_S_size>
1076 using mask = basic_mask<
sizeof(_Tp), __deduce_abi_t<_Tp, _Np>>;
1079 template <
typename _Rg>
1081 __static_range_size(_Rg& __r)
1083 if constexpr (ranges::__static_sized_range<_Rg>)
1084 return ranges::size(__r);
1086 return dynamic_extent;
1090 template <
typename _From,
typename _To>
1091 concept __arithmetic_only_value_preserving_convertible_to
1092 = convertible_to<_From, _To> && is_arithmetic_v<_From> && is_arithmetic_v<_To>
1093 && !(is_signed_v<_From> && is_unsigned_v<_To>)
1103 template <
typename _From,
typename _To>
1104 concept __value_preserving_convertible_to
1105 = __arithmetic_only_value_preserving_convertible_to<_From, _To>
1106 || (__complex_like<_To> && __arithmetic_only_value_preserving_convertible_to<
1107 _From,
typename _To::value_type>);
1110 template <
typename _From,
typename _To>
1111 concept __explicitly_convertible_to =
requires {
1119 template <auto _From,
typename _To>
1120 concept __non_narrowing_constexpr_conversion
1121 = is_arithmetic_v<
decltype(_From)>
1122 &&
static_cast<decltype(_From)
>(
static_cast<_To
>(_From)) == _From
1123 && !(unsigned_integral<_To> && _From <
decltype(_From)())
1129 template <
typename _From,
typename _To>
1130 concept __broadcast_constructible
1131 = ((convertible_to<_From, _To> && !is_arithmetic_v<remove_cvref_t<_From>>
1132 && !__constexpr_wrapper_like<remove_cvref_t<_From>>)
1133 || __value_preserving_convertible_to<remove_cvref_t<_From>, _To>
1134 || (__constexpr_wrapper_like<remove_cvref_t<_From>>
1135 && __non_narrowing_constexpr_conversion<
auto(remove_cvref_t<_From>::value),
1139 template <
typename _From,
typename _To>
1141 __higher_floating_point_rank_than()
1143 return floating_point<_From> && floating_point<_To>
1144 && is_same_v<common_type_t<_From, _To>, _From> && !is_same_v<_From, _To>;
1148 template <
typename _From,
typename _To>
1150 __higher_integer_rank_than()
1152 return integral<_From> && integral<_To>
1153 && (
sizeof(_From) >
sizeof(_To) || is_same_v<common_type_t<_From, _To>, _From>)
1154 && !is_same_v<_From, _To>;
1157 template <
typename _From,
typename _To>
1158 concept __higher_rank_than
1159 = __higher_floating_point_rank_than<_From, _To>() || __higher_integer_rank_than<_From, _To>();
1161 struct __convert_flag;
1163 template <
typename _From,
typename _To,
typename... _Flags>
1164 concept __loadstore_convertible_to
1165 = same_as<_From, _To>
1166 || (__vectorizable<_From> && __vectorizable<_To>
1167 && (__value_preserving_convertible_to<_From, _To>
1168 || (__explicitly_convertible_to<_From, _To>
1169 && (std::is_same_v<_Flags, __convert_flag> || ...))));
1171 template <
typename _From,
typename _To>
1172 concept __simd_generator_convertible_to
1173 = std::convertible_to<_From, _To>
1174 && (!is_arithmetic_v<_From> || __value_preserving_convertible_to<_From, _To>);
1176 template <
typename _Fp,
typename _Tp, __simd_size_type... _Is>
1177 requires (__simd_generator_convertible_to<
1178 decltype(
declval<_Fp>()(__simd_size_c<_Is>)), _Tp> && ...)
1180 __simd_generator_invokable_impl(integer_sequence<__simd_size_type, _Is...>);
1182 template <
typename _Fp,
typename _Tp, __simd_
size_type _Np>
1183 concept __simd_generator_invokable =
requires {
1187 template <
typename _Fp>
1188 concept __index_permutation_function_sized =
requires(_Fp
const& __f)
1190 { __f(0, 0) } -> std::integral;
1193 template <
typename _Fp,
typename _Simd>
1194 concept __index_permutation_function
1195 = __index_permutation_function_sized<_Fp> ||
requires(_Fp
const& __f) {
1196 { __f(0) } -> std::integral;
1204 template <
typename _Tp>
1205 constexpr size_t __mask_element_size = 0;
1207 template <
size_t _Bytes, __abi_tag _Ap>
1208 constexpr size_t __mask_element_size<basic_mask<_Bytes, _Ap>> = _Bytes;
1211 template <
typename _Vp>
1212 concept __simd_vec_type
1213 = same_as<_Vp, basic_vec<typename _Vp::value_type, typename _Vp::abi_type>>
1214 && is_default_constructible_v<_Vp>;
1216 template <
typename _Vp>
1217 concept __simd_mask_type
1218 = same_as<_Vp, basic_mask<__mask_element_size<_Vp>,
typename _Vp::abi_type>>
1219 && is_default_constructible_v<_Vp>;
1224 template <
typename _Vp>
1225 concept __simd_vec_or_mask_type = __simd_vec_type<_Vp> || __simd_mask_type<_Vp>;
1227 template <
typename _Vp>
1228 concept __simd_floating_point
1229 = __simd_vec_type<_Vp> && floating_point<typename _Vp::value_type>;
1231 template <
typename _Vp>
1232 concept __simd_integral
1233 = __simd_vec_type<_Vp> && integral<typename _Vp::value_type>;
1235 template <
typename _Vp>
1236 concept __simd_unsigned_integer
1237 = __simd_vec_type<_Vp> && __unsigned_integer<typename _Vp::value_type>;
1239 template <
typename _Vp>
1240 using __simd_complex_value_type =
typename _Vp::value_type::value_type;
1242 template <
typename _Vp>
1243 concept __simd_complex
1244 = __simd_vec_type<_Vp> && __complex_like_impl<typename _Vp::value_type>;
1246 template <
typename _Tp>
1247 concept __converts_to_vec
1250 template <__converts_to_vec _Tp>
1253 template <
typename _Vp,
typename _Tp>
1254 using __make_compatible_simd_t
1257 if constexpr (__simd_vec_type<_Up>)
1260 return vec<_Up, _Vp::size()>();
1263 template <
typename _Tp>
1264 concept __math_floating_point = __simd_floating_point<__deduced_vec_t<_Tp>>;
1266 template <
typename _BinaryOperation,
typename _Tp>
1267 concept __reduction_binary_operation
1268 =
requires (
const _BinaryOperation __binary_op,
const vec<_Tp, 1> __v) {
1269 { __binary_op(__v, __v) } -> same_as<vec<_Tp, 1>>;
1275 [[__gnu__::__always_inline__]]
1276 constexpr __simd_size_type
1277 __highest_bit(std::unsigned_integral
auto __bits)
1280 constexpr auto _Nd =
__int_traits<
decltype(__bits)>::__digits;
1281 return _Nd - 1 - __countl_zero(__bits);
1284 template <__vectorizable _Tp, __simd_
size_type _Np, __abi_tag _Ap>
1285 using __similar_mask = basic_mask<sizeof(_Tp), decltype(__abi_rebind<_Tp, _Np, _Ap>())>;
1287 template <
size_t _Bytes, __abi_tag _Ap>
1288 using __component_mask_for_ileav
1289 = basic_mask<_Bytes / 2,
1290 decltype(__abi_rebind<__float_from<_Bytes / 2>, _Ap::_S_size * 2, _Ap>())>;
1292 template <
size_t _Bytes, __abi_tag _Ap>
1293 using __component_mask_for_ctgus
1294 = basic_mask<_Bytes / 2,
1295 decltype(__abi_rebind<__float_from<_Bytes / 2>, _Ap::_S_size, _Ap>())>;
1298 template <
typename _Tp, __simd_
size_type _Np, __abi_tag _Ap>
1299 using __similar_vec = basic_vec<_Tp, decltype(__abi_rebind<_Tp, _Np, _Ap>())>;
1302 template <
size_t _Bytes,
typename _Ap>
1303 using __simd_vec_from_mask_t = __similar_vec<__integer_from<_Bytes>, _Ap::_S_size, _Ap>;
1305#if _GLIBCXX_SIMD_THROW_ON_BAD_VALUE
1306 class __bad_value_preserving_cast
1309#define __glibcxx_on_bad_value_preserving_cast throw __bad_value_preserving_cast
1311 void __bad_value_preserving_cast();
1313#define __glibcxx_on_bad_value_preserving_cast __bad_value_preserving_cast
1316 template <
typename _To,
typename _From>
1317#if _GLIBCXX_SIMD_THROW_ON_BAD_VALUE
1318 [[__gnu__::__optimize__(
"exceptions")]]
1321 __value_preserving_cast(
const _From& __x)
1323 static_assert(is_arithmetic_v<_From>);
1324 if constexpr (!__value_preserving_convertible_to<_From, _To>)
1326 using _Up =
typename __make_unsigned<_From>::__type;
1327 if (
static_cast<_Up
>(
static_cast<_To
>(__x)) !=
static_cast<_Up
>(__x))
1328 __glibcxx_on_bad_value_preserving_cast();
1329 else if constexpr (is_signed_v<_From> && is_unsigned_v<_To>)
1332 __glibcxx_on_bad_value_preserving_cast();
1334 else if constexpr (unsigned_integral<_From> && signed_integral<_To>)
1337 __glibcxx_on_bad_value_preserving_cast();
1340 return static_cast<_To
>(__x);
1346 template <
typename _T0,
typename _T1>
1347 struct __trivial_pair
1353 template <
typename _From,
typename _To>
1354 concept __converts_trivially = convertible_to<_From, _To>
1355 &&
sizeof(_From) ==
sizeof(_To)
1356 && is_integral_v<_From> == is_integral_v<_To>
1357 && is_floating_point_v<_From> == is_floating_point_v<_To>;
1359 [[__gnu__::__always_inline__]]
1361 __bit_foreach(unsigned_integral
auto __bits,
auto&& __fun)
1363 static_assert(
sizeof(__bits) >=
sizeof(int));
1366 __fun(__countr_zero(__bits));
1367 __bits &= (__bits - 1);
1385 template <
size_t _Chunk,
size_t _Max>
1387 __memcpy_chunks(
byte* __restrict__ __dst,
const byte* __restrict__ __src,
1390 static_assert(_Max <= 64);
1391 static_assert(__has_single_bit(_Chunk) && _Chunk <= 8);
1392 size_t __bytes = _Chunk * __n;
1393 if (__builtin_constant_p(__bytes))
1396 __builtin_memcpy(__dst, __src, __bytes);
1398 else if (__bytes > 32 && _Max > 32)
1400 __builtin_memcpy(__dst, __src, 32);
1402 __builtin_memcpy(__dst + __bytes, __src + __bytes, 32);
1404 else if (__bytes > 16 && _Max > 16)
1406 __builtin_memcpy(__dst, __src, 16);
1407 if constexpr (_Chunk == 8)
1410 __builtin_memcpy(__dst + __bytes, __src + __bytes, 8);
1415 __builtin_memcpy(__dst + __bytes, __src + __bytes, 16);
1418 else if (__bytes > 8 && _Max > 8)
1420 __builtin_memcpy(__dst, __src, 8);
1421 if constexpr (_Chunk == 4)
1424 __builtin_memcpy(__dst + __bytes, __src + __bytes, 4);
1426 else if constexpr (_Chunk < 4)
1429 __builtin_memcpy(__dst + __bytes, __src + __bytes, 8);
1432 else if (__bytes > 4 && _Max > 4)
1434 __builtin_memcpy(__dst, __src, 4);
1435 if constexpr (_Chunk == 2)
1438 __builtin_memcpy(__dst + __bytes, __src + __bytes, 2);
1440 else if constexpr (_Chunk == 1)
1443 __builtin_memcpy(__dst + __bytes, __src + __bytes, 4);
1446 else if (__bytes >= 2)
1448 __builtin_memcpy(__dst, __src, 2);
1449 if constexpr (_Chunk == 2)
1452 __builtin_memcpy(__dst + __bytes, __src + __bytes, 2);
1454 else if constexpr (_Chunk == 1)
1457 __builtin_memcpy(__dst + __bytes, __src + __bytes, 1);
1460 else if (__bytes == 1)
1461 __builtin_memcpy(__dst, __src, 1);
1465 template <
typename _Tp,
typename _BinaryOperation>
1466 requires __is_one_of<_BinaryOperation,
1467 plus<>, multiplies<>, bit_and<>, bit_or<>, bit_xor<>>::value
1469 __default_identity_element()
1471 if constexpr (same_as<_BinaryOperation, multiplies<>>)
1473 else if constexpr (same_as<_BinaryOperation, bit_and<>>)
1479_GLIBCXX_END_NAMESPACE_VERSION
1482#pragma GCC diagnostic pop
typename underlying_type< _Tp >::type underlying_type_t
Alias template for underlying_type.
typename make_unsigned< _Tp >::type make_unsigned_t
Alias template for make_unsigned.
auto declval() noexcept -> decltype(__declval< _Tp >(0))
ISO C++ entities toplevel namespace is std.
__make_integer_seq< integer_sequence, _Tp, _Num > make_integer_sequence
Alias template make_integer_sequence.
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.
static constexpr int digits
static constexpr _Tp max() noexcept
static constexpr _Tp lowest() noexcept