[committed] Re: [PATCH] libstdc++: Add missing constexpr to simd

Message ID 15963891.uLZWGnKmhe@minbar
State Accepted
Headers
Series [committed] Re: [PATCH] libstdc++: Add missing constexpr to simd |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Matthias Kretz May 23, 2023, 7:30 a.m. UTC
  I pushed the attached patch.

I kept the operator names... too late, there were already operator names in 
the stdx::simd implemenation anyway. ;)

- Matthias

On Monday, 22 May 2023 22:51:49 CEST Jonathan Wakely wrote:
> On Mon, 22 May 2023 at 21:27, Matthias Kretz <m.kretz@gsi.de> wrote:
> > On Monday, 22 May 2023 18:25:15 CEST Jonathan Wakely wrote:
> > > I note that using if (not __builtin_constant_evaluated()) will fail if
> > > compiled with -fno-operator-names, which is why we don't use 'not',
> > 
> > 'and',
> > 
> > > etc. elsewhere in libstdc++. I don't know if (or why) anybody uses that
> > > option though, so I don't think you need to hange anything in
> > > stdx::simd.
> > 
> > Ah, I just recently convinced myself that "operator-names" are more
> > readable
> > (=> easier to maintain).
> 
> I tend to agree, but every time I decide to start using them some testcases
> start to fail and I remember why we don't use them :-(
> 
> > But OTOH a mix isn't necessarily better. I'm fine
> > with keeping it consistent.
> > 
> > > > * subscripting vector builtins is not allowed in constant expressions
> > > 
> > > Is that just because nobody made it work (yet)?
> > 
> > That is a good question. I guess I should open a PR.
> > 
> > > * if the implementation needs/uses memcpy
> > > 
> > > > * if the implementation would otherwise call SIMD intrinsics/builtins
> > > 
> > > The indentation looks off here and in the _M_set member function
> > 
> > following
> > 
> > > it:
> > Yes. I had to put an #if between an else and an if. Looks like this:
> >   else
> > 
> > #ifdef _GLIBCXX_SIMD_USE_ALIASING_LOADS
> > 
> >     if (not __builtin_is_constant_evaluated())
> >     return reinterpret_cast<const __may_alias<_Tp>*>(this)[__i];
> >   
> >   else
> > 
> > #endif
> > 
> >     if constexpr (__is_scalar_abi<_Abi0>())
> 
> Ah yes, so the if is indented two spaces from the else above it.
> What looks wrong to me is that the return is the at the same indentation as
> the if controlling it.
> 
> > Should the `if` be aligned to the `else` instead?
> 
> How about moving the two else tokens?
> 
>  #ifdef _GLIBCXX_SIMD_USE_ALIASING_LOADS
>    else if (not __builtin_is_constant_evaluated())
>      return reinterpret_cast<const __may_alias<_Tp>*>(this)[__i];
>  #endif
>    else if constexpr (__is_scalar_abi<_Abi0>())
> 
> I think that avoids the issue.
> 
> > > Are the copyright years on
> > > testsuite/experimental/simd/pr109261_constexpr_simd.cc correct, or just
> > > copy&paste?
> > 
> > Right, copy&paste. Should I simply remove the complete header?
> 
> You could do. I don't think there's much in that test that's novel or worth
> asserting copyright over - but if you disagree and want to assign whatever
> is copyrightable to the FSF, keep the header but fix the years. Either way
> is fine by me.
> 
> OK for trunk and backports, with the comments above suitably resolved.
  

Patch

diff --git a/libstdc++-v3/include/experimental/bits/simd.h b/libstdc++-v3/include/experimental/bits/simd.h
index 224153ffbaf..b0571ca26c4 100644
--- a/libstdc++-v3/include/experimental/bits/simd.h
+++ b/libstdc++-v3/include/experimental/bits/simd.h
@@ -2675,7 +2675,14 @@  _SimdWrapper(_V __x)
 
     _GLIBCXX_SIMD_INTRINSIC constexpr void
     _M_set(size_t __i, _Tp __x)
-    { _M_data[__i] = __x; }
+    {
+      if (__builtin_is_constant_evaluated())
+	_M_data = __generate_from_n_evaluations<_Width, _BuiltinType>([&](auto __j) {
+		    return __j == __i ? __x : _M_data[__j()];
+		  });
+      else
+	_M_data[__i] = __x;
+    }
 
     _GLIBCXX_SIMD_INTRINSIC
     constexpr bool
