diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index e6834b3607a..bc740f8e1ba 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
@@ -2869,6 +2869,17 @@ since C++14 and the implementation is complete.
Library Fundamentals 2 TS
+
+
+
+ P0214R9
+
+
+ Data-Parallel Types
+ Y
+ Parallelism 2 TS
+
+
@@ -3014,6 +3025,211 @@ since C++14 and the implementation is complete.
If !is_regular_file(p), an error is reported.
+ Parallelism 2 TS
+
+
+ 9.3 [parallel.simd.abi]
+ max_fixed_size<T> is 32, except when targetting
+ AVX512BW and sizeof(T) is 1.
+
+
+
+ When targeting 32-bit x86,
+ simd_abi::compatible<T> is an alias for
+ simd_abi::scalar.
+ When targeting 64-bit x86 (including x32) or Aarch64,
+ simd_abi::compatible<T> is an alias for
+ simd_abi::_VecBuiltin<16>,
+ unless T is long double, in which case it is
+ an alias for simd_abi::scalar.
+ When targeting ARM (but not Aarch64) with NEON support,
+ simd_abi::compatible<T> is an alias for
+ simd_abi::_VecBuiltin<16>,
+ unless sizeof(T) > 4, in which case it is
+ an alias for simd_abi::scalar. Additionally,
+ simd_abi::compatible<float> is an alias for
+ simd_abi::scalar unless compiling with
+ -ffast-math.
+
+
+
+ When targeting x86 (both 32-bit and 64-bit),
+ simd_abi::native<T> is an alias for one of
+ simd_abi::scalar,
+ simd_abi::_VecBuiltin<16>,
+ simd_abi::_VecBuiltin<32>, or
+ simd_abi::_VecBltnBtmsk<64>, depending on
+ T and the machine options the compiler was invoked with.
+
+
+
+ When targeting ARM/Aarch64 or POWER,
+ simd_abi::native<T> is an alias for
+ simd_abi::scalar or
+ simd_abi::_VecBuiltin<16>, depending on
+ T and the machine options the compiler was invoked with.
+
+
+
+ For any other targeted machine
+ simd_abi::compatible<T> and
+ simd_abi::native<T> are aliases for
+ simd_abi::scalar. (subject to change)
+
+
+
+ The extended ABI tag types defined in the
+ std::experimental::parallelism_v2::simd_abi namespace are:
+ simd_abi::_VecBuiltin<Bytes>, and
+ simd_abi::_VecBltnBtmsk<Bytes>.
+
+
+
+ simd_abi::deduce<T, N, Abis...>::type,
+ with N > 1 is an alias for an extended ABI tag, if a
+ supported extended ABI tag exists. Otherwise it is an alias for
+ simd_abi::fixed_size<N>. The
+ simd_abi::_VecBltnBtmsk ABI tag is preferred over
+ simd_abi::_VecBuiltin.
+
+
+
+ 9.4 [parallel.simd.traits]
+ memory_alignment<T, U>::value is
+ sizeof(U) * T::size() rounded up to the next power-of-two
+ value.
+
+
+
+ 9.6.1 [parallel.simd.overview]
+ On ARM, simd<T, _VecBuiltin<Bytes>>
+ is supported if __ARM_NEON is defined and
+ sizeof(T) <= 4. Additionally,
+ sizeof(T) == 8 with integral T is supported if
+ __ARM_ARCH >= 8, and double is supported if
+ __aarch64__ is defined.
+
+ On POWER, simd<T, _VecBuiltin<Bytes>>
+ is supported if __ALTIVEC__ is defined and sizeof(T)
+ < 8. Additionally, double is supported if
+ __VSX__ is defined, and any T with
+ sizeof(T) ≤ 8 is supported if __POWER8_VECTOR__
+ is defined.
+
+ On x86, given an extended ABI tag Abi,
+ simd<T, Abi> is supported according to the
+ following table:
+
+ Support for Extended ABI Tags
+
+
+
+
+
+
+
+
+ ABI tag Abi
+ value type T
+ values for Bytes
+ required machine option
+
+
+
+
+
+
+ _VecBuiltin<Bytes>
+
+ float
+ 8, 12, 16
+ "-msse"
+
+
+
+ 20, 24, 28, 32
+ "-mavx"
+
+
+
+ double
+ 16
+ "-msse2"
+
+
+
+ 24, 32
+ "-mavx"
+
+
+
+
+ integral types other than bool
+
+
+ Bytes ≤ 16 and Bytes divisible by
+ sizeof(T)
+
+ "-msse2"
+
+
+
+
+ 16 < Bytes ≤ 32 and Bytes
+ divisible by sizeof(T)
+
+ "-mavx2"
+
+
+
+
+ _VecBuiltin<Bytes> and
+ _VecBltnBtmsk<Bytes>
+
+
+ vectorizable types with sizeof(T) ≥ 4
+
+
+ 32 < Bytes ≤ 64 and Bytes
+ divisible by sizeof(T)
+
+ "-mavx512f"
+
+
+
+
+ vectorizable types with sizeof(T) < 4
+
+ "-mavx512bw"
+
+
+
+
+ _VecBltnBtmsk<Bytes>
+
+
+ vectorizable types with sizeof(T) ≥ 4
+
+
+ Bytes ≤ 32 and Bytes divisible by
+ sizeof(T)
+
+ "-mavx512vl"
+
+
+
+
+ vectorizable types with sizeof(T) < 4
+
+ "-mavx512bw" and "-mavx512vl"
+
+
+
+
+
+
+
+
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 958dfea5a98..3ad24267cfd 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -746,6 +746,7 @@ experimental_headers = \
${experimental_srcdir}/ratio \
${experimental_srcdir}/regex \
${experimental_srcdir}/set \
+ ${experimental_srcdir}/simd \
${experimental_srcdir}/socket \
${experimental_srcdir}/source_location \
${experimental_srcdir}/string \
@@ -765,7 +766,19 @@ experimental_bits_builddir = ./experimental/bits
experimental_bits_headers = \
${experimental_bits_srcdir}/lfts_config.h \
${experimental_bits_srcdir}/net.h \
+ ${experimental_bits_srcdir}/numeric_traits.h \
${experimental_bits_srcdir}/shared_ptr.h \
+ ${experimental_bits_srcdir}/simd.h \
+ ${experimental_bits_srcdir}/simd_builtin.h \
+ ${experimental_bits_srcdir}/simd_converter.h \
+ ${experimental_bits_srcdir}/simd_detail.h \
+ ${experimental_bits_srcdir}/simd_fixed_size.h \
+ ${experimental_bits_srcdir}/simd_math.h \
+ ${experimental_bits_srcdir}/simd_neon.h \
+ ${experimental_bits_srcdir}/simd_ppc.h \
+ ${experimental_bits_srcdir}/simd_scalar.h \
+ ${experimental_bits_srcdir}/simd_x86.h \
+ ${experimental_bits_srcdir}/simd_x86_conversions.h \
${experimental_bits_srcdir}/string_view.tcc \
${experimental_bits_filesystem_headers}
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index b3256a7835e..2692b8352be 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -1096,6 +1096,7 @@ experimental_headers = \
${experimental_srcdir}/ratio \
${experimental_srcdir}/regex \
${experimental_srcdir}/set \
+ ${experimental_srcdir}/simd \
${experimental_srcdir}/socket \
${experimental_srcdir}/source_location \
${experimental_srcdir}/string \
@@ -1115,7 +1116,19 @@ experimental_bits_builddir = ./experimental/bits
experimental_bits_headers = \
${experimental_bits_srcdir}/lfts_config.h \
${experimental_bits_srcdir}/net.h \
+ ${experimental_bits_srcdir}/numeric_traits.h \
${experimental_bits_srcdir}/shared_ptr.h \
+ ${experimental_bits_srcdir}/simd.h \
+ ${experimental_bits_srcdir}/simd_builtin.h \
+ ${experimental_bits_srcdir}/simd_converter.h \
+ ${experimental_bits_srcdir}/simd_detail.h \
+ ${experimental_bits_srcdir}/simd_fixed_size.h \
+ ${experimental_bits_srcdir}/simd_math.h \
+ ${experimental_bits_srcdir}/simd_neon.h \
+ ${experimental_bits_srcdir}/simd_ppc.h \
+ ${experimental_bits_srcdir}/simd_scalar.h \
+ ${experimental_bits_srcdir}/simd_x86.h \
+ ${experimental_bits_srcdir}/simd_x86_conversions.h \
${experimental_bits_srcdir}/string_view.tcc \
${experimental_bits_filesystem_headers}
diff --git a/libstdc++-v3/include/experimental/bits/numeric_traits.h b/libstdc++-v3/include/experimental/bits/numeric_traits.h
new file mode 100644
index 00000000000..1b60874b788
--- /dev/null
+++ b/libstdc++-v3/include/experimental/bits/numeric_traits.h
@@ -0,0 +1,567 @@
+// Definition of numeric_limits replacement traits P1841R1 -*- C++ -*-
+
+// Copyright (C) 2020 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// .
+
+#include
+
+namespace std {
+
+template class _Trait, typename _Tp, typename = void>
+ struct __value_exists_impl : false_type {};
+
+template class _Trait, typename _Tp>
+ struct __value_exists_impl<_Trait, _Tp, void_t::value)>>
+ : true_type {};
+
+template >
+ struct __digits_impl {};
+
+template
+ struct __digits_impl<_Tp, true>
+ {
+ static inline constexpr int value
+ = sizeof(_Tp) * __CHAR_BIT__ - is_signed_v<_Tp>;
+ };
+
+template <>
+ struct __digits_impl
+ { static inline constexpr int value = __FLT_MANT_DIG__; };
+
+template <>
+ struct __digits_impl
+ { static inline constexpr int value = __DBL_MANT_DIG__; };
+
+template <>
+ struct __digits_impl
+ { static inline constexpr int value = __LDBL_MANT_DIG__; };
+
+template >
+ struct __digits10_impl {};
+
+template
+ struct __digits10_impl<_Tp, true>
+ {
+ // The fraction 643/2136 approximates log10(2) to 7 significant digits.
+ static inline constexpr int value = __digits_impl<_Tp>::value * 643L / 2136;
+ };
+
+template <>
+ struct __digits10_impl
+ { static inline constexpr int value = __FLT_DIG__; };
+
+template <>
+ struct __digits10_impl
+ { static inline constexpr int value = __DBL_DIG__; };
+
+template <>
+ struct __digits10_impl
+ { static inline constexpr int value = __LDBL_DIG__; };
+
+template >
+ struct __max_digits10_impl {};
+
+template
+ struct __max_digits10_impl<_Tp, true>
+ {
+ static inline constexpr int value
+ = is_floating_point_v<_Tp> ? 2 + __digits_impl<_Tp>::value * 643L / 2136
+ : __digits10_impl<_Tp>::value + 1;
+ };
+
+template
+ struct __max_exponent_impl {};
+
+template <>
+ struct __max_exponent_impl
+ { static inline constexpr int value = __FLT_MAX_EXP__; };
+
+template <>
+ struct __max_exponent_impl
+ { static inline constexpr int value = __DBL_MAX_EXP__; };
+
+template <>
+ struct __max_exponent_impl
+ { static inline constexpr int value = __LDBL_MAX_EXP__; };
+
+template
+ struct __max_exponent10_impl {};
+
+template <>
+ struct __max_exponent10_impl
+ { static inline constexpr int value = __FLT_MAX_10_EXP__; };
+
+template <>
+ struct __max_exponent10_impl
+ { static inline constexpr int value = __DBL_MAX_10_EXP__; };
+
+template <>
+ struct __max_exponent10_impl
+ { static inline constexpr int value = __LDBL_MAX_10_EXP__; };
+
+template
+ struct __min_exponent_impl {};
+
+template <>
+ struct __min_exponent_impl
+ { static inline constexpr int value = __FLT_MIN_EXP__; };
+
+template <>
+ struct __min_exponent_impl
+ { static inline constexpr int value = __DBL_MIN_EXP__; };
+
+template <>
+ struct __min_exponent_impl
+ { static inline constexpr int value = __LDBL_MIN_EXP__; };
+
+template
+ struct __min_exponent10_impl {};
+
+template <>
+ struct __min_exponent10_impl
+ { static inline constexpr int value = __FLT_MIN_10_EXP__; };
+
+template <>
+ struct __min_exponent10_impl
+ { static inline constexpr int value = __DBL_MIN_10_EXP__; };
+
+template <>
+ struct __min_exponent10_impl
+ { static inline constexpr int value = __LDBL_MIN_10_EXP__; };
+
+template >
+ struct __radix_impl {};
+
+template
+ struct __radix_impl<_Tp, true>
+ {
+ static inline constexpr int value
+ = is_floating_point_v<_Tp> ? __FLT_RADIX__ : 2;
+ };
+
+// [num.traits.util], numeric utility traits
+template class _Trait, typename _Tp>
+ struct __value_exists : __value_exists_impl<_Trait, _Tp> {};
+
+template class _Trait, typename _Tp>
+ inline constexpr bool __value_exists_v = __value_exists<_Trait, _Tp>::value;
+
+template class _Trait, typename _Tp, typename _Up = _Tp>
+ inline constexpr _Up
+ __value_or(_Up __def = _Up()) noexcept
+ {
+ if constexpr (__value_exists_v<_Trait, _Tp>)
+ return static_cast<_Up>(_Trait<_Tp>::value);
+ else
+ return __def;
+ }
+
+template >
+ struct __norm_min_impl {};
+
+template
+ struct __norm_min_impl<_Tp, true>
+ { static inline constexpr _Tp value = 1; };
+
+template <>
+ struct __norm_min_impl
+ { static inline constexpr float value = __FLT_MIN__; };
+
+template <>
+ struct __norm_min_impl
+ { static inline constexpr double value = __DBL_MIN__; };
+
+template <>
+ struct __norm_min_impl
+ { static inline constexpr long double value = __LDBL_MIN__; };
+
+template
+ struct __denorm_min_impl : __norm_min_impl<_Tp> {};
+
+#if __FLT_HAS_DENORM__
+template <>
+ struct __denorm_min_impl
+ { static inline constexpr float value = __FLT_DENORM_MIN__; };
+#endif
+
+#if __DBL_HAS_DENORM__
+template <>
+ struct __denorm_min_impl
+ { static inline constexpr double value = __DBL_DENORM_MIN__; };
+#endif
+
+#if __LDBL_HAS_DENORM__
+template <>
+ struct __denorm_min_impl
+ { static inline constexpr long double value = __LDBL_DENORM_MIN__; };
+#endif
+
+template
+ struct __epsilon_impl {};
+
+template <>
+ struct __epsilon_impl
+ { static inline constexpr float value = __FLT_EPSILON__; };
+
+template <>
+ struct __epsilon_impl
+ { static inline constexpr double value = __DBL_EPSILON__; };
+
+template <>
+ struct __epsilon_impl
+ { static inline constexpr long double value = __LDBL_EPSILON__; };
+
+template >
+ struct __finite_min_impl {};
+
+template
+ struct __finite_min_impl<_Tp, true>
+ {
+ static inline constexpr _Tp value
+ = is_unsigned_v<_Tp> ? _Tp()
+ : -2 * (_Tp(1) << __digits_impl<_Tp>::value - 1);
+ };
+
+template <>
+ struct __finite_min_impl
+ { static inline constexpr float value = -__FLT_MAX__; };
+
+template <>
+ struct __finite_min_impl
+ { static inline constexpr double value = -__DBL_MAX__; };
+
+template <>
+ struct __finite_min_impl
+ { static inline constexpr long double value = -__LDBL_MAX__; };
+
+template >
+ struct __finite_max_impl {};
+
+template
+ struct __finite_max_impl<_Tp, true>
+ { static inline constexpr _Tp value = ~__finite_min_impl<_Tp>::value; };
+
+template <>
+ struct __finite_max_impl
+ { static inline constexpr float value = __FLT_MAX__; };
+
+template <>
+ struct __finite_max_impl
+ { static inline constexpr double value = __DBL_MAX__; };
+
+template <>
+ struct __finite_max_impl
+ { static inline constexpr long double value = __LDBL_MAX__; };
+
+template
+ struct __infinity_impl {};
+
+#if __FLT_HAS_INFINITY__
+template <>
+ struct __infinity_impl
+ { static inline constexpr float value = __builtin_inff(); };
+#endif
+
+#if __DBL_HAS_INFINITY__
+template <>
+ struct __infinity_impl
+ { static inline constexpr double value = __builtin_inf(); };
+#endif
+
+#if __LDBL_HAS_INFINITY__
+template <>
+ struct __infinity_impl
+ { static inline constexpr long double value = __builtin_infl(); };
+#endif
+
+template
+ struct __quiet_NaN_impl {};
+
+#if __FLT_HAS_QUIET_NAN__
+template <>
+ struct __quiet_NaN_impl
+ { static inline constexpr float value = __builtin_nanf(""); };
+#endif
+
+#if __DBL_HAS_QUIET_NAN__
+template <>
+ struct __quiet_NaN_impl
+ { static inline constexpr double value = __builtin_nan(""); };
+#endif
+
+#if __LDBL_HAS_QUIET_NAN__
+template <>
+ struct __quiet_NaN_impl
+ { static inline constexpr long double value = __builtin_nanl(""); };
+#endif
+
+template >
+ struct __reciprocal_overflow_threshold_impl {};
+
+template
+ struct __reciprocal_overflow_threshold_impl<_Tp, true>
+ {
+ // This typically yields a subnormal value. Is this incorrect for
+ // flush-to-zero configurations?
+ static constexpr _Tp _S_search(_Tp __ok, _Tp __overflows)
+ {
+ const _Tp __mid = (__ok + __overflows) / 2;
+ // 1/__mid without -ffast-math is not a constant expression if it
+ // overflows. Therefore divide 1 by the radix before division.
+ // Consequently finite_max (the threshold) must be scaled by the
+ // same value.
+ if (__mid == __ok || __mid == __overflows)
+ return __ok;
+ else if (_Tp(1) / (__radix_impl<_Tp>::value * __mid)
+ <= __finite_max_impl<_Tp>::value / __radix_impl<_Tp>::value)
+ return _S_search(__mid, __overflows);
+ else
+ return _S_search(__ok, __mid);
+ }
+
+ static inline constexpr _Tp value
+ = _S_search(_Tp(1.01) / __finite_max_impl<_Tp>::value,
+ _Tp(0.99) / __finite_max_impl<_Tp>::value);
+ };
+
+template >
+ struct __round_error_impl {};
+
+template
+ struct __round_error_impl<_Tp, true>
+ { static inline constexpr _Tp value = 0.5; };
+
+template
+ struct __signaling_NaN_impl {};
+
+#if __FLT_HAS_QUIET_NAN__
+template <>
+ struct __signaling_NaN_impl
+ { static inline constexpr float value = __builtin_nansf(""); };
+#endif
+
+#if __DBL_HAS_QUIET_NAN__
+template <>
+ struct __signaling_NaN_impl
+ { static inline constexpr double value = __builtin_nans(""); };
+#endif
+
+#if __LDBL_HAS_QUIET_NAN__
+template <>
+ struct __signaling_NaN_impl
+ { static inline constexpr long double value = __builtin_nansl(""); };
+#endif
+
+// [num.traits.val], numeric distinguished value traits
+template
+ struct __denorm_min : __denorm_min_impl> {};
+
+template
+ struct __epsilon : __epsilon_impl> {};
+
+template
+ struct __finite_max : __finite_max_impl> {};
+
+template
+ struct __finite_min : __finite_min_impl> {};
+
+template
+ struct __infinity : __infinity_impl> {};
+
+template
+ struct __norm_min : __norm_min_impl> {};
+
+template
+ struct __quiet_NaN : __quiet_NaN_impl> {};
+
+template
+ struct __reciprocal_overflow_threshold
+ : __reciprocal_overflow_threshold_impl> {};
+
+template
+ struct __round_error : __round_error_impl> {};
+
+template
+ struct __signaling_NaN : __signaling_NaN_impl> {};
+
+template
+ inline constexpr auto __denorm_min_v = __denorm_min<_Tp>::value;
+
+template
+ inline constexpr auto __epsilon_v = __epsilon<_Tp>::value;
+
+template
+ inline constexpr auto __finite_max_v = __finite_max<_Tp>::value;
+
+template
+ inline constexpr auto __finite_min_v = __finite_min<_Tp>::value;
+
+template
+ inline constexpr auto __infinity_v = __infinity<_Tp>::value;
+
+template
+ inline constexpr auto __norm_min_v = __norm_min<_Tp>::value;
+
+template
+ inline constexpr auto __quiet_NaN_v = __quiet_NaN<_Tp>::value;
+
+template
+ inline constexpr auto __reciprocal_overflow_threshold_v
+ = __reciprocal_overflow_threshold<_Tp>::value;
+
+template
+ inline constexpr auto __round_error_v = __round_error<_Tp>::value;
+
+template
+ inline constexpr auto __signaling_NaN_v = __signaling_NaN<_Tp>::value;
+
+// [num.traits.char], numeric characteristics traits
+template
+ struct __digits : __digits_impl> {};
+
+template
+ struct __digits10 : __digits10_impl> {};
+
+template
+ struct __max_digits10 : __max_digits10_impl> {};
+
+template
+ struct __max_exponent : __max_exponent_impl> {};
+
+template
+ struct __max_exponent10 : __max_exponent10_impl> {};
+
+template
+ struct __min_exponent : __min_exponent_impl> {};
+
+template
+ struct __min_exponent10 : __min_exponent10_impl> {};
+
+template
+ struct __radix : __radix_impl> {};
+
+template
+ inline constexpr auto __digits_v = __digits<_Tp>::value;
+
+template
+ inline constexpr auto __digits10_v = __digits10<_Tp>::value;
+
+template
+ inline constexpr auto __max_digits10_v = __max_digits10<_Tp>::value;
+
+template
+ inline constexpr auto __max_exponent_v = __max_exponent<_Tp>::value;
+
+template
+ inline constexpr auto __max_exponent10_v = __max_exponent10<_Tp>::value;
+
+template
+ inline constexpr auto __min_exponent_v = __min_exponent<_Tp>::value;
+
+template
+ inline constexpr auto __min_exponent10_v = __min_exponent10<_Tp>::value;
+
+template
+ inline constexpr auto __radix_v = __radix<_Tp>::value;
+
+// mkretz's extensions
+// TODO: does GCC tell me? __GCC_IEC_559 >= 2 is not the right answer
+template
+ struct __has_iec559_storage_format : true_type {};
+
+template
+ inline constexpr bool __has_iec559_storage_format_v
+ = __has_iec559_storage_format<_Tp>::value;
+
+/* To propose:
+ If __has_iec559_behavior<__quiet_NaN, T> is true the following holds:
+ - nan == nan is false
+ - isnan(nan) is true
+ - isnan(nan + x) is true
+ - isnan(inf/inf) is true
+ - isnan(0/0) is true
+ - isunordered(nan, x) is true
+
+ If __has_iec559_behavior<__infinity, T> is true the following holds (x is
+ neither nan nor inf):
+ - isinf(inf) is true
+ - isinf(inf + x) is true
+ - isinf(1/0) is true
+ */
+template class _Trait, typename _Tp>
+ struct __has_iec559_behavior : false_type {};
+
+template class _Trait, typename _Tp>
+ inline constexpr bool __has_iec559_behavior_v
+ = __has_iec559_behavior<_Trait, _Tp>::value;
+
+#if !__FINITE_MATH_ONLY__
+#if __FLT_HAS_QUIET_NAN__
+template <>
+ struct __has_iec559_behavior<__quiet_NaN, float> : true_type {};
+#endif
+
+#if __DBL_HAS_QUIET_NAN__
+template <>
+ struct __has_iec559_behavior<__quiet_NaN, double> : true_type {};
+#endif
+
+#if __LDBL_HAS_QUIET_NAN__
+template <>
+ struct __has_iec559_behavior<__quiet_NaN, long double> : true_type {};
+#endif
+
+#if __FLT_HAS_INFINITY__
+template <>
+ struct __has_iec559_behavior<__infinity, float> : true_type {};
+#endif
+
+#if __DBL_HAS_INFINITY__
+template <>
+ struct __has_iec559_behavior<__infinity, double> : true_type {};
+#endif
+
+#if __LDBL_HAS_INFINITY__
+template <>
+ struct __has_iec559_behavior<__infinity, long double> : true_type {};
+#endif
+
+#ifdef __SUPPORT_SNAN__
+#if __FLT_HAS_QUIET_NAN__
+template <>
+ struct __has_iec559_behavior<__signaling_NaN, float> : true_type {};
+#endif
+
+#if __DBL_HAS_QUIET_NAN__
+template <>
+ struct __has_iec559_behavior<__signaling_NaN, double> : true_type {};
+#endif
+
+#if __LDBL_HAS_QUIET_NAN__
+template <>
+ struct __has_iec559_behavior<__signaling_NaN, long double> : true_type {};
+#endif
+
+#endif
+#endif // __FINITE_MATH_ONLY__
+
+} // namespace std
diff --git a/libstdc++-v3/include/experimental/bits/simd.h b/libstdc++-v3/include/experimental/bits/simd.h
new file mode 100644
index 00000000000..00eec50d64f
--- /dev/null
+++ b/libstdc++-v3/include/experimental/bits/simd.h
@@ -0,0 +1,5051 @@
+// Definition of the public simd interfaces -*- C++ -*-
+
+// Copyright (C) 2020 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// .
+
+#ifndef _GLIBCXX_EXPERIMENTAL_SIMD_H
+#define _GLIBCXX_EXPERIMENTAL_SIMD_H
+
+#if __cplusplus >= 201703L
+
+#include "simd_detail.h"
+#include "numeric_traits.h"
+#include
+#include
+#ifdef _GLIBCXX_DEBUG_UB
+#include // for stderr
+#endif
+#include
+#include
+#include
+#include
+
+#if _GLIBCXX_SIMD_X86INTRIN
+#include
+#elif _GLIBCXX_SIMD_HAVE_NEON
+#include
+#endif
+
+/* There are several closely related types, with the following naming
+ * convention:
+ * _Tp: vectorizable (arithmetic) type (or any type)
+ * _TV: __vector_type_t<_Tp, _Np>
+ * _TW: _SimdWrapper<_Tp, _Np>
+ * _TI: __intrinsic_type_t<_Tp, _Np>
+ * _TVT: _VectorTraits<_TV> or _VectorTraits<_TW>
+ * If one additional type is needed use _U instead of _T.
+ * Otherwise use _T\d, _TV\d, _TW\d, TI\d, _TVT\d.
+ *
+ * More naming conventions:
+ * _Ap or _Abi: An ABI tag from the simd_abi namespace
+ * _Ip: often used for integer types with sizeof(_Ip) == sizeof(_Tp),
+ * _IV, _IW as for _TV, _TW
+ * _Np: number of elements (not bytes)
+ * _Bytes: number of bytes
+ *
+ * Variable names:
+ * __k: mask object (vector- or bitmask)
+ */
+_GLIBCXX_SIMD_BEGIN_NAMESPACE
+
+#if !_GLIBCXX_SIMD_X86INTRIN
+using __m128 [[__gnu__::__vector_size__(16)]] = float;
+using __m128d [[__gnu__::__vector_size__(16)]] = double;
+using __m128i [[__gnu__::__vector_size__(16)]] = long long;
+using __m256 [[__gnu__::__vector_size__(32)]] = float;
+using __m256d [[__gnu__::__vector_size__(32)]] = double;
+using __m256i [[__gnu__::__vector_size__(32)]] = long long;
+using __m512 [[__gnu__::__vector_size__(64)]] = float;
+using __m512d [[__gnu__::__vector_size__(64)]] = double;
+using __m512i [[__gnu__::__vector_size__(64)]] = long long;
+#endif
+
+namespace simd_abi {
+// simd_abi forward declarations {{{
+// implementation details:
+struct _Scalar;
+
+template
+ struct _Fixed;
+
+// There are two major ABIs that appear on different architectures.
+// Both have non-boolean values packed into an N Byte register
+// -> #elements = N / sizeof(T)
+// Masks differ:
+// 1. Use value vector registers for masks (all 0 or all 1)
+// 2. Use bitmasks (mask registers) with one bit per value in the corresponding
+// value vector
+//
+// Both can be partially used, masking off the rest when doing horizontal
+// operations or operations that can trap (e.g. FP_INVALID or integer division
+// by 0). This is encoded as the number of used bytes.
+template
+ struct _VecBuiltin;
+
+template
+ struct _VecBltnBtmsk;
+
+template
+ using _VecN = _VecBuiltin;
+
+template
+ using _Sse = _VecBuiltin<_UsedBytes>;
+
+template
+ using _Avx = _VecBuiltin<_UsedBytes>;
+
+template
+ using _Avx512 = _VecBltnBtmsk<_UsedBytes>;
+
+template
+ using _Neon = _VecBuiltin<_UsedBytes>;
+
+// implementation-defined:
+using __sse = _Sse<>;
+using __avx = _Avx<>;
+using __avx512 = _Avx512<>;
+using __neon = _Neon<>;
+using __neon128 = _Neon<16>;
+using __neon64 = _Neon<8>;
+
+// standard:
+template
+ struct deduce;
+
+template
+ using fixed_size = _Fixed<_Np>;
+
+using scalar = _Scalar;
+
+// }}}
+} // namespace simd_abi
+// forward declarations is_simd(_mask), simd(_mask), simd_size {{{
+template
+ struct is_simd;
+
+template
+ struct is_simd_mask;
+
+template
+ class simd;
+
+template
+ class simd_mask;
+
+template
+ struct simd_size;
+
+// }}}
+// load/store flags {{{
+struct element_aligned_tag
+{
+ template
+ static constexpr size_t _S_alignment = alignof(_Up);
+
+ template
+ _GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
+ _S_apply(_Up* __ptr)
+ { return __ptr; }
+};
+
+struct vector_aligned_tag
+{
+ template
+ static constexpr size_t _S_alignment
+ = std::__bit_ceil(sizeof(_Up) * _Tp::size());
+
+ template
+ _GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
+ _S_apply(_Up* __ptr)
+ {
+ return static_cast<_Up*>(
+ __builtin_assume_aligned(__ptr, _S_alignment<_Tp, _Up>));
+ }
+};
+
+template struct overaligned_tag
+{
+ template
+ static constexpr size_t _S_alignment = _Np;
+
+ template
+ _GLIBCXX_SIMD_INTRINSIC static constexpr _Up*
+ _S_apply(_Up* __ptr)
+ { return static_cast<_Up*>(__builtin_assume_aligned(__ptr, _Np)); }
+};
+
+inline constexpr element_aligned_tag element_aligned = {};
+
+inline constexpr vector_aligned_tag vector_aligned = {};
+
+template
+ inline constexpr overaligned_tag<_Np> overaligned = {};
+
+// }}}
+template
+ using _SizeConstant = integral_constant;
+
+// unrolled/pack execution helpers
+// __execute_n_times{{{
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr void
+ __execute_on_index_sequence(_Fp&& __f, index_sequence<_I...>)
+ { ((void)__f(_SizeConstant<_I>()), ...); }
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr void
+ __execute_on_index_sequence(_Fp&&, index_sequence<>)
+ { }
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr void
+ __execute_n_times(_Fp&& __f)
+ {
+ __execute_on_index_sequence(static_cast<_Fp&&>(__f),
+ make_index_sequence<_Np>{});
+ }
+
+// }}}
+// __generate_from_n_evaluations{{{
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr _R
+ __execute_on_index_sequence_with_return(_Fp&& __f, index_sequence<_I...>)
+ { return _R{__f(_SizeConstant<_I>())...}; }
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr _R
+ __generate_from_n_evaluations(_Fp&& __f)
+ {
+ return __execute_on_index_sequence_with_return<_R>(
+ static_cast<_Fp&&>(__f), make_index_sequence<_Np>{});
+ }
+
+// }}}
+// __call_with_n_evaluations{{{
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto
+ __call_with_n_evaluations(index_sequence<_I...>, _F0&& __f0, _FArgs&& __fargs)
+ { return __f0(__fargs(_SizeConstant<_I>())...); }
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto
+ __call_with_n_evaluations(_F0&& __f0, _FArgs&& __fargs)
+ {
+ return __call_with_n_evaluations(make_index_sequence<_Np>{},
+ static_cast<_F0&&>(__f0),
+ static_cast<_FArgs&&>(__fargs));
+ }
+
+// }}}
+// __call_with_subscripts{{{
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto
+ __call_with_subscripts(_Tp&& __x, index_sequence<_It...>, _Fp&& __fun)
+ { return __fun(__x[_First + _It]...); }
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto
+ __call_with_subscripts(_Tp&& __x, _Fp&& __fun)
+ {
+ return __call_with_subscripts<_First>(static_cast<_Tp&&>(__x),
+ make_index_sequence<_Np>(),
+ static_cast<_Fp&&>(__fun));
+ }
+
+// }}}
+
+// vvv ---- type traits ---- vvv
+// integer type aliases{{{
+using _UChar = unsigned char;
+using _SChar = signed char;
+using _UShort = unsigned short;
+using _UInt = unsigned int;
+using _ULong = unsigned long;
+using _ULLong = unsigned long long;
+using _LLong = long long;
+
+//}}}
+// __first_of_pack{{{
+template
+ struct __first_of_pack
+ { using type = _T0; };
+
+template
+ using __first_of_pack_t = typename __first_of_pack<_Ts...>::type;
+
+//}}}
+// __value_type_or_identity_t {{{
+template
+ typename _Tp::value_type
+ __value_type_or_identity_impl(int);
+
+template
+ _Tp
+ __value_type_or_identity_impl(float);
+
+template
+ using __value_type_or_identity_t
+ = decltype(__value_type_or_identity_impl<_Tp>(int()));
+
+// }}}
+// __is_vectorizable {{{
+template
+ struct __is_vectorizable : public is_arithmetic<_Tp> {};
+
+template <>
+ struct __is_vectorizable : public false_type {};
+
+template
+ inline constexpr bool __is_vectorizable_v = __is_vectorizable<_Tp>::value;
+
+// Deduces to a vectorizable type
+template >>
+ using _Vectorizable = _Tp;
+
+// }}}
+// _LoadStorePtr / __is_possible_loadstore_conversion {{{
+template
+ struct __is_possible_loadstore_conversion
+ : conjunction<__is_vectorizable<_Ptr>, __is_vectorizable<_ValueType>> {};
+
+template <>
+ struct __is_possible_loadstore_conversion : true_type {};
+
+// Deduces to a type allowed for load/store with the given value type.
+template ::value>>
+ using _LoadStorePtr = _Ptr;
+
+// }}}
+// __is_bitmask{{{
+template >
+ struct __is_bitmask : false_type {};
+
+template
+ inline constexpr bool __is_bitmask_v = __is_bitmask<_Tp>::value;
+
+// the __mmaskXX case:
+template
+ struct __is_bitmask<_Tp,
+ void_t() = declval<_Tp>() & 1u)>>
+ : true_type {};
+
+// }}}
+// __int_for_sizeof{{{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+template
+ constexpr auto
+ __int_for_sizeof()
+ {
+ if constexpr (_Bytes == sizeof(int))
+ return int();
+ #ifdef __clang__
+ else if constexpr (_Bytes == sizeof(char))
+ return char();
+ #else
+ else if constexpr (_Bytes == sizeof(_SChar))
+ return _SChar();
+ #endif
+ else if constexpr (_Bytes == sizeof(short))
+ return short();
+ #ifndef __clang__
+ else if constexpr (_Bytes == sizeof(long))
+ return long();
+ #endif
+ else if constexpr (_Bytes == sizeof(_LLong))
+ return _LLong();
+ #ifdef __SIZEOF_INT128__
+ else if constexpr (_Bytes == sizeof(__int128))
+ return __int128();
+ #endif // __SIZEOF_INT128__
+ else if constexpr (_Bytes % sizeof(int) == 0)
+ {
+ constexpr size_t _Np = _Bytes / sizeof(int);
+ struct _Ip
+ {
+ int _M_data[_Np];
+
+ _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
+ operator&(_Ip __rhs) const
+ {
+ return __generate_from_n_evaluations<_Np, _Ip>(
+ [&](auto __i) { return __rhs._M_data[__i] & _M_data[__i]; });
+ }
+
+ _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
+ operator|(_Ip __rhs) const
+ {
+ return __generate_from_n_evaluations<_Np, _Ip>(
+ [&](auto __i) { return __rhs._M_data[__i] | _M_data[__i]; });
+ }
+
+ _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
+ operator^(_Ip __rhs) const
+ {
+ return __generate_from_n_evaluations<_Np, _Ip>(
+ [&](auto __i) { return __rhs._M_data[__i] ^ _M_data[__i]; });
+ }
+
+ _GLIBCXX_SIMD_INTRINSIC constexpr _Ip
+ operator~() const
+ {
+ return __generate_from_n_evaluations<_Np, _Ip>(
+ [&](auto __i) { return ~_M_data[__i]; });
+ }
+ };
+ return _Ip{};
+ }
+ else
+ static_assert(_Bytes != _Bytes, "this should be unreachable");
+ }
+#pragma GCC diagnostic pop
+
+template
+ using __int_for_sizeof_t = decltype(__int_for_sizeof());
+
+template
+ using __int_with_sizeof_t = decltype(__int_for_sizeof<_Np>());
+
+// }}}
+// __is_fixed_size_abi{{{
+template
+ struct __is_fixed_size_abi : false_type {};
+
+template
+ struct __is_fixed_size_abi> : true_type {};
+
+template
+ inline constexpr bool __is_fixed_size_abi_v = __is_fixed_size_abi<_Tp>::value;
+
+// }}}
+// constexpr feature detection{{{
+constexpr inline bool __have_mmx = _GLIBCXX_SIMD_HAVE_MMX;
+constexpr inline bool __have_sse = _GLIBCXX_SIMD_HAVE_SSE;
+constexpr inline bool __have_sse2 = _GLIBCXX_SIMD_HAVE_SSE2;
+constexpr inline bool __have_sse3 = _GLIBCXX_SIMD_HAVE_SSE3;
+constexpr inline bool __have_ssse3 = _GLIBCXX_SIMD_HAVE_SSSE3;
+constexpr inline bool __have_sse4_1 = _GLIBCXX_SIMD_HAVE_SSE4_1;
+constexpr inline bool __have_sse4_2 = _GLIBCXX_SIMD_HAVE_SSE4_2;
+constexpr inline bool __have_xop = _GLIBCXX_SIMD_HAVE_XOP;
+constexpr inline bool __have_avx = _GLIBCXX_SIMD_HAVE_AVX;
+constexpr inline bool __have_avx2 = _GLIBCXX_SIMD_HAVE_AVX2;
+constexpr inline bool __have_bmi = _GLIBCXX_SIMD_HAVE_BMI1;
+constexpr inline bool __have_bmi2 = _GLIBCXX_SIMD_HAVE_BMI2;
+constexpr inline bool __have_lzcnt = _GLIBCXX_SIMD_HAVE_LZCNT;
+constexpr inline bool __have_sse4a = _GLIBCXX_SIMD_HAVE_SSE4A;
+constexpr inline bool __have_fma = _GLIBCXX_SIMD_HAVE_FMA;
+constexpr inline bool __have_fma4 = _GLIBCXX_SIMD_HAVE_FMA4;
+constexpr inline bool __have_f16c = _GLIBCXX_SIMD_HAVE_F16C;
+constexpr inline bool __have_popcnt = _GLIBCXX_SIMD_HAVE_POPCNT;
+constexpr inline bool __have_avx512f = _GLIBCXX_SIMD_HAVE_AVX512F;
+constexpr inline bool __have_avx512dq = _GLIBCXX_SIMD_HAVE_AVX512DQ;
+constexpr inline bool __have_avx512vl = _GLIBCXX_SIMD_HAVE_AVX512VL;
+constexpr inline bool __have_avx512bw = _GLIBCXX_SIMD_HAVE_AVX512BW;
+constexpr inline bool __have_avx512dq_vl = __have_avx512dq && __have_avx512vl;
+constexpr inline bool __have_avx512bw_vl = __have_avx512bw && __have_avx512vl;
+
+constexpr inline bool __have_neon = _GLIBCXX_SIMD_HAVE_NEON;
+constexpr inline bool __have_neon_a32 = _GLIBCXX_SIMD_HAVE_NEON_A32;
+constexpr inline bool __have_neon_a64 = _GLIBCXX_SIMD_HAVE_NEON_A64;
+constexpr inline bool __support_neon_float =
+#if defined __GCC_IEC_559
+ __GCC_IEC_559 == 0;
+#elif defined __FAST_MATH__
+ true;
+#else
+ false;
+#endif
+
+#ifdef __POWER9_VECTOR__
+constexpr inline bool __have_power9vec = true;
+#else
+constexpr inline bool __have_power9vec = false;
+#endif
+#if defined __POWER8_VECTOR__
+constexpr inline bool __have_power8vec = true;
+#else
+constexpr inline bool __have_power8vec = __have_power9vec;
+#endif
+#if defined __VSX__
+constexpr inline bool __have_power_vsx = true;
+#else
+constexpr inline bool __have_power_vsx = __have_power8vec;
+#endif
+#if defined __ALTIVEC__
+constexpr inline bool __have_power_vmx = true;
+#else
+constexpr inline bool __have_power_vmx = __have_power_vsx;
+#endif
+
+// }}}
+// __is_scalar_abi {{{
+template
+ constexpr bool
+ __is_scalar_abi()
+ { return is_same_v; }
+
+// }}}
+// __abi_bytes_v {{{
+template class _Abi, int _Bytes>
+ constexpr int
+ __abi_bytes_impl(_Abi<_Bytes>*)
+ { return _Bytes; }
+
+template
+ constexpr int
+ __abi_bytes_impl(_Tp*)
+ { return -1; }
+
+template
+ inline constexpr int __abi_bytes_v
+ = __abi_bytes_impl(static_cast<_Abi*>(nullptr));
+
+// }}}
+// __is_builtin_bitmask_abi {{{
+template
+ constexpr bool
+ __is_builtin_bitmask_abi()
+ { return is_same_v>, _Abi>; }
+
+// }}}
+// __is_sse_abi {{{
+template
+ constexpr bool
+ __is_sse_abi()
+ {
+ constexpr auto _Bytes = __abi_bytes_v<_Abi>;
+ return _Bytes <= 16 && is_same_v, _Abi>;
+ }
+
+// }}}
+// __is_avx_abi {{{
+template
+ constexpr bool
+ __is_avx_abi()
+ {
+ constexpr auto _Bytes = __abi_bytes_v<_Abi>;
+ return _Bytes > 16 && _Bytes <= 32
+ && is_same_v, _Abi>;
+ }
+
+// }}}
+// __is_avx512_abi {{{
+template
+ constexpr bool
+ __is_avx512_abi()
+ {
+ constexpr auto _Bytes = __abi_bytes_v<_Abi>;
+ return _Bytes <= 64 && is_same_v, _Abi>;
+ }
+
+// }}}
+// __is_neon_abi {{{
+template
+ constexpr bool
+ __is_neon_abi()
+ {
+ constexpr auto _Bytes = __abi_bytes_v<_Abi>;
+ return _Bytes <= 16 && is_same_v, _Abi>;
+ }
+
+// }}}
+// __make_dependent_t {{{
+template
+ struct __make_dependent
+ { using type = _Up; };
+
+template
+ using __make_dependent_t = typename __make_dependent<_Tp, _Up>::type;
+
+// }}}
+// ^^^ ---- type traits ---- ^^^
+
+// __invoke_ub{{{
+template
+ [[noreturn]] _GLIBCXX_SIMD_ALWAYS_INLINE void
+ __invoke_ub([[maybe_unused]] const char* __msg,
+ [[maybe_unused]] const _Args&... __args)
+ {
+#ifdef _GLIBCXX_DEBUG_UB
+ __builtin_fprintf(stderr, __msg, __args...);
+ __builtin_trap();
+#else
+ __builtin_unreachable();
+#endif
+ }
+
+// }}}
+// __assert_unreachable{{{
+template
+ struct __assert_unreachable
+ { static_assert(!is_same_v<_Tp, _Tp>, "this should be unreachable"); };
+
+// }}}
+// __size_or_zero_v {{{
+template ::value>
+ constexpr size_t
+ __size_or_zero_dispatch(int)
+ { return _Np; }
+
+template
+ constexpr size_t
+ __size_or_zero_dispatch(float)
+ { return 0; }
+
+template
+ inline constexpr size_t __size_or_zero_v
+ = __size_or_zero_dispatch<_Tp, _Ap>(0);
+
+// }}}
+// __div_roundup {{{
+inline constexpr size_t
+__div_roundup(size_t __a, size_t __b)
+{ return (__a + __b - 1) / __b; }
+
+// }}}
+// _ExactBool{{{
+class _ExactBool
+{
+ const bool _M_data;
+
+public:
+ _GLIBCXX_SIMD_INTRINSIC constexpr _ExactBool(bool __b) : _M_data(__b) {}
+
+ _ExactBool(int) = delete;
+
+ _GLIBCXX_SIMD_INTRINSIC constexpr operator bool() const { return _M_data; }
+};
+
+// }}}
+// __may_alias{{{
+/**@internal
+ * Helper __may_alias<_Tp> that turns _Tp into the type to be used for an
+ * aliasing pointer. This adds the __may_alias attribute to _Tp (with compilers
+ * that support it).
+ */
+template
+ using __may_alias [[__gnu__::__may_alias__]] = _Tp;
+
+// }}}
+// _UnsupportedBase {{{
+// simd and simd_mask base for unsupported <_Tp, _Abi>
+struct _UnsupportedBase
+{
+ _UnsupportedBase() = delete;
+ _UnsupportedBase(const _UnsupportedBase&) = delete;
+ _UnsupportedBase& operator=(const _UnsupportedBase&) = delete;
+ ~_UnsupportedBase() = delete;
+};
+
+// }}}
+// _InvalidTraits {{{
+/**
+ * @internal
+ * Defines the implementation of __a given <_Tp, _Abi>.
+ *
+ * Implementations must ensure that only valid <_Tp, _Abi> instantiations are
+ * possible. Static assertions in the type definition do not suffice. It is
+ * important that SFINAE works.
+ */
+struct _InvalidTraits
+{
+ using _IsValid = false_type;
+ using _SimdBase = _UnsupportedBase;
+ using _MaskBase = _UnsupportedBase;
+
+ static constexpr size_t _S_full_size = 0;
+ static constexpr bool _S_is_partial = false;
+
+ static constexpr size_t _S_simd_align = 1;
+ struct _SimdImpl;
+ struct _SimdMember {};
+ struct _SimdCastType;
+
+ static constexpr size_t _S_mask_align = 1;
+ struct _MaskImpl;
+ struct _MaskMember {};
+ struct _MaskCastType;
+};
+
+// }}}
+// _SimdTraits {{{
+template >
+ struct _SimdTraits : _InvalidTraits {};
+
+// }}}
+// __private_init, __bitset_init{{{
+/**
+ * @internal
+ * Tag used for private init constructor of simd and simd_mask
+ */
+inline constexpr struct _PrivateInit {} __private_init = {};
+
+inline constexpr struct _BitsetInit {} __bitset_init = {};
+
+// }}}
+// __is_narrowing_conversion<_From, _To>{{{
+template ,
+ bool = is_arithmetic_v<_To>>
+ struct __is_narrowing_conversion;
+
+// ignore "signed/unsigned mismatch" in the following trait.
+// The implicit conversions will do the right thing here.
+template
+ struct __is_narrowing_conversion<_From, _To, true, true>
+ : public __bool_constant<(
+ __digits_v<_From> > __digits_v<_To>
+ || __finite_max_v<_From> > __finite_max_v<_To>
+ || __finite_min_v<_From> < __finite_min_v<_To>
+ || (is_signed_v<_From> && is_unsigned_v<_To>))> {};
+
+template
+ struct __is_narrowing_conversion<_Tp, bool, true, true>
+ : public true_type {};
+
+template <>
+ struct __is_narrowing_conversion
+ : public false_type {};
+
+template
+ struct __is_narrowing_conversion<_Tp, _Tp, true, true>
+ : public false_type {};
+
+template
+ struct __is_narrowing_conversion<_From, _To, false, true>
+ : public negation> {};
+
+// }}}
+// __converts_to_higher_integer_rank{{{
+template
+ struct __converts_to_higher_integer_rank : public true_type {};
+
+// this may fail for char -> short if sizeof(char) == sizeof(short)
+template
+ struct __converts_to_higher_integer_rank<_From, _To, false>
+ : public is_same() + declval<_To>()), _To> {};
+
+// }}}
+// __data(simd/simd_mask) {{{
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr const auto&
+ __data(const simd<_Tp, _Ap>& __x);
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto&
+ __data(simd<_Tp, _Ap>& __x);
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr const auto&
+ __data(const simd_mask<_Tp, _Ap>& __x);
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto&
+ __data(simd_mask<_Tp, _Ap>& __x);
+
+// }}}
+// _SimdConverter {{{
+template
+ struct _SimdConverter;
+
+template
+ struct _SimdConverter<_Tp, _Ap, _Tp, _Ap, void>
+ {
+ template
+ _GLIBCXX_SIMD_INTRINSIC const _Up&
+ operator()(const _Up& __x)
+ { return __x; }
+ };
+
+// }}}
+// __to_value_type_or_member_type {{{
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr auto
+ __to_value_type_or_member_type(const _V& __x) -> decltype(__data(__x))
+ { return __data(__x); }
+
+template
+ _GLIBCXX_SIMD_INTRINSIC constexpr const typename _V::value_type&
+ __to_value_type_or_member_type(const typename _V::value_type& __x)
+ { return __x; }
+
+// }}}
+// __bool_storage_member_type{{{
+template
+ struct __bool_storage_member_type;
+
+template
+ using __bool_storage_member_type_t =
+ typename __bool_storage_member_type<_Size>::type;
+
+// }}}
+// _SimdTuple {{{
+// why not tuple?
+// 1. tuple gives no guarantee about the storage order, but I require
+// storage
+// equivalent to array<_Tp, _Np>
+// 2. direct access to the element type (first template argument)
+// 3. enforces equal element type, only different _Abi types are allowed
+template
+ struct _SimdTuple;
+
+//}}}
+// __fixed_size_storage_t {{{
+template
+ struct __fixed_size_storage;
+
+template
+ using __fixed_size_storage_t = typename __fixed_size_storage<_Tp, _Np>::type;
+
+// }}}
+// _SimdWrapper fwd decl{{{
+template >
+ struct _SimdWrapper;
+
+template
+ using _SimdWrapper8 = _SimdWrapper<_Tp, 8 / sizeof(_Tp)>;
+template
+ using _SimdWrapper16 = _SimdWrapper<_Tp, 16 / sizeof(_Tp)>;
+template
+ using _SimdWrapper32 = _SimdWrapper<_Tp, 32 / sizeof(_Tp)>;
+template