@@ -3186,6 +3193,10 @@  resizing_simd_cast(const simd<_Up, _Ap>& __x)
   {
     if constexpr (is_same_v<typename _Tp::abi_type, _Ap>)
       return __x;
+    else if (__builtin_is_constant_evaluated())
+      return _Tp([&](auto __i) constexpr {
+	       return __i < simd_size_v<_Up, _Ap> ? __x[__i] : _Up();
+	     });
     else if constexpr (simd_size_v<_Up, _Ap> == 1)
       {
 	_Tp __r{};
@@ -3321,10 +3332,11 @@  __get_lvalue(const const_where_expression& __x)
 
     const_where_expression& operator=(const const_where_expression&) = delete;
 
-    _GLIBCXX_SIMD_INTRINSIC const_where_expression(const _M& __kk, const _Tp& dd)
-      : _M_k(__kk), _M_value(const_cast<_Tp&>(dd)) {}
+    _GLIBCXX_SIMD_INTRINSIC constexpr
+    const_where_expression(const _M& __kk, const _Tp& dd)
+    : _M_k(__kk), _M_value(const_cast<_Tp&>(dd)) {}
 
-    _GLIBCXX_SIMD_INTRINSIC _V
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
     operator-() const&&
     {
       return {__private_init,
@@ -3333,7 +3345,7 @@  __get_lvalue(const const_where_expression& __x)
     }
 
     template <typename _Up, typename _Flags>
-      [[nodiscard]] _GLIBCXX_SIMD_INTRINSIC _V
+      [[nodiscard]] _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
       copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
       {
 	return {__private_init,
@@ -3342,7 +3354,7 @@  __get_lvalue(const const_where_expression& __x)
       }
 
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_INTRINSIC void
+      _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
       copy_to(_LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
       {
 	_Impl::_S_masked_store(__data(_M_value),
@@ -3381,19 +3393,21 @@  __get_lvalue(const const_where_expression& __x)
     const_where_expression(const const_where_expression&) = delete;
     const_where_expression& operator=(const const_where_expression&) = delete;
 
-    _GLIBCXX_SIMD_INTRINSIC const_where_expression(const bool __kk, const _Tp& dd)
-      : _M_k(__kk), _M_value(const_cast<_Tp&>(dd)) {}
+    _GLIBCXX_SIMD_INTRINSIC constexpr
+    const_where_expression(const bool __kk, const _Tp& dd)
+    : _M_k(__kk), _M_value(const_cast<_Tp&>(dd)) {}
 
-    _GLIBCXX_SIMD_INTRINSIC _V operator-() const&&
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
+    operator-() const&&
     { return _M_k ? -_M_value : _M_value; }
 
     template <typename _Up, typename _Flags>
-      [[nodiscard]] _GLIBCXX_SIMD_INTRINSIC _V
+      [[nodiscard]] _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR _V
       copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
       { return _M_k ? static_cast<_V>(__mem[0]) : _M_value; }
 
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_INTRINSIC void
+      _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
       copy_to(_LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) const&&
       {
 	if (_M_k)
@@ -3419,18 +3433,21 @@  static_assert(
       is_same<typename _M::abi_type, typename _Tp::abi_type>::value, "");
     static_assert(_M::size() == _Tp::size(), "");
 
-    _GLIBCXX_SIMD_INTRINSIC friend _Tp& __get_lvalue(where_expression& __x)
+    _GLIBCXX_SIMD_INTRINSIC friend constexpr _Tp&
+    __get_lvalue(where_expression& __x)
     { return __x._M_value; }
 
   public:
     where_expression(const where_expression&) = delete;
     where_expression& operator=(const where_expression&) = delete;
 
-    _GLIBCXX_SIMD_INTRINSIC where_expression(const _M& __kk, _Tp& dd)
-      : const_where_expression<_M, _Tp>(__kk, dd) {}
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
+    where_expression(const _M& __kk, _Tp& dd)
+    : const_where_expression<_M, _Tp>(__kk, dd) {}
 
     template <typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC void operator=(_Up&& __x) &&
+      _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
+      operator=(_Up&& __x) &&
       {
 	_Impl::_S_masked_assign(__data(_M_k), __data(_M_value),
 				__to_value_type_or_member_type<_Tp>(
@@ -3439,7 +3456,8 @@  static_assert(
 
 #define _GLIBCXX_SIMD_OP_(__op, __name)                                        \
   template <typename _Up>                                                      \
-    _GLIBCXX_SIMD_INTRINSIC void operator __op##=(_Up&& __x)&&                 \
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void                       \
+    operator __op##=(_Up&& __x)&&                                              \
     {                                                                          \
       _Impl::template _S_masked_cassign(                                       \
 	__data(_M_k), __data(_M_value),                                        \
@@ -3461,28 +3479,28 @@  static_assert(
     _GLIBCXX_SIMD_OP_(>>, _S_shift_right);
 #undef _GLIBCXX_SIMD_OP_
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator++() &&
     {
       __data(_M_value)
 	= _Impl::template _S_masked_unary<__increment>(__data(_M_k), __data(_M_value));
     }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator++(int) &&
     {
       __data(_M_value)
 	= _Impl::template _S_masked_unary<__increment>(__data(_M_k), __data(_M_value));
     }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator--() &&
     {
       __data(_M_value)
 	= _Impl::template _S_masked_unary<__decrement>(__data(_M_k), __data(_M_value));
     }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator--(int) &&
     {
       __data(_M_value)
@@ -3491,7 +3509,7 @@  static_assert(
 
     // intentionally hides const_where_expression::copy_from
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_INTRINSIC void
+      _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
       copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) &&
       {
 	__data(_M_value) = _Impl::_S_masked_load(__data(_M_value), __data(_M_k),
@@ -3513,13 +3531,13 @@  class where_expression<bool, _Tp>
     where_expression(const where_expression&) = delete;
     where_expression& operator=(const where_expression&) = delete;
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
     where_expression(const _M& __kk, _Tp& dd)
     : const_where_expression<_M, _Tp>(__kk, dd) {}
 
 #define _GLIBCXX_SIMD_OP_(__op)                                                \
     template <typename _Up>                                                    \
-      _GLIBCXX_SIMD_INTRINSIC void                                             \
+      _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void                     \
       operator __op(_Up&& __x)&&                                               \
       { if (_M_k) _M_value __op static_cast<_Up&&>(__x); }
 
@@ -3536,68 +3554,71 @@  where_expression(const _M& __kk, _Tp& dd)
     _GLIBCXX_SIMD_OP_(>>=)
   #undef _GLIBCXX_SIMD_OP_
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator++() &&
     { if (_M_k) ++_M_value; }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator++(int) &&
     { if (_M_k) ++_M_value; }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator--() &&
     { if (_M_k) --_M_value; }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
     operator--(int) &&
     { if (_M_k) --_M_value; }
 
     // intentionally hides const_where_expression::copy_from
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_INTRINSIC void
+      _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR void
       copy_from(const _LoadStorePtr<_Up, value_type>* __mem, _IsSimdFlagType<_Flags>) &&
       { if (_M_k) _M_value = __mem[0]; }
   };
 
 // where {{{1
 template <typename _Tp, typename _Ap>
-  _GLIBCXX_SIMD_INTRINSIC where_expression<simd_mask<_Tp, _Ap>, simd<_Tp, _Ap>>
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
+  where_expression<simd_mask<_Tp, _Ap>, simd<_Tp, _Ap>>
   where(const typename simd<_Tp, _Ap>::mask_type& __k, simd<_Tp, _Ap>& __value)
   { return {__k, __value}; }
 
 template <typename _Tp, typename _Ap>
-  _GLIBCXX_SIMD_INTRINSIC
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
   const_where_expression<simd_mask<_Tp, _Ap>, simd<_Tp, _Ap>>
   where(const typename simd<_Tp, _Ap>::mask_type& __k, const simd<_Tp, _Ap>& __value)
   { return {__k, __value}; }
 
 template <typename _Tp, typename _Ap>
-  _GLIBCXX_SIMD_INTRINSIC
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
   where_expression<simd_mask<_Tp, _Ap>, simd_mask<_Tp, _Ap>>
   where(const remove_const_t<simd_mask<_Tp, _Ap>>& __k, simd_mask<_Tp, _Ap>& __value)
   { return {__k, __value}; }
 
 template <typename _Tp, typename _Ap>
-  _GLIBCXX_SIMD_INTRINSIC
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR
   const_where_expression<simd_mask<_Tp, _Ap>, simd_mask<_Tp, _Ap>>
   where(const remove_const_t<simd_mask<_Tp, _Ap>>& __k, const simd_mask<_Tp, _Ap>& __value)
   { return {__k, __value}; }
 
 template <typename _Tp>
-  _GLIBCXX_SIMD_INTRINSIC where_expression<bool, _Tp>
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR where_expression<bool, _Tp>
   where(_ExactBool __k, _Tp& __value)
   { return {__k, __value}; }
 
 template <typename _Tp>
-  _GLIBCXX_SIMD_INTRINSIC const_where_expression<bool, _Tp>
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR const_where_expression<bool, _Tp>
   where(_ExactBool __k, const _Tp& __value)
   { return {__k, __value}; }
 
 template <typename _Tp, typename _Ap>
-  void where(bool __k, simd<_Tp, _Ap>& __value) = delete;
+  _GLIBCXX_SIMD_CONSTEXPR void
+  where(bool __k, simd<_Tp, _Ap>& __value) = delete;
 
 template <typename _Tp, typename _Ap>
-  void where(bool __k, const simd<_Tp, _Ap>& __value) = delete;
+  _GLIBCXX_SIMD_CONSTEXPR void
+  where(bool __k, const simd<_Tp, _Ap>& __value) = delete;
 
 // proposed mask iterations {{{1
 namespace __proposed {
@@ -3820,12 +3841,12 @@  clamp(const simd<_Tp, _Ap>& __v, const simd<_Tp, _Ap>& __lo, const simd<_Tp, _Ap
 
 // __extract_part {{{
 template <int _Index, int _Total, int _Combine = 1, typename _Tp, size_t _Np>
-  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST constexpr
   _SimdWrapper<_Tp, _Np / _Total * _Combine>
   __extract_part(const _SimdWrapper<_Tp, _Np> __x);
 
 template <int _Index, int _Parts, int _Combine = 1, typename _Tp, typename _A0, typename... _As>
-  _GLIBCXX_SIMD_INTRINSIC auto
+  _GLIBCXX_SIMD_INTRINSIC constexpr auto
   __extract_part(const _SimdTuple<_Tp, _A0, _As...>& __x);
 
 // }}}
@@ -4551,7 +4572,7 @@  class simd_mask
 
     // }}}
     // access to internal representation (optional feature) {{{
-    _GLIBCXX_SIMD_ALWAYS_INLINE explicit
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR explicit
     simd_mask(typename _Traits::_MaskCastType __init)
     : _M_data{__init} {}
     // conversions to internal type is done in _MaskBase
@@ -4562,11 +4583,11 @@  class simd_mask
     // Conversion of simd_mask to and from bitset makes it much easier to
     // interface with other facilities. I suggest adding `static
     // simd_mask::from_bitset` and `simd_mask::to_bitset`.
-    _GLIBCXX_SIMD_ALWAYS_INLINE static simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR static simd_mask
     __from_bitset(bitset<size()> bs)
     { return {__bitset_init, bs}; }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE bitset<size()>
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR bitset<size()>
     __to_bitset() const
     { return _Impl::_S_to_bits(_M_data)._M_to_bitset(); }
 
@@ -4591,7 +4612,7 @@  simd_mask(const simd_mask<_Up, _A2>& __x)
     template <typename _Up, typename = enable_if_t<conjunction<
 			      is_same<abi_type, simd_abi::fixed_size<size()>>,
 			      is_same<_Up, _Up>>::value>>
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
       simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
       : _M_data(_Impl::_S_from_bitmask(__data(__x), _S_type_tag)) {}
   #endif
@@ -4599,12 +4620,12 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
     // }}}
     // load constructor {{{
     template <typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
       simd_mask(const value_type* __mem, _IsSimdFlagType<_Flags>)
       : _M_data(_Impl::template _S_load<_Ip>(_Flags::template _S_apply<simd_mask>(__mem))) {}
 
     template <typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
       simd_mask(const value_type* __mem, simd_mask __k, _IsSimdFlagType<_Flags>)
       : _M_data{}
       {
@@ -4615,20 +4636,20 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
     // }}}
     // loads [simd_mask.load] {{{
     template <typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE void
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
       copy_from(const value_type* __mem, _IsSimdFlagType<_Flags>)
       { _M_data = _Impl::template _S_load<_Ip>(_Flags::template _S_apply<simd_mask>(__mem)); }
 
     // }}}
     // stores [simd_mask.store] {{{
     template <typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE void
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
       copy_to(value_type* __mem, _IsSimdFlagType<_Flags>) const
       { _Impl::_S_store(_M_data, _Flags::template _S_apply<simd_mask>(__mem)); }
 
     // }}}
     // scalar access {{{
-    _GLIBCXX_SIMD_ALWAYS_INLINE reference
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR reference
     operator[](size_t __i)
     {
       if (__i >= size())
@@ -4636,7 +4657,7 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
       return {_M_data, int(__i)};
     }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE value_type
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR value_type
     operator[](size_t __i) const
     {
       if (__i >= size())
@@ -4649,7 +4670,7 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
 
     // }}}
     // negation {{{
-    _GLIBCXX_SIMD_ALWAYS_INLINE simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR simd_mask
     operator!() const
     { return {__private_init, _Impl::_S_bit_not(_M_data)}; }
 
@@ -4659,7 +4680,7 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
     // simd_mask<int> && simd_mask<uint> needs disambiguation
     template <typename _Up, typename _A2,
 	      typename = enable_if_t<is_convertible_v<simd_mask<_Up, _A2>, simd_mask>>>
-      _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
       operator&&(const simd_mask& __x, const simd_mask<_Up, _A2>& __y)
       {
 	return {__private_init,
@@ -4668,7 +4689,7 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
 
     template <typename _Up, typename _A2,
 	      typename = enable_if_t<is_convertible_v<simd_mask<_Up, _A2>, simd_mask>>>
-      _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
       operator||(const simd_mask& __x, const simd_mask<_Up, _A2>& __y)
       {
 	return {__private_init,
@@ -4676,41 +4697,41 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
       }
   #endif // _GLIBCXX_SIMD_ENABLE_IMPLICIT_MASK_CAST
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
     operator&&(const simd_mask& __x, const simd_mask& __y)
     { return {__private_init, _Impl::_S_logical_and(__x._M_data, __y._M_data)}; }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
     operator||(const simd_mask& __x, const simd_mask& __y)
     { return {__private_init, _Impl::_S_logical_or(__x._M_data, __y._M_data)}; }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
     operator&(const simd_mask& __x, const simd_mask& __y)
     { return {__private_init, _Impl::_S_bit_and(__x._M_data, __y._M_data)}; }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
     operator|(const simd_mask& __x, const simd_mask& __y)
     { return {__private_init, _Impl::_S_bit_or(__x._M_data, __y._M_data)}; }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask
     operator^(const simd_mask& __x, const simd_mask& __y)
     { return {__private_init, _Impl::_S_bit_xor(__x._M_data, __y._M_data)}; }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask&
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask&
     operator&=(simd_mask& __x, const simd_mask& __y)
     {
       __x._M_data = _Impl::_S_bit_and(__x._M_data, __y._M_data);
       return __x;
     }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask&
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask&
     operator|=(simd_mask& __x, const simd_mask& __y)
     {
       __x._M_data = _Impl::_S_bit_or(__x._M_data, __y._M_data);
       return __x;
     }
 
-    _GLIBCXX_SIMD_ALWAYS_INLINE friend simd_mask&
+    _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR friend simd_mask&
     operator^=(simd_mask& __x, const simd_mask& __y)
     {
       __x._M_data = _Impl::_S_bit_xor(__x._M_data, __y._M_data);
@@ -4747,7 +4768,8 @@  simd_mask(const simd_mask<_Up, simd_abi::fixed_size<size()>>& __x)
 
     // }}}
     // bitset_init ctor {{{
-    _GLIBCXX_SIMD_INTRINSIC simd_mask(_BitsetInit, bitset<size()> __init)
+    _GLIBCXX_SIMD_INTRINSIC constexpr
+    simd_mask(_BitsetInit, bitset<size()> __init)
     : _M_data(_Impl::_S_from_bitmask(_SanitizedBitMask<size()>(__init), _S_type_tag))
     {}
 
@@ -5015,7 +5037,8 @@  class _SimdIntOperators<_V, _Tp, _Abi, true>
   {
     using _Impl = typename _SimdTraits<_Tp, _Abi>::_SimdImpl;
 
-    _GLIBCXX_SIMD_INTRINSIC const _V& __derived() const
+    _GLIBCXX_SIMD_INTRINSIC constexpr const _V&
+    __derived() const
     { return *static_cast<const _V*>(this); }
 
     template <typename _Up>
@@ -5235,7 +5258,7 @@  simd(const simd<_Up, _A2>& __x)
 
     // load constructor
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR
       simd(const _Up* __mem, _IsSimdFlagType<_Flags>)
       : _M_data(
 	  _Impl::_S_load(_Flags::template _S_apply<simd>(__mem), _S_type_tag))
@@ -5243,7 +5266,7 @@  simd(const simd<_Up, _A2>& __x)
 
     // loads [simd.load]
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE void
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
       copy_from(const _Vectorizable<_Up>* __mem, _IsSimdFlagType<_Flags>)
       {
 	_M_data = static_cast<decltype(_M_data)>(
@@ -5252,7 +5275,7 @@  simd(const simd<_Up, _A2>& __x)
 
     // stores [simd.store]
     template <typename _Up, typename _Flags>
-      _GLIBCXX_SIMD_ALWAYS_INLINE void
+      _GLIBCXX_SIMD_ALWAYS_INLINE _GLIBCXX_SIMD_CONSTEXPR void
       copy_to(_Vectorizable<_Up>* __mem, _IsSimdFlagType<_Flags>) const
       {
 	_Impl::_S_store(_M_data, _Flags::template _S_apply<simd>(__mem),
@@ -5424,7 +5447,7 @@  _M_is_constprop() const
     }
 
   private:
-    _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_SIMD_CONSTEXPR static mask_type
+    _GLIBCXX_SIMD_INTRINSIC static constexpr mask_type
     _S_make_mask(typename mask_type::_MemberType __k)
     { return {__private_init, __k}; }
 
diff --git a/libstdc++-v3/include/experimental/bits/simd_builtin.h b/libstdc++-v3/include/experimental/bits/simd_builtin.h
index 3d52bc6c96a..8337fa2d9a6 100644
--- a/libstdc++-v3/include/experimental/bits/simd_builtin.h
+++ b/libstdc++-v3/include/experimental/bits/simd_builtin.h
@@ -52,7 +52,7 @@ 
 // Index == -1 requests zeroing of the output element
 template <int... _Indices, typename _Tp, typename _TVT = _VectorTraits<_Tp>,
 	  typename = __detail::__odr_helper>
-  _Tp
+  constexpr _Tp
   __vector_permute(_Tp __x)
   {
     static_assert(sizeof...(_Indices) == _TVT::_S_full_size);
@@ -65,7 +65,7 @@  __vector_permute(_Tp __x)
 // Index == -1 requests zeroing of the output element
 template <int... _Indices, typename _Tp, typename _TVT = _VectorTraits<_Tp>,
 	  typename = __detail::__odr_helper>
-  _Tp
+  constexpr _Tp
   __vector_shuffle(_Tp __x, _Tp __y)
   {
     return _Tp{(_Indices == -1 ? 0
@@ -205,7 +205,7 @@  __shift_elements_right(_Tp __v)
 // }}}
 // __extract_part(_SimdWrapper<_Tp, _Np>) {{{
 template <int _Index, int _Total, int _Combine, typename _Tp, size_t _Np>
-  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST
+  _GLIBCXX_SIMD_INTRINSIC _GLIBCXX_CONST constexpr
   _SimdWrapper<_Tp, _Np / _Total * _Combine>
   __extract_part(const _SimdWrapper<_Tp, _Np> __x)
   {
@@ -905,10 +905,10 @@  class _SimdCastType1
       _SimdMember _M_data;
 
     public:
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
       _SimdCastType1(_Ap __a) : _M_data(__vector_bitcast<_Tp>(__a)) {}
 
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
       operator _SimdMember() const { return _M_data; }
     };
 
@@ -919,13 +919,13 @@  class _SimdCastType2
       _SimdMember _M_data;
 
     public:
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
       _SimdCastType2(_Ap __a) : _M_data(__vector_bitcast<_Tp>(__a)) {}
 
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
       _SimdCastType2(_Bp __b) : _M_data(__b) {}
 
-      _GLIBCXX_SIMD_ALWAYS_INLINE
+      _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
       operator _SimdMember() const { return _M_data; }
     };
 
@@ -1345,6 +1345,11 @@  _S_store_bool_array(_BitMask<_Np, _Sanitized> __x, bool* __mem)
     {
       if constexpr (_Np == 1)
 	__mem[0] = __x[0];
+      else if (__builtin_is_constant_evaluated())
+	{
+	  for (size_t __i = 0; __i < _Np; ++__i)
+	    __mem[__i] = __x[__i];
+	}
       else if constexpr (_Np == 2)
 	{
 	  short __bool2 = (__x._M_to_bits() * 0x81) & 0x0101;
@@ -1424,12 +1429,12 @@  struct _SimdImplBuiltin
 
     // _M_make_simd(_SimdWrapper/__intrinsic_type_t) {{{2
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static simd<_Tp, _Abi>
+      _GLIBCXX_SIMD_INTRINSIC static constexpr simd<_Tp, _Abi>
       _M_make_simd(_SimdWrapper<_Tp, _Np> __x)
       { return {__private_init, __x}; }
 
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static simd<_Tp, _Abi>
+      _GLIBCXX_SIMD_INTRINSIC static constexpr simd<_Tp, _Abi>
       _M_make_simd(__intrinsic_type_t<_Tp, _Np> __x)
       { return {__private_init, __vector_bitcast<_Tp>(__x)}; }
 
@@ -1455,7 +1460,7 @@  _S_broadcast(_Tp __x) noexcept
 
     // _S_load {{{2
     template <typename _Tp, typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC static _SimdMember<_Tp>
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdMember<_Tp>
       _S_load(const _Up* __mem, _TypeTag<_Tp>) noexcept
       {
 	constexpr size_t _Np = _S_size<_Tp>;
@@ -1464,7 +1469,12 @@  _S_broadcast(_Tp __x) noexcept
 	    : (is_floating_point_v<_Up> && __have_avx) || __have_avx2 ? 32
 								      : 16;
 	constexpr size_t __bytes_to_load = sizeof(_Up) * _Np;
-	if constexpr (sizeof(_Up) > 8)
+	if (__builtin_is_constant_evaluated())
+	  return __generate_vector<_Tp, _S_full_size<_Tp>>(
+		   [&](auto __i) constexpr {
+		     return static_cast<_Tp>(__i < _Np ? __mem[__i] : 0);
+		   });
+	else if constexpr (sizeof(_Up) > 8)
 	  return __generate_vector<_Tp, _SimdMember<_Tp>::_S_full_size>(
 		   [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
 		     return static_cast<_Tp>(__i < _Np ? __mem[__i] : 0);
@@ -1511,7 +1521,7 @@  _S_broadcast(_Tp __x) noexcept
 
     // _S_masked_load {{{2
     template <typename _Tp, size_t _Np, typename _Up>
-      static inline _SimdWrapper<_Tp, _Np>
+      static constexpr inline _SimdWrapper<_Tp, _Np>
       _S_masked_load(_SimdWrapper<_Tp, _Np> __merge, _MaskMember<_Tp> __k,
 		     const _Up* __mem) noexcept
       {
@@ -1524,14 +1534,19 @@  _S_masked_load(_SimdWrapper<_Tp, _Np> __merge, _MaskMember<_Tp> __k,
 
     // _S_store {{{2
     template <typename _Tp, typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_store(_SimdMember<_Tp> __v, _Up* __mem, _TypeTag<_Tp>) noexcept
       {
 	// TODO: converting int -> "smaller int" can be optimized with AVX512
 	constexpr size_t _Np = _S_size<_Tp>;
 	constexpr size_t __max_store_size
 	  = _SuperImpl::template _S_max_store_size<_Up>;
-	if constexpr (sizeof(_Up) > 8)
+	if (__builtin_is_constant_evaluated())
+	  {
+	    for (size_t __i = 0; __i < _Np; ++__i)
+	      __mem[__i] = __v[__i];
+	  }
+	else if constexpr (sizeof(_Up) > 8)
 	  __execute_n_times<_Np>([&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
 	    __mem[__i] = __v[__i];
 	  });
@@ -1562,7 +1577,7 @@  _S_masked_load(_SimdWrapper<_Tp, _Np> __merge, _MaskMember<_Tp> __k,
 
     // _S_masked_store_nocvt {{{2
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_store_nocvt(_SimdWrapper<_Tp, _Np> __v, _Tp* __mem, _MaskMember<_Tp> __k)
       {
 	_BitOps::_S_bit_iteration(
@@ -1575,7 +1590,7 @@  _S_masked_store_nocvt(_SimdWrapper<_Tp, _Np> __v, _Tp* __mem, _MaskMember<_Tp> _
     // _S_masked_store {{{2
     template <typename _TW, typename _TVT = _VectorTraits<_TW>,
 	      typename _Tp = typename _TVT::value_type, typename _Up>
-      static inline void
+      static constexpr inline void
       _S_masked_store(const _TW __v, _Up* __mem, const _MaskMember<_Tp> __k) noexcept
       {
 	constexpr size_t _TV_size = _S_size<_Tp>;
@@ -1803,7 +1818,7 @@  _S_minmax(_SimdWrapper<_Tp, _Np> __a, _SimdWrapper<_Tp, _Np> __b)
     // reductions {{{2
     template <size_t _Np, size_t... _Is, size_t... _Zeros, typename _Tp,
 	      typename _BinaryOperation>
-      _GLIBCXX_SIMD_INTRINSIC static _Tp
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp
       _S_reduce_partial(index_sequence<_Is...>, index_sequence<_Zeros...>,
 			simd<_Tp, _Abi> __x, _BinaryOperation&& __binary_op)
       {
@@ -1833,6 +1848,13 @@  _S_reduce(simd<_Tp, _Abi> __x, _BinaryOperation&& __binary_op)
 	else if constexpr (_Np == 2)
 	  return __binary_op(simd<_Tp, simd_abi::scalar>(__x[0]),
 			     simd<_Tp, simd_abi::scalar>(__x[1]))[0];
+	else if (__builtin_is_constant_evaluated())
+	  {
+	    simd<_Tp, simd_abi::scalar> __acc = __x[0];
+	    for (size_t __i = 1; __i < _Np; ++__i)
+	      __acc = __binary_op(__acc, simd<_Tp, simd_abi::scalar>(__x[__i]));
+	    return __acc[0];
+	  }
 	else if constexpr (_Abi::template _S_is_partial<_Tp>) //{{{
 	  {
 	    [[maybe_unused]] constexpr auto __full_size
@@ -2445,24 +2467,24 @@  _S_fpclassify(_SimdWrapper<_Tp, _Np> __x)
 
     // _S_increment & _S_decrement{{{2
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_increment(_SimdWrapper<_Tp, _Np>& __x)
       { __x = __x._M_data + 1; }
 
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_decrement(_SimdWrapper<_Tp, _Np>& __x)
       { __x = __x._M_data - 1; }
 
     // smart_reference access {{{2
     template <typename _Tp, size_t _Np, typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC constexpr static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_set(_SimdWrapper<_Tp, _Np>& __v, int __i, _Up&& __x) noexcept
       { __v._M_set(__i, static_cast<_Up&&>(__x)); }
 
     // _S_masked_assign{{{2
     template <typename _Tp, typename _K, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_assign(_SimdWrapper<_K, _Np> __k, _SimdWrapper<_Tp, _Np>& __lhs,
 		       __type_identity_t<_SimdWrapper<_Tp, _Np>> __rhs)
       {
@@ -2475,7 +2497,7 @@  _S_masked_assign(_SimdWrapper<_K, _Np> __k, _SimdWrapper<_Tp, _Np>& __lhs,
       }
 
     template <typename _Tp, typename _K, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_assign(_SimdWrapper<_K, _Np> __k, _SimdWrapper<_Tp, _Np>& __lhs,
 		       __type_identity_t<_Tp> __rhs)
       {
@@ -2503,7 +2525,7 @@  _S_masked_assign(_SimdWrapper<_K, _Np> __k, _SimdWrapper<_Tp, _Np>& __lhs,
 
     // _S_masked_cassign {{{2
     template <typename _Op, typename _Tp, typename _K, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_cassign(const _SimdWrapper<_K, _Np> __k,
 			_SimdWrapper<_Tp, _Np>& __lhs,
 			const __type_identity_t<_SimdWrapper<_Tp, _Np>> __rhs,
@@ -2519,7 +2541,7 @@  _S_masked_cassign(const _SimdWrapper<_K, _Np> __k,
       }
 
     template <typename _Op, typename _Tp, typename _K, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_cassign(const _SimdWrapper<_K, _Np> __k,
 			_SimdWrapper<_Tp, _Np>& __lhs,
 			const __type_identity_t<_Tp> __rhs, _Op __op)
@@ -2528,7 +2550,7 @@  _S_masked_cassign(const _SimdWrapper<_K, _Np> __k,
     // _S_masked_unary {{{2
     template <template <typename> class _Op, typename _Tp, typename _K,
 	      size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static _SimdWrapper<_Tp, _Np>
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdWrapper<_Tp, _Np>
       _S_masked_unary(const _SimdWrapper<_K, _Np> __k,
 		      const _SimdWrapper<_Tp, _Np> __v)
       {
@@ -2704,18 +2726,18 @@  _S_broadcast(bool __x)
       _S_load(const bool* __mem)
       {
 	using _I = __int_for_sizeof_t<_Tp>;
-	if constexpr (sizeof(_Tp) == sizeof(bool))
-	  {
-	    const auto __bools
-	      = _CommonImpl::template _S_load<_I, _S_size<_Tp>>(__mem);
-	    // bool is {0, 1}, everything else is UB
-	    return __bools > 0;
-	  }
-	else
-	  return __generate_vector<_I, _S_size<_Tp>>(
-		   [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
-		     return __mem[__i] ? ~_I() : _I();
-		   });
+	if (not __builtin_is_constant_evaluated())
+	  if constexpr (sizeof(_Tp) == sizeof(bool))
+	    {
+	      const auto __bools
+		= _CommonImpl::template _S_load<_I, _S_size<_Tp>>(__mem);
+	      // bool is {0, 1}, everything else is UB
+	      return __bools > 0;
+	    }
+	return __generate_vector<_I, _S_size<_Tp>>(
+		 [&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
+		   return __mem[__i] ? ~_I() : _I();
+		 });
       }
 
     // }}}
@@ -2797,7 +2819,7 @@  _S_masked_load(_SimdWrapper<_Tp, _Np> __merge,
 
     // _S_store {{{2
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_store(_SimdWrapper<_Tp, _Np> __v, bool* __mem) noexcept
       {
 	__execute_n_times<_Np>([&](auto __i) constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
diff --git a/libstdc++-v3/include/experimental/bits/simd_fixed_size.h b/libstdc++-v3/include/experimental/bits/simd_fixed_size.h
index 123e714b528..131fbd254be 100644
--- a/libstdc++-v3/include/experimental/bits/simd_fixed_size.h
+++ b/libstdc++-v3/include/experimental/bits/simd_fixed_size.h
@@ -166,25 +166,25 @@  struct __tuple_element_meta
     static constexpr _MaskImpl _S_mask_impl = {};
 
     template <size_t _Np, bool _Sanitized>
-      _GLIBCXX_SIMD_INTRINSIC static auto
+      _GLIBCXX_SIMD_INTRINSIC static constexpr auto
       _S_submask(_BitMask<_Np, _Sanitized> __bits)
       { return __bits.template _M_extract<_Offset, _S_size()>(); }
 
     template <size_t _Np, bool _Sanitized>
-      _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
       _S_make_mask(_BitMask<_Np, _Sanitized> __bits)
       {
 	return _MaskImpl::template _S_convert<_Tp>(
 	  __bits.template _M_extract<_Offset, _S_size()>()._M_sanitized());
       }
 
-    _GLIBCXX_SIMD_INTRINSIC static _ULLong
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _ULLong
     _S_mask_to_shifted_ullong(_MaskMember __k)
     { return _MaskImpl::_S_to_bits(__k).to_ullong() << _Offset; }
   };
 
 template <size_t _Offset, typename _Tp, typename _Abi, typename... _As>
-  _GLIBCXX_SIMD_INTRINSIC
+  _GLIBCXX_SIMD_INTRINSIC constexpr
   __tuple_element_meta<_Tp, _Abi, _Offset>
   __make_meta(const _SimdTuple<_Tp, _Abi, _As...>&)
   { return {}; }
@@ -535,7 +535,7 @@  _M_assign_front(const _SimdTuple<_Tp, _As...>& __x) &
       }
 
     template <typename _R = _Tp, typename _Fp, typename... _More>
-      _GLIBCXX_SIMD_INTRINSIC auto
+      _GLIBCXX_SIMD_INTRINSIC constexpr auto
       _M_apply_r(_Fp&& __fun, const _More&... __more) const
       {
 	auto&& __first = __fun(__tuple_element_meta<_Tp, _Abi0, 0>(), first,
@@ -573,50 +573,43 @@  _M_assign_front(const _SimdTuple<_Tp, _As...>& __x) &
 	  return second[integral_constant<_Up, _I - simd_size_v<_Tp, _Abi0>>()];
       }
 
-    _GLIBCXX_SIMD_INTRINSIC _Tp
+    _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
     operator[](size_t __i) const noexcept
     {
       if constexpr (_S_tuple_size == 1)
 	return _M_subscript_read(__i);
-      else
-	{
 #ifdef _GLIBCXX_SIMD_USE_ALIASING_LOADS
-	  return reinterpret_cast<const __may_alias<_Tp>*>(this)[__i];
-#else
-	  if constexpr (__is_scalar_abi<_Abi0>())
-	    {
-	      const _Tp* ptr = &first;
-	      return ptr[__i];
-	    }
-	  else
-	    return __i < simd_size_v<_Tp, _Abi0>
-		     ? _M_subscript_read(__i)
-		     : second[__i - simd_size_v<_Tp, _Abi0>];
+      else if (not __builtin_is_constant_evaluated())
+	return reinterpret_cast<const __may_alias<_Tp>*>(this)[__i];
 #endif
+      else if constexpr (__is_scalar_abi<_Abi0>())
+	{
+	  const _Tp* ptr = &first;
+	  return ptr[__i];
 	}
+      else
+	return __i < simd_size_v<_Tp, _Abi0> ? _M_subscript_read(__i)
+					     : second[__i - simd_size_v<_Tp, _Abi0>];
     }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC constexpr void
     _M_set(size_t __i, _Tp __val) noexcept
     {
       if constexpr (_S_tuple_size == 1)
 	return _M_subscript_write(__i, __val);
-      else
-	{
 #ifdef _GLIBCXX_SIMD_USE_ALIASING_LOADS
-	  reinterpret_cast<__may_alias<_Tp>*>(this)[__i] = __val;
-#else
-	  if (__i < simd_size_v<_Tp, _Abi0>)
-	    _M_subscript_write(__i, __val);
-	  else
-	    second._M_set(__i - simd_size_v<_Tp, _Abi0>, __val);
+      else if (not __builtin_is_constant_evaluated())
+	reinterpret_cast<__may_alias<_Tp>*>(this)[__i] = __val;
 #endif
-	}
+      else if (__i < simd_size_v<_Tp, _Abi0>)
+	_M_subscript_write(__i, __val);
+      else
+	second._M_set(__i - simd_size_v<_Tp, _Abi0>, __val);
     }
 
   private:
     // _M_subscript_read/_write {{{
-    _GLIBCXX_SIMD_INTRINSIC _Tp
+    _GLIBCXX_SIMD_INTRINSIC constexpr _Tp
     _M_subscript_read([[maybe_unused]] size_t __i) const noexcept
     {
       if constexpr (__is_vectorizable_v<_FirstType>)
@@ -625,7 +618,7 @@  _M_set(size_t __i, _Tp __val) noexcept
 	return first[__i];
     }
 
-    _GLIBCXX_SIMD_INTRINSIC void
+    _GLIBCXX_SIMD_INTRINSIC constexpr void
     _M_subscript_write([[maybe_unused]] size_t __i, _Tp __y) noexcept
     {
       if constexpr (__is_vectorizable_v<_FirstType>)
@@ -639,22 +632,22 @@  _M_set(size_t __i, _Tp __val) noexcept
 
 // __make_simd_tuple {{{1
 template <typename _Tp, typename _A0>
-  _GLIBCXX_SIMD_INTRINSIC _SimdTuple<_Tp, _A0>
+  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdTuple<_Tp, _A0>
   __make_simd_tuple(simd<_Tp, _A0> __x0)
   { return {__data(__x0)}; }
 
 template <typename _Tp, typename _A0, typename... _As>
-  _GLIBCXX_SIMD_INTRINSIC _SimdTuple<_Tp, _A0, _As...>
+  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdTuple<_Tp, _A0, _As...>
   __make_simd_tuple(const simd<_Tp, _A0>& __x0, const simd<_Tp, _As>&... __xs)
   { return {__data(__x0), __make_simd_tuple(__xs...)}; }
 
 template <typename _Tp, typename _A0>
-  _GLIBCXX_SIMD_INTRINSIC _SimdTuple<_Tp, _A0>
+  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdTuple<_Tp, _A0>
   __make_simd_tuple(const typename _SimdTraits<_Tp, _A0>::_SimdMember& __arg0)
   { return {__arg0}; }
 
 template <typename _Tp, typename _A0, typename _A1, typename... _Abis>
-  _GLIBCXX_SIMD_INTRINSIC _SimdTuple<_Tp, _A0, _A1, _Abis...>
+  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdTuple<_Tp, _A0, _A1, _Abis...>
   __make_simd_tuple(
     const typename _SimdTraits<_Tp, _A0>::_SimdMember& __arg0,
     const typename _SimdTraits<_Tp, _A1>::_SimdMember& __arg1,
@@ -797,19 +790,19 @@  __to_simd_tuple_sized(
 
 // __optimize_simd_tuple {{{1
 template <typename _Tp>
-  _GLIBCXX_SIMD_INTRINSIC _SimdTuple<_Tp>
+  _GLIBCXX_SIMD_INTRINSIC constexpr _SimdTuple<_Tp>
   __optimize_simd_tuple(const _SimdTuple<_Tp>)
   { return {}; }
 
 template <typename _Tp, typename _Ap>
-  _GLIBCXX_SIMD_INTRINSIC const _SimdTuple<_Tp, _Ap>&
+  _GLIBCXX_SIMD_INTRINSIC constexpr const _SimdTuple<_Tp, _Ap>&
   __optimize_simd_tuple(const _SimdTuple<_Tp, _Ap>& __x)
   { return __x; }
 
 template <typename _Tp, typename _A0, typename _A1, typename... _Abis,
 	  typename _R = __fixed_size_storage_t<
 	    _Tp, _SimdTuple<_Tp, _A0, _A1, _Abis...>::_S_size()>>
-  _GLIBCXX_SIMD_INTRINSIC _R
+  _GLIBCXX_SIMD_INTRINSIC constexpr _R
   __optimize_simd_tuple(const _SimdTuple<_Tp, _A0, _A1, _Abis...>& __x)
   {
     using _Tup = _SimdTuple<_Tp, _A0, _A1, _Abis...>;
@@ -916,7 +909,7 @@  __for_each(const _SimdTuple<_Tp, _A0, _A1, _As...>& __a,
 // }}}1
 // __extract_part(_SimdTuple) {{{
 template <int _Index, int _Total, int _Combine, typename _Tp, typename _A0, typename... _As>
-  _GLIBCXX_SIMD_INTRINSIC auto // __vector_type_t or _SimdTuple
+  _GLIBCXX_SIMD_INTRINSIC constexpr auto // __vector_type_t or _SimdTuple
   __extract_part(const _SimdTuple<_Tp, _A0, _As...>& __x)
   {
     // worst cases:
@@ -1017,11 +1010,11 @@  struct __autocvt_to_simd
     _Tp _M_data;
     using _TT = __remove_cvref_t<_Tp>;
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC constexpr
     operator _TT()
     { return _M_data; }
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC constexpr
     operator _TT&()
     {
       static_assert(is_lvalue_reference<_Tp>::value, "");
@@ -1029,7 +1022,7 @@  struct __autocvt_to_simd
       return _M_data;
     }
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC constexpr
     operator _TT*()
     {
       static_assert(is_lvalue_reference<_Tp>::value, "");
@@ -1041,17 +1034,17 @@  struct __autocvt_to_simd
     __autocvt_to_simd(_Tp dd) : _M_data(dd) {}
 
     template <typename _Abi>
-      _GLIBCXX_SIMD_INTRINSIC
+      _GLIBCXX_SIMD_INTRINSIC constexpr
       operator simd<typename _TT::value_type, _Abi>()
       { return {__private_init, _M_data}; }
 
     template <typename _Abi>
-      _GLIBCXX_SIMD_INTRINSIC
+      _GLIBCXX_SIMD_INTRINSIC constexpr
       operator simd<typename _TT::value_type, _Abi>&()
       { return *reinterpret_cast<simd<typename _TT::value_type, _Abi>*>(&_M_data); }
 
     template <typename _Abi>
-      _GLIBCXX_SIMD_INTRINSIC
+      _GLIBCXX_SIMD_INTRINSIC constexpr
       operator simd<typename _TT::value_type, _Abi>*()
       { return reinterpret_cast<simd<typename _TT::value_type, _Abi>*>(&_M_data); }
   };
@@ -1073,11 +1066,11 @@  struct __autocvt_to_simd<_Tp, true>
     ~__autocvt_to_simd()
     { _M_data = __data(_M_fd).first; }
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC constexpr
     operator fixed_size_simd<_TT, 1>()
     { return _M_fd; }
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC constexpr
     operator fixed_size_simd<_TT, 1> &()
     {
       static_assert(is_lvalue_reference<_Tp>::value, "");
@@ -1085,7 +1078,7 @@  struct __autocvt_to_simd<_Tp, true>
       return _M_fd;
     }
 
-    _GLIBCXX_SIMD_INTRINSIC
+    _GLIBCXX_SIMD_INTRINSIC constexpr
     operator fixed_size_simd<_TT, 1> *()
     {
       static_assert(is_lvalue_reference<_Tp>::value, "");
@@ -1162,15 +1155,16 @@  struct _SimdBase
 	{
 	  // The following ensures, function arguments are passed via the stack.
 	  // This is important for ABI compatibility across TU boundaries
-	  _GLIBCXX_SIMD_ALWAYS_INLINE
+	  _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
 	  _SimdBase(const _SimdBase&) {}
+
 	  _SimdBase() = default;
 
-	  _GLIBCXX_SIMD_ALWAYS_INLINE explicit
+	  _GLIBCXX_SIMD_ALWAYS_INLINE constexpr explicit
 	  operator const _SimdMember &() const
 	  { return static_cast<const simd<_Tp, _Fixed>*>(this)->_M_data; }
 
-	  _GLIBCXX_SIMD_ALWAYS_INLINE explicit
+	  _GLIBCXX_SIMD_ALWAYS_INLINE constexpr explicit
 	  operator array<_Tp, _Np>() const
 	  {
 	    array<_Tp, _Np> __r;
@@ -1191,13 +1185,13 @@  struct _MaskBase
 	// _SimdCastType {{{
 	struct _SimdCastType
 	{
-	  _GLIBCXX_SIMD_ALWAYS_INLINE
+	  _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
 	  _SimdCastType(const array<_Tp, _Np>&);
 
-	  _GLIBCXX_SIMD_ALWAYS_INLINE
+	  _GLIBCXX_SIMD_ALWAYS_INLINE constexpr
 	  _SimdCastType(const _SimdMember& dd) : _M_data(dd) {}
 
-	  _GLIBCXX_SIMD_ALWAYS_INLINE explicit
+	  _GLIBCXX_SIMD_ALWAYS_INLINE constexpr explicit
 	  operator const _SimdMember &() const { return _M_data; }
 
 	private:
@@ -1282,7 +1276,7 @@  _S_broadcast(_Tp __x) noexcept
 
     // _S_load {{{2
     template <typename _Tp, typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC static _SimdMember<_Tp>
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _SimdMember<_Tp>
       _S_load(const _Up* __mem, _TypeTag<_Tp>) noexcept
       {
 	return _SimdMember<_Tp>::_S_generate(
@@ -1301,10 +1295,10 @@  _S_masked_load(const _SimdTuple<_Tp, _As...>& __old,
 	__for_each(__merge, [&](auto __meta, auto& __native) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
 	  if (__meta._S_submask(__bits).any())
 #pragma GCC diagnostic push
-	  // __mem + __mem._S_offset could be UB ([expr.add]/4.3, but it punts
-	  // the responsibility for avoiding UB to the caller of the masked load
-	  // via the mask. Consequently, the compiler may assume this branch is
-	  // unreachable, if the pointer arithmetic is UB.
+	    // Dereferencing __mem + __meta._S_offset could be UB ([expr.add]/4.3).
+	    // It is the responsibility of the caller of the masked load (via the mask's value) to
+	    // avoid UB. Consequently, the compiler may assume this branch is unreachable, if the
+	    // pointer arithmetic is UB.
 #pragma GCC diagnostic ignored "-Warray-bounds"
 	    __native
 	      = __meta._S_masked_load(__native, __meta._S_make_mask(__bits),
@@ -1316,7 +1310,7 @@  _S_masked_load(const _SimdTuple<_Tp, _As...>& __old,
 
     // _S_store {{{2
     template <typename _Tp, typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_store(const _SimdMember<_Tp>& __v, _Up* __mem, _TypeTag<_Tp>) noexcept
       {
 	__for_each(__v, [&](auto __meta, auto __native) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
@@ -1346,7 +1340,7 @@  _S_masked_store(const _SimdTuple<_Tp, _As...>& __v, _Up* __mem,
 
     // negation {{{2
     template <typename _Tp, typename... _As>
-      static inline _MaskMember
+      static constexpr inline _MaskMember
       _S_negate(const _SimdTuple<_Tp, _As...>& __x) noexcept
       {
 	_MaskMember __bits = 0;
@@ -1699,7 +1693,7 @@  __for_each(
     // compares {{{2
 #define _GLIBCXX_SIMD_CMP_OPERATIONS(__cmp)                                    \
     template <typename _Tp, typename... _As>                                   \
-      _GLIBCXX_SIMD_INTRINSIC constexpr static _MaskMember                     \
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember                     \
       __cmp(const _SimdTuple<_Tp, _As...>& __x,                                \
 	    const _SimdTuple<_Tp, _As...>& __y)                                \
       {                                                                        \
@@ -1723,13 +1717,13 @@  __for_each(
 
     // smart_reference access {{{2
     template <typename _Tp, typename... _As, typename _Up>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_set(_SimdTuple<_Tp, _As...>& __v, int __i, _Up&& __x) noexcept
       { __v._M_set(__i, static_cast<_Up&&>(__x)); }
 
     // _S_masked_assign {{{2
     template <typename _Tp, typename... _As>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_assign(const _MaskMember __bits, _SimdTuple<_Tp, _As...>& __lhs,
 		       const __type_identity_t<_SimdTuple<_Tp, _As...>>& __rhs)
       {
@@ -1745,7 +1739,7 @@  _S_masked_assign(const _MaskMember __bits, _SimdTuple<_Tp, _As...>& __lhs,
     // Optimization for the case where the RHS is a scalar. No need to broadcast
     // the scalar to a simd first.
     template <typename _Tp, typename... _As>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_masked_assign(const _MaskMember __bits, _SimdTuple<_Tp, _As...>& __lhs,
 		       const __type_identity_t<_Tp> __rhs)
       {
@@ -1758,7 +1752,7 @@  __for_each(
 
     // _S_masked_cassign {{{2
     template <typename _Op, typename _Tp, typename... _As>
-      static inline void
+      static constexpr inline void
       _S_masked_cassign(const _MaskMember __bits, _SimdTuple<_Tp, _As...>& __lhs,
 			const _SimdTuple<_Tp, _As...>& __rhs, _Op __op)
       {
@@ -1774,7 +1768,7 @@  _S_masked_cassign(const _MaskMember __bits, _SimdTuple<_Tp, _As...>& __lhs,
     // Optimization for the case where the RHS is a scalar. No need to broadcast
     // the scalar to a simd first.
     template <typename _Op, typename _Tp, typename... _As>
-      static inline void
+      static constexpr inline void
       _S_masked_cassign(const _MaskMember __bits, _SimdTuple<_Tp, _As...>& __lhs,
 			const _Tp& __rhs, _Op __op)
       {
@@ -1787,7 +1781,7 @@  __for_each(
 
     // _S_masked_unary {{{2
     template <template <typename> class _Op, typename _Tp, typename... _As>
-      static inline _SimdTuple<_Tp, _As...>
+      static constexpr inline _SimdTuple<_Tp, _As...>
       _S_masked_unary(const _MaskMember __bits, const _SimdTuple<_Tp, _As...>& __v)
       {
 	return __v._M_apply_wrapped([&__bits](auto __meta,
@@ -1834,6 +1828,13 @@  _S_broadcast(bool __x)
       _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
       _S_load(const bool* __mem)
       {
+	if (__builtin_is_constant_evaluated())
+	  {
+	    _MaskMember __r{};
+	    for (size_t __i = 0; __i < _Np; ++__i)
+	      __r.set(__i, __mem[__i]);
+	    return __r;
+	  }
 	using _Ip = __int_for_sizeof_t<bool>;
 	// the following load uses element_aligned and relies on __mem already
 	// carrying alignment information from when this load function was
@@ -1869,12 +1870,12 @@  _S_convert(simd_mask<_Up, _UAbi> __x)
     // }}}
     // _S_from_bitmask {{{2
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+      _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
       _S_from_bitmask(_MaskMember __bits, _TypeTag<_Tp>) noexcept
       { return __bits; }
 
     // _S_load {{{2
-    static inline _MaskMember
+    static constexpr inline _MaskMember
     _S_load(const bool* __mem) noexcept
     {
       // TODO: _UChar is not necessarily the best type to use here. For smaller
@@ -1890,7 +1891,7 @@  _S_load(const bool* __mem) noexcept
     }
 
     // _S_masked_load {{{2
-    static inline _MaskMember
+    static constexpr inline _MaskMember
     _S_masked_load(_MaskMember __merge, _MaskMember __mask, const bool* __mem) noexcept
     {
       _BitOps::_S_bit_iteration(__mask.to_ullong(),
@@ -1901,7 +1902,7 @@  _S_load(const bool* __mem) noexcept
     }
 
     // _S_store {{{2
-    static inline void
+    static constexpr inline void
     _S_store(const _MaskMember __bitmask, bool* __mem) noexcept
     {
       if constexpr (_Np == 1)
@@ -1911,7 +1912,7 @@  _S_store(const _MaskMember __bitmask, bool* __mem) noexcept
     }
 
     // _S_masked_store {{{2
-    static inline void
+    static constexpr inline void
     _S_masked_store(const _MaskMember __v, bool* __mem, const _MaskMember __k) noexcept
     {
       _BitOps::_S_bit_iteration(
@@ -1919,11 +1920,11 @@  _S_store(const _MaskMember __bitmask, bool* __mem) noexcept
     }
 
     // logical and bitwise operators {{{2
-    _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
     _S_logical_and(const _MaskMember& __x, const _MaskMember& __y) noexcept
     { return __x & __y; }
 
-    _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
     _S_logical_or(const _MaskMember& __x, const _MaskMember& __y) noexcept
     { return __x | __y; }
 
@@ -1931,30 +1932,30 @@  _S_logical_or(const _MaskMember& __x, const _MaskMember& __y) noexcept
     _S_bit_not(const _MaskMember& __x) noexcept
     { return ~__x; }
 
-    _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
     _S_bit_and(const _MaskMember& __x, const _MaskMember& __y) noexcept
     { return __x & __y; }
 
-    _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
     _S_bit_or(const _MaskMember& __x, const _MaskMember& __y) noexcept
     { return __x | __y; }
 
-    _GLIBCXX_SIMD_INTRINSIC static _MaskMember
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _MaskMember
     _S_bit_xor(const _MaskMember& __x, const _MaskMember& __y) noexcept
     { return __x ^ __y; }
 
     // smart_reference access {{{2
-    _GLIBCXX_SIMD_INTRINSIC static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_set(_MaskMember& __k, int __i, bool __x) noexcept
     { __k.set(__i, __x); }
 
     // _S_masked_assign {{{2
-    _GLIBCXX_SIMD_INTRINSIC static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_masked_assign(const _MaskMember __k, _MaskMember& __lhs, const _MaskMember __rhs)
     { __lhs = (__lhs & ~__k) | (__rhs & __k); }
 
     // Optimization for the case where the RHS is a scalar.
-    _GLIBCXX_SIMD_INTRINSIC static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_masked_assign(const _MaskMember __k, _MaskMember& __lhs, const bool __rhs)
     {
       if (__rhs)
@@ -1966,28 +1967,28 @@  _S_bit_xor(const _MaskMember& __x, const _MaskMember& __y) noexcept
     // }}}2
     // _S_all_of {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static bool
+      _GLIBCXX_SIMD_INTRINSIC static constexpr bool
       _S_all_of(simd_mask<_Tp, _Abi> __k)
       { return __data(__k).all(); }
 
     // }}}
     // _S_any_of {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static bool
+      _GLIBCXX_SIMD_INTRINSIC static constexpr bool
       _S_any_of(simd_mask<_Tp, _Abi> __k)
       { return __data(__k).any(); }
 
     // }}}
     // _S_none_of {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static bool
+      _GLIBCXX_SIMD_INTRINSIC static constexpr bool
       _S_none_of(simd_mask<_Tp, _Abi> __k)
       { return __data(__k).none(); }
 
     // }}}
     // _S_some_of {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static bool
+      _GLIBCXX_SIMD_INTRINSIC static constexpr bool
       _S_some_of([[maybe_unused]] simd_mask<_Tp, _Abi> __k)
       {
 	if constexpr (_Np == 1)
@@ -1999,21 +2000,21 @@  _S_none_of(simd_mask<_Tp, _Abi> __k)
     // }}}
     // _S_popcount {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static int
+      _GLIBCXX_SIMD_INTRINSIC static constexpr int
       _S_popcount(simd_mask<_Tp, _Abi> __k)
       { return __data(__k).count(); }
 
     // }}}
     // _S_find_first_set {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static int
+      _GLIBCXX_SIMD_INTRINSIC static constexpr int
       _S_find_first_set(simd_mask<_Tp, _Abi> __k)
       { return std::__countr_zero(__data(__k).to_ullong()); }
 
     // }}}
     // _S_find_last_set {{{
     template <typename _Tp>
-      _GLIBCXX_SIMD_INTRINSIC static int
+      _GLIBCXX_SIMD_INTRINSIC static constexpr int
       _S_find_last_set(simd_mask<_Tp, _Abi> __k)
       { return std::__bit_width(__data(__k).to_ullong()) - 1; }
 
diff --git a/libstdc++-v3/include/experimental/bits/simd_scalar.h b/libstdc++-v3/include/experimental/bits/simd_scalar.h
index 1a1cc46fbe0..b88e13ff8bc 100644
--- a/libstdc++-v3/include/experimental/bits/simd_scalar.h
+++ b/libstdc++-v3/include/experimental/bits/simd_scalar.h
@@ -152,13 +152,13 @@  _S_broadcast(_Tp __x) noexcept
 
   // _S_load {{{2
   template <typename _Tp, typename _Up>
-    _GLIBCXX_SIMD_INTRINSIC static _Tp
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp
     _S_load(const _Up* __mem, _TypeTag<_Tp>) noexcept
     { return static_cast<_Tp>(__mem[0]); }
 
   // _S_masked_load {{{2
   template <typename _Tp, typename _Up>
-    _GLIBCXX_SIMD_INTRINSIC static _Tp
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp
     _S_masked_load(_Tp __merge, bool __k, const _Up* __mem) noexcept
     {
       if (__k)
@@ -168,13 +168,13 @@  _S_broadcast(_Tp __x) noexcept
 
   // _S_store {{{2
   template <typename _Tp, typename _Up>
-    _GLIBCXX_SIMD_INTRINSIC static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_store(_Tp __v, _Up* __mem, _TypeTag<_Tp>) noexcept
     { __mem[0] = static_cast<_Up>(__v); }
 
   // _S_masked_store {{{2
   template <typename _Tp, typename _Up>
-    _GLIBCXX_SIMD_INTRINSIC static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_masked_store(const _Tp __v, _Up* __mem, const bool __k) noexcept
     { if (__k) __mem[0] = __v; }
 
@@ -572,101 +572,101 @@  _S_fmin(_Tp __x, _Tp __y)
     { return std::remquo(__x, __y, &__z->first); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static _ST<int>
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _ST<int>
     _S_fpclassify(_Tp __x)
     { return {std::fpclassify(__x)}; }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isfinite(_Tp __x)
     { return std::isfinite(__x); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isinf(_Tp __x)
     { return std::isinf(__x); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isnan(_Tp __x)
     { return std::isnan(__x); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isnormal(_Tp __x)
     { return std::isnormal(__x); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_signbit(_Tp __x)
     { return std::signbit(__x); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isgreater(_Tp __x, _Tp __y)
     { return std::isgreater(__x, __y); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isgreaterequal(_Tp __x, _Tp __y)
     { return std::isgreaterequal(__x, __y); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isless(_Tp __x, _Tp __y)
     { return std::isless(__x, __y); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_islessequal(_Tp __x, _Tp __y)
     { return std::islessequal(__x, __y); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_islessgreater(_Tp __x, _Tp __y)
     { return std::islessgreater(__x, __y); }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_isunordered(_Tp __x, _Tp __y)
     { return std::isunordered(__x, __y); }
 
   // _S_increment & _S_decrement{{{2
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_increment(_Tp& __x)
     { ++__x; }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_decrement(_Tp& __x)
     { --__x; }
 
 
   // compares {{{2
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_equal_to(_Tp __x, _Tp __y)
     { return __x == __y; }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_not_equal_to(_Tp __x, _Tp __y)
     { return __x != __y; }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_less(_Tp __x, _Tp __y)
     { return __x < __y; }
 
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_less_equal(_Tp __x, _Tp __y)
     { return __x <= __y; }
 
   // smart_reference access {{{2
   template <typename _Tp, typename _Up>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_set(_Tp& __v, [[maybe_unused]] int __i, _Up&& __x) noexcept
     {
       _GLIBCXX_DEBUG_ASSERT(__i == 0);
@@ -675,19 +675,19 @@  _S_less_equal(_Tp __x, _Tp __y)
 
   // _S_masked_assign {{{2
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_masked_assign(bool __k, _Tp& __lhs, _Tp __rhs)
     { if (__k) __lhs = __rhs; }
 
   // _S_masked_cassign {{{2
   template <typename _Op, typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_masked_cassign(const bool __k, _Tp& __lhs, const _Tp __rhs, _Op __op)
     { if (__k) __lhs = __op(_SimdImplScalar{}, __lhs, __rhs); }
 
   // _S_masked_unary {{{2
   template <template <typename> class _Op, typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static _Tp
+    _GLIBCXX_SIMD_INTRINSIC static constexpr _Tp
     _S_masked_unary(const bool __k, const _Tp __v)
     { return static_cast<_Tp>(__k ? _Op<_Tp>{}(__v) : __v); }
 
@@ -737,12 +737,12 @@  _S_convert(simd_mask<_Up, _UAbi> __x)
   // }}}
   // _S_from_bitmask {{{2
   template <typename _Tp>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_from_bitmask(_SanitizedBitMask<1> __bits, _TypeTag<_Tp>) noexcept
     { return __bits[0]; }
 
   // _S_masked_load {{{2
-  _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+  _GLIBCXX_SIMD_INTRINSIC static constexpr bool
   _S_masked_load(bool __merge, bool __mask, const bool* __mem) noexcept
   {
     if (__mask)
@@ -751,12 +751,12 @@  _S_convert(simd_mask<_Up, _UAbi> __x)
   }
 
   // _S_store {{{2
-  _GLIBCXX_SIMD_INTRINSIC static void
+  _GLIBCXX_SIMD_INTRINSIC static constexpr void
   _S_store(bool __v, bool* __mem) noexcept
   { __mem[0] = __v; }
 
   // _S_masked_store {{{2
-  _GLIBCXX_SIMD_INTRINSIC static void
+  _GLIBCXX_SIMD_INTRINSIC static constexpr void
   _S_masked_store(const bool __v, bool* __mem, const bool __k) noexcept
   {
     if (__k)
@@ -789,7 +789,7 @@  _S_bit_xor(bool __x, bool __y)
   { return __x != __y; }
 
   // smart_reference access {{{2
-  _GLIBCXX_SIMD_INTRINSIC constexpr static void
+  _GLIBCXX_SIMD_INTRINSIC static constexpr void
   _S_set(bool& __k, [[maybe_unused]] int __i, bool __x) noexcept
   {
     _GLIBCXX_DEBUG_ASSERT(__i == 0);
@@ -797,7 +797,7 @@  _S_bit_xor(bool __x, bool __y)
   }
 
   // _S_masked_assign {{{2
-  _GLIBCXX_SIMD_INTRINSIC static void
+  _GLIBCXX_SIMD_INTRINSIC static constexpr void
   _S_masked_assign(bool __k, bool& __lhs, bool __rhs)
   {
     if (__k)
@@ -807,49 +807,49 @@  _S_bit_xor(bool __x, bool __y)
   // }}}2
   // _S_all_of {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_all_of(simd_mask<_Tp, _Abi> __k)
     { return __k._M_data; }
 
   // }}}
   // _S_any_of {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_any_of(simd_mask<_Tp, _Abi> __k)
     { return __k._M_data; }
 
   // }}}
   // _S_none_of {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_none_of(simd_mask<_Tp, _Abi> __k)
     { return !__k._M_data; }
 
   // }}}
   // _S_some_of {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static bool
+    _GLIBCXX_SIMD_INTRINSIC static constexpr bool
     _S_some_of(simd_mask<_Tp, _Abi>)
     { return false; }
 
   // }}}
   // _S_popcount {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static int
+    _GLIBCXX_SIMD_INTRINSIC static constexpr int
     _S_popcount(simd_mask<_Tp, _Abi> __k)
     { return __k._M_data; }
 
   // }}}
   // _S_find_first_set {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static int
+    _GLIBCXX_SIMD_INTRINSIC static constexpr int
     _S_find_first_set(simd_mask<_Tp, _Abi>)
     { return 0; }
 
   // }}}
   // _S_find_last_set {{{
   template <typename _Tp, typename _Abi>
-    _GLIBCXX_SIMD_INTRINSIC constexpr static int
+    _GLIBCXX_SIMD_INTRINSIC static constexpr int
     _S_find_last_set(simd_mask<_Tp, _Abi>)
     { return 0; }
 
diff --git a/libstdc++-v3/include/experimental/bits/simd_x86.h b/libstdc++-v3/include/experimental/bits/simd_x86.h
index fc3e96d696c..77d2f84ab71 100644
--- a/libstdc++-v3/include/experimental/bits/simd_x86.h
+++ b/libstdc++-v3/include/experimental/bits/simd_x86.h
@@ -510,12 +510,14 @@  _S_converts_via_decomposition()
   using _CommonImplBuiltin::_S_store;
 
   template <typename _Tp, size_t _Np>
-    _GLIBCXX_SIMD_INTRINSIC static void
+    _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_store(_SimdWrapper<_Tp, _Np> __x, void* __addr)
     {
       constexpr size_t _Bytes = _Np * sizeof(_Tp);
 
-      if constexpr ((_Bytes & (_Bytes - 1)) != 0 && __have_avx512bw_vl)
+      if (__builtin_is_constant_evaluated())
+	_CommonImplBuiltin::_S_store(__x, __addr);
+      else if constexpr ((_Bytes & (_Bytes - 1)) != 0 && __have_avx512bw_vl)
 	{
 	  const auto __v = __to_intrin(__x);
 
@@ -581,7 +583,9 @@  static_assert(
     _GLIBCXX_SIMD_INTRINSIC static constexpr void
     _S_store_bool_array(const _BitMask<_Np, _Sanitized> __x, bool* __mem)
     {
-      if constexpr (__have_avx512bw_vl) // don't care for BW w/o VL
+      if (__builtin_is_constant_evaluated())
+	_CommonImplBuiltin::_S_store_bool_array(__x, __mem);
+      else if constexpr (__have_avx512bw_vl) // don't care for BW w/o VL
 	_S_store<_Np>(1 & __vector_bitcast<_UChar, _Np>(
 			    [=]() constexpr _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA {
 			      if constexpr (_Np <= 16)
@@ -2319,14 +2323,14 @@  _S_equal_to(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
 	  } // }}}
 	else if (__builtin_is_constant_evaluated())
 	  return _Base::_S_equal_to(__x, __y);
-	else if constexpr (sizeof(__x) == 8) // {{{
+	else if constexpr (sizeof(__x) == 8)
 	  {
 	    const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
 				== __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
-	    _MaskMember<_Tp> __r64;
+	    _MaskMember<_Tp> __r64{};
 	    __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
 	    return __r64;
-	  } // }}}
+	  }
 	else
 	  return _Base::_S_equal_to(__x, __y);
       }
@@ -2397,7 +2401,7 @@  _S_not_equal_to(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
 	  {
 	    const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
 				!= __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
-	    _MaskMember<_Tp> __r64;
+	    _MaskMember<_Tp> __r64{};
 	    __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
 	    return __r64;
 	  }
@@ -2505,7 +2509,7 @@  _S_less(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
 	  {
 	    const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
 				< __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
-	    _MaskMember<_Tp> __r64;
+	    _MaskMember<_Tp> __r64{};
 	    __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
 	    return __r64;
 	  }
@@ -2613,7 +2617,7 @@  _S_less_equal(_SimdWrapper<_Tp, _Np> __x, _SimdWrapper<_Tp, _Np> __y)
 	  {
 	    const auto __r128 = __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__x)
 				<= __vector_bitcast<_Tp, 16 / sizeof(_Tp)>(__y);
-	    _MaskMember<_Tp> __r64;
+	    _MaskMember<_Tp> __r64{};
 	    __builtin_memcpy(&__r64._M_data, &__r128, sizeof(__r64));
 	    return __r64;
 	  }
@@ -4409,7 +4413,19 @@  _S_broadcast(bool __x)
       _S_load(const bool* __mem)
       {
 	static_assert(is_same_v<_Tp, __int_for_sizeof_t<_Tp>>);
-	if constexpr (__have_avx512bw)
+	if (__builtin_is_constant_evaluated())
+	  {
+	    if constexpr (__is_avx512_abi<_Abi>())
+	      {
+		_MaskMember<_Tp> __r{};
+		for (size_t __i = 0; __i < _S_size<_Tp>; ++__i)
+		  __r._M_data |= _ULLong(__mem[__i]) << __i;
+		return __r;
+	      }
+	    else
+	      return _Base::template _S_load<_Tp>(__mem);
+	  }
+	else if constexpr (__have_avx512bw)
 	  {
 	    const auto __to_vec_or_bits
 	      = [](auto __bits) _GLIBCXX_SIMD_ALWAYS_INLINE_LAMBDA -> decltype(auto) {
@@ -4677,10 +4693,12 @@  _mm256_cvtepi8_epi64(
 
     // _S_store {{{2
     template <typename _Tp, size_t _Np>
-      _GLIBCXX_SIMD_INTRINSIC static void
+      _GLIBCXX_SIMD_INTRINSIC static constexpr void
       _S_store(_SimdWrapper<_Tp, _Np> __v, bool* __mem) noexcept
       {
-	if constexpr (__is_avx512_abi<_Abi>())
+	if (__builtin_is_constant_evaluated())
+	  _Base::_S_store(__v, __mem);
+	else if constexpr (__is_avx512_abi<_Abi>())
 	  {
 	    if constexpr (__have_avx512bw_vl)
 	      _CommonImplX86::_S_store<_Np>(
@@ -4762,7 +4780,7 @@  _mm512_mask_cvtepi32_storeu_epi8(
 	    if constexpr (_Np <= 4 && sizeof(_Tp) == 8)
 	      {
 		auto __k = __intrin_bitcast<__m256i>(__to_intrin(__v));
-		int __bool4;
+		int __bool4{};
 		if constexpr (__have_avx2)
 		  __bool4 = _mm256_movemask_epi8(__k);
 		else
@@ -4846,7 +4864,9 @@  _S_logical_and(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>&
       {
 	if constexpr (is_same_v<_Tp, bool>)
 	  {
-	    if constexpr (__have_avx512dq && _Np <= 8)
+	    if (__builtin_is_constant_evaluated())
+	      return __x._M_data & __y._M_data;
+	    else if constexpr (__have_avx512dq && _Np <= 8)
 	      return _kand_mask8(__x._M_data, __y._M_data);
 	    else if constexpr (_Np <= 16)
 	      return _kand_mask16(__x._M_data, __y._M_data);
@@ -4867,7 +4887,9 @@  _S_logical_or(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& _
       {
 	if constexpr (is_same_v<_Tp, bool>)
 	  {
-	    if constexpr (__have_avx512dq && _Np <= 8)
+	    if (__builtin_is_constant_evaluated())
+	      return __x._M_data | __y._M_data;
+	    else if constexpr (__have_avx512dq && _Np <= 8)
 	      return _kor_mask8(__x._M_data, __y._M_data);
 	    else if constexpr (_Np <= 16)
 	      return _kor_mask16(__x._M_data, __y._M_data);
@@ -4888,7 +4910,9 @@  _S_bit_not(const _SimdWrapper<_Tp, _Np>& __x)
       {
 	if constexpr (is_same_v<_Tp, bool>)
 	  {
-	    if constexpr (__have_avx512dq && _Np <= 8)
+	    if (__builtin_is_constant_evaluated())
+	      return __x._M_data ^ _Abi::template __implicit_mask_n<_Np>();
+	    else if constexpr (__have_avx512dq && _Np <= 8)
 	      return _kandn_mask8(__x._M_data,
 				  _Abi::template __implicit_mask_n<_Np>());
 	    else if constexpr (_Np <= 16)
@@ -4913,7 +4937,9 @@  _S_bit_and(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
       {
 	if constexpr (is_same_v<_Tp, bool>)
 	  {
-	    if constexpr (__have_avx512dq && _Np <= 8)
+	    if (__builtin_is_constant_evaluated())
+	      return __x._M_data & __y._M_data;
+	    else if constexpr (__have_avx512dq && _Np <= 8)
 	      return _kand_mask8(__x._M_data, __y._M_data);
 	    else if constexpr (_Np <= 16)
 	      return _kand_mask16(__x._M_data, __y._M_data);
@@ -4934,7 +4960,9 @@  _S_bit_or(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
       {
 	if constexpr (is_same_v<_Tp, bool>)
 	  {
-	    if constexpr (__have_avx512dq && _Np <= 8)
+	    if (__builtin_is_constant_evaluated())
+	      return __x._M_data | __y._M_data;
+	    else if constexpr (__have_avx512dq && _Np <= 8)
 	      return _kor_mask8(__x._M_data, __y._M_data);
 	    else if constexpr (_Np <= 16)
 	      return _kor_mask16(__x._M_data, __y._M_data);
@@ -4955,7 +4983,9 @@  _S_bit_xor(const _SimdWrapper<_Tp, _Np>& __x, const _SimdWrapper<_Tp, _Np>& __y)
       {
 	if constexpr (is_same_v<_Tp, bool>)
 	  {
-	    if constexpr (__have_avx512dq && _Np <= 8)
+	    if (__builtin_is_constant_evaluated())
+	      return __x._M_data ^ __y._M_data;
+	    else if constexpr (__have_avx512dq && _Np <= 8)
 	      return _kxor_mask8(__x._M_data, __y._M_data);
 	    else if constexpr (_Np <= 16)
 	      return _kxor_mask16(__x._M_data, __y._M_data);
diff --git a/libstdc++-v3/testsuite/experimental/simd/pr109261_constexpr_simd.cc b/libstdc++-v3/testsuite/experimental/simd/pr109261_constexpr_simd.cc
new file mode 100644
index 00000000000..d1bfea7a794
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/simd/pr109261_constexpr_simd.cc
@@ -0,0 +1,92 @@ 
+// { 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>();
+}