https://gcc.gnu.org/g:66a144b16aa9034350d6294abbbe06559143da9d

commit r17-5183-g66a144b16aa9034350d6294abbbe06559143da9d
Author: Jakub Jelinek <[email protected]>
Date:   Wed Oct 14 11:21:50 2026 +0200

    libstdc++: Implement C++29 P3104R6 - Bit permutations
    
    The following patch implements the
    C++29 P3104R6 - Bit permutations
    paper.
    
    bit_repeat comes first in the patch because I'm using it in the bit_reverse
    fallback.
    
    bit_reverse tested both without the
    https://gcc.gnu.org/pipermail/gcc-patches/2026-September/731814.html
    patch (where __builtin_bitreverseg isn't used, as gcc doesn't announce it),
    also tested just the fallback of fallback variant by adding 0 && to the
    if constexpr condition, and with that patch.
    
    bit_compress and bit_expand written according to Hacker's Delight (only
    clang implements the two builtins), and testcases for those double checked
    against clang++'s __builtin_elementwise_{pext,pdep}.
    The implementation of all the functions is fairly optimized but I'm not
    using any x86 nor aarch64 intrinsics to optimize those even more, I think
    it is better when we implement builtins for this and handle such details on
    the compiler side.
    
    I've tried to write the tests so that it would eventually work also with
    _BitInt if voted in and these would be enabled for those too, but haven't
    actually tested that; __builtin_bitreverseg is known to work fine for
    _BitInt, the others would likely work too but not efficiently for larger
    precisions.
    
    2026-10-14  Jakub Jelinek  <[email protected]>
    
            P3104R6
            * include/bits/version.def: Implement C++29 P3104R6 - Bit 
permutations.
            (bitops): Change value from 202606 to 202607.
            * include/bits/version.h: Regenerate.
            * include/std/bit (std::bit_repeat, std::bit_reverse,
            std::bit_compress, std::bit_expand): New function templates for 
C++29.
            * src/c++23/std.cc.in (std::bit_repeat, std::bit_reverse,
            std::bit_compress, std::bit_expand): New exports for C++29.
            * testsuite/26_numerics/bit/bit.permute/bit_reverse.cc: New test.
            * testsuite/26_numerics/bit/bit.permute/bit_repeat.cc: New test.
            * testsuite/26_numerics/bit/bit.permute/bit_compress.cc: New test.
            * testsuite/26_numerics/bit/bit.permute/bit_expand.cc: New test.
    
    Reviewed-by: Jonathan Wakely <[email protected]>

Diff:
---
 libstdc++-v3/include/bits/version.def              |   5 +-
 libstdc++-v3/include/bits/version.h                |   4 +-
 libstdc++-v3/include/std/bit                       | 117 +++++++++++++++++++
 libstdc++-v3/src/c++23/std.cc.in                   |   6 +
 .../26_numerics/bit/bit.permute/bit_compress.cc    |  87 ++++++++++++++
 .../26_numerics/bit/bit.permute/bit_expand.cc      |  87 ++++++++++++++
 .../26_numerics/bit/bit.permute/bit_repeat.cc      | 125 +++++++++++++++++++++
 .../26_numerics/bit/bit.permute/bit_reverse.cc     |  73 ++++++++++++
 8 files changed, 501 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 9c523581c65a..170309c96999 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -890,10 +890,13 @@ ftms = {
 
 ftms = {
   name = bitops;
+  // 202606 P3793R2 Better shifting
+  // 202607 P3104R6 Bit permutations
   values = {
-    v = 202606;
+    v = 202607;
     cxxmin = 29;
   };
+  // 201907 P0553R4 Bit operations
   values = {
     v = 201907;
     cxxmin = 20;
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index e0003054af68..ce20b41caa2d 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -990,9 +990,9 @@
 
 #if !defined(__cpp_lib_bitops)
 # if (__cplusplus >  202603L)
-#  define __glibcxx_bitops 202606L
+#  define __glibcxx_bitops 202607L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_bitops)
-#   define __cpp_lib_bitops 202606L
+#   define __cpp_lib_bitops 202607L
 #  endif
 # elif (__cplusplus >= 202002L)
 #  define __glibcxx_bitops 201907L
diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index 46fa8b65032c..51910fda1c10 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -515,6 +515,123 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return std::__bit_width(__x); }
 #endif // defined (__cpp_lib_int_pow2)
 
+#if __cpp_lib_bitops >= 202607L // >= C++29
+  // [bit.permute], permutation
+  template<__unsigned_integer _Tp>
+    [[nodiscard]] constexpr _Tp
+    bit_repeat(_Tp __x, int __l)
+    {
+      __glibcxx_assert( __l > 0 );
+      constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+      if (__l >= _Nd)
+       return __x;
+      __x &= ((_Tp)1 << __l) - 1;
+      do
+       {
+         __x |= __x << __l;
+         __l <<= 1;
+       }
+      while (__l < _Nd);
+      return __x;
+    }
+
+  template<__unsigned_integer _Tp>
+    [[nodiscard]] constexpr _Tp
+    bit_reverse(_Tp __x) noexcept
+    {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_bitreverseg)
+      return __builtin_bitreverseg(__x);
+#else
+      constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+      if constexpr (_Nd % __CHAR_BIT__ == 0 && __CHAR_BIT__ == 8)
+       {
+         __x = std::byteswap(__x);
+         constexpr auto __m1 = std::bit_repeat<_Tp>(15, 8);
+         constexpr auto __m2 = std::bit_repeat<_Tp>(3, 4);
+         constexpr auto __m3 = std::bit_repeat<_Tp>(1, 2);
+         __x = ((__x >> 4) & __m1) | ((__x & __m1) << 4);
+         __x = ((__x >> 2) & __m2) | ((__x & __m2) << 2);
+         __x = ((__x >> 1) & __m3) | ((__x & __m3) << 1);
+         return __x;
+       }
+      else
+       {
+         _Tp __r = 0;
+         for (int __i = 0; __i < _Nd; ++__i)
+           {
+             __r <<= 1;
+             __r |= (__x & 1);
+             __x >>= 1;
+           }
+         return __r;
+       }
+#endif
+    }
+
+  template<__unsigned_integer _Tp>
+    [[nodiscard]] constexpr _Tp
+    bit_compress(_Tp __x, _Tp __m) noexcept
+    {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_elementwise_pext)
+      return __builtin_elementwise_pext(__x, __m);
+#else
+      constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+      // Based on "Compress, or Generalized Extract" in Hacker's Delight
+      __x &= __m;
+      _Tp __mk = ~__m << 1;
+      for (int __i = 1; __i < _Nd; __i <<= 1)
+       {
+         _Tp __mp = __mk;
+         for (int __j = 1; __j < _Nd; __j <<= 1)
+           __mp ^= __mp << __j;
+         _Tp __mv = __mp & __m;
+         __m = (__m ^ __mv) | (__mv >> __i);
+         _Tp __t = __x & __mv;
+         __x = (__x ^ __t) | (__t >> __i);
+         __mk = __mk & ~__mp;
+       }
+      return __x;
+#endif
+    }
+
+  template<__unsigned_integer _Tp>
+    [[nodiscard]] constexpr _Tp
+    bit_expand(_Tp __x, _Tp __m) noexcept
+    {
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_elementwise_pdep)
+      return __builtin_elementwise_pdep(__x, __m);
+#else
+      constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
+      if constexpr (_Nd == 1)
+       return __x & __m;
+      constexpr auto __log2_Nd
+       = _Nd == 1 ? 1 : (__gnu_cxx::__int_traits<unsigned>::__digits
+                         - std::__countl_zero<unsigned>(_Nd - 1));
+      // Based on "Expand, or Generalized Insert" in Hacker's Delight
+      _Tp __m0 = __m;
+      _Tp __mk = ~__m << 1;
+      _Tp __array[__log2_Nd];
+      for (int __i = 0; __i < __log2_Nd; __i++)
+       {
+         _Tp __mp = __mk;
+         for (int __j = 1; __j < _Nd; __j <<= 1)
+           __mp ^= __mp << __j;
+         _Tp __mv = __mp & __m;
+         __array[__i] = __mv;
+         __m = (__m ^ __mv) | (__mv >> (_Tp(1) << __i));
+         __mk = __mk & ~__mp;
+       }
+      for (int __i = __log2_Nd - 1; __i >= 0; __i--)
+       {
+         _Tp __mv = __array[__i];
+         _Tp __t = __x << (_Tp(1) << __i);
+         __x = (__x & ~__mv) | (__t & __mv);
+       }
+      return __x & __m0;
+#endif
+    }
+#endif // __cpp_lib_bitops >= 202607L
+
 #ifdef __cpp_lib_endian // C++ >= 20
 
   /// Byte order constants
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index 928281699db9..d05902466d97 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -699,6 +699,12 @@ export namespace std
   using std::shl;
   using std::shr;
 #endif
+#if __cpp_lib_bitops >= 202607L // >= C++29
+  using std::bit_reverse;
+  using std::bit_repeat;
+  using std::bit_compress;
+  using std::bit_expand;
+#endif
 }
 
 // 22.9 <bitset>
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_compress.cc 
b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_compress.cc
new file mode 100644
index 000000000000..130bf6cfea82
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_compress.cc
@@ -0,0 +1,87 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_compress(x, x))
+{
+  constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+  static_assert( std::bit_compress(UInt(0), UInt(0)) == UInt(0) );
+  static_assert( std::bit_compress(UInt(0x123456789abcdefull), UInt(0)) == 
UInt(0) );
+  static_assert( std::bit_compress(UInt(0x123456789abcdefull), UInt(~UInt(0))) 
== UInt(0x123456789abcdefull) );
+  static_assert( std::bit_compress(UInt(0), UInt(0x123456789abcdefull)) == 
UInt(0) );
+  static_assert( std::bit_compress(UInt(~UInt(0)), UInt(~UInt(0))) == 
UInt(~UInt(0)) );
+  static_assert( std::bit_compress(UInt(~UInt(0)), UInt(0x123456789abcdefull)) 
== (UInt(1) << std::popcount(UInt(0x123456789abcdefull))) - 1 );
+  static_assert( digits < 16 || digits % 2 != 0 || 
std::bit_compress(std::bit_repeat(UInt(0x1234), 16), std::bit_repeat(UInt(1), 
2)) == std::bit_repeat(UInt(0x46), 8) >> (digits / 2) );
+  static_assert( digits < 16 || digits % 2 != 0 || 
std::bit_compress(std::bit_repeat(UInt(0x1234), 16), std::bit_repeat(UInt(2), 
2)) == std::bit_repeat(UInt(0x14), 8) >> (digits / 2) );
+  static_assert( digits < 8 || std::bit_compress(UInt(0xff), UInt(0xff)) == 
UInt(0xff) );
+  static_assert( digits < 8 || std::bit_compress(UInt(0xff), UInt(0x0f)) == 
UInt(0x0f) );
+  static_assert( digits < 8 || std::bit_compress(UInt(0xff), UInt(0xf0)) == 
UInt(0x0f) );
+  static_assert( digits % 2 != 0 || std::bit_compress(std::bit_repeat(UInt(2), 
2), std::bit_repeat(UInt(0xc), 4)) == std::bit_repeat(UInt(0x2), 2) >> (digits 
/ 2) );
+  static_assert( digits % 2 != 0 || std::bit_compress(UInt(~UInt(0)), 
std::bit_repeat(UInt(2), 2)) == UInt(~UInt(0)) >> (digits / 2) );
+  if constexpr (digits >= 8)
+    {
+      static_assert( std::bit_compress(UInt(0xd4), UInt(0xbf)) == UInt(0x54) );
+      static_assert( std::bit_compress(UInt(0x66), UInt(0x1d)) == UInt(0x02) );
+    }
+  if constexpr (digits >= 16)
+    {
+      static_assert( std::bit_compress(UInt(0xebd4u), UInt(0x93bfu)) == 
UInt(0x05d4) );
+      static_assert( std::bit_compress(UInt(0xa166u), UInt(0x001du)) == 
UInt(2) );
+    }
+  if constexpr (digits >= 32)
+    {
+      static_assert( std::bit_compress(UInt(0x9daeebd4u), UInt(0xad8793bfu)) 
== UInt(0xbf5d4u) );
+      static_assert( std::bit_compress(UInt(0x979ba166u), UInt(0x54ca001du)) 
== UInt(0x3b2u) );
+    }
+  if constexpr (digits >= 64)
+    {
+      static_assert( std::bit_compress(UInt(0x5bd30f069daeebd4ull), 
UInt(0x64f9a89bad8793bfull)) == UInt(0x13522bf5d4ull) );
+      static_assert( std::bit_compress(UInt(0xb5672499979ba166ull), 
UInt(0xd315782354ca001dull)) == UInt(0x2ad0bb2ull) );
+    }
+  return x;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_compress(T) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+  
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_expand.cc 
b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_expand.cc
new file mode 100644
index 000000000000..0e510dfea99c
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_expand.cc
@@ -0,0 +1,87 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_expand(x, x))
+{
+  constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+  static_assert( std::bit_expand(UInt(0), UInt(0)) == UInt(0) );
+  static_assert( std::bit_expand(UInt(0x123456789abcdefull), UInt(0)) == 
UInt(0) );
+  static_assert( std::bit_expand(UInt(0x123456789abcdefull), UInt(~UInt(0))) 
== UInt(0x123456789abcdefull) );
+  static_assert( std::bit_expand(UInt(0), UInt(0x123456789abcdefull)) == 
UInt(0) );
+  static_assert( std::bit_expand(UInt(~UInt(0)), UInt(~UInt(0))) == 
UInt(~UInt(0)) );
+  static_assert( std::bit_expand(UInt((UInt(1) << 
std::popcount(UInt(0x123456789abcdefull))) - 1), UInt(0x123456789abcdefull)) == 
UInt(0x123456789abcdefull) );
+  static_assert( digits < 16 || std::bit_expand(std::bit_repeat(UInt(0x46), 
8), std::bit_repeat(UInt(1), 2)) == std::bit_repeat(UInt(0x1014), 16) );
+  static_assert( digits < 16 || std::bit_expand(std::bit_repeat(UInt(0x14), 
8), std::bit_repeat(UInt(2), 2)) == std::bit_repeat(UInt(0x0220), 16) );
+  static_assert( digits < 8 || std::bit_expand(UInt(0xff), UInt(0xff)) == 
UInt(0xff) );
+  static_assert( digits < 8 || std::bit_expand(UInt(0x0f), UInt(0xff)) == 
UInt(0x0f) );
+  static_assert( digits < 8 || std::bit_expand(UInt(0x0f), UInt(0xf0)) == 
UInt(0xf0) );
+  static_assert( std::bit_expand(std::bit_repeat(UInt(2), 2), 
std::bit_repeat(UInt(0xc), 4)) == std::bit_repeat(UInt(0x8), 4) );
+  static_assert( std::bit_expand(std::bit_repeat(UInt(0x0f), 8), 
std::bit_repeat(UInt(2), 2)) == std::bit_repeat(UInt(0xaa), 16) );
+  if constexpr (digits >= 8)
+    {
+      static_assert( std::bit_expand(UInt(0xd4), UInt(0xbf)) == UInt(0x94) );
+      static_assert( std::bit_expand(UInt(0x66), UInt(0x1d)) == UInt(0x0c) );
+    }
+  if constexpr (digits >= 16)
+    {
+      static_assert( std::bit_expand(UInt(0xebd4u), UInt(0x93bfu)) == 
UInt(0x1394) );
+      static_assert( std::bit_expand(UInt(0xa166u), UInt(0x001du)) == 
UInt(0xc) );
+    }
+  if constexpr (digits >= 32)
+    {
+      static_assert( std::bit_expand(UInt(0x9daeebd4u), UInt(0xad8793bfu)) == 
UInt(0xa9851394u) );
+      static_assert( std::bit_expand(UInt(0x979ba166u), UInt(0x54ca001du)) == 
UInt(0x448000cu) );
+    }
+  if constexpr (digits >= 64)
+    {
+      static_assert( std::bit_expand(UInt(0x5bd30f069daeebd4ull), 
UInt(0x64f9a89bad8793bfull)) == UInt(0x4a1a092a9851394ull) );
+      static_assert( std::bit_expand(UInt(0xb5672499979ba166ull), 
UInt(0xd315782354ca001dull)) == UInt(0xd01470200448000cull) );
+    }
+  return x;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_expand(T) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+  
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_repeat.cc 
b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_repeat.cc
new file mode 100644
index 000000000000..c6270f826121
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_repeat.cc
@@ -0,0 +1,125 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+// Detect whether std::bit_repeat(T(0), N) is a constant expression.
+template<typename T, auto N, typename = void>
+  struct bit_repeat_valid
+  : std::false_type { };
+
+template<typename T, auto N>
+  struct bit_repeat_valid<T, N, std::void_t<char[(std::bit_repeat(T(0), N) == 
T(0))]>>
+  : std::true_type { };
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_repeat(x, 1))
+{
+  constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+  static_assert( std::bit_repeat(UInt(0), 1) == UInt(0) );
+  static_assert( std::bit_repeat(UInt(0), digits) == UInt(0) );
+  static_assert( std::bit_repeat(UInt(0), digits * 6) == UInt(0) );
+  static_assert( std::bit_repeat(UInt(~UInt(0)), 1) == UInt(~UInt(0)) );
+  static_assert( std::bit_repeat(UInt(~UInt(0)), digits) == UInt(~UInt(0)) );
+  static_assert( std::bit_repeat(UInt(~UInt(0)), digits * 6) == UInt(~UInt(0)) 
);
+  static_assert( std::bit_repeat(UInt(1), 1) == UInt(~UInt(0)) );
+  static_assert( std::bit_repeat(UInt(~UInt(1)), 1) == UInt(0) );
+  static_assert( std::bit_repeat(std::bit_repeat(UInt(0x0123456789abcdefull), 
3), 3)
+                == std::bit_repeat(UInt(0x0123456789abcdefull), 3) );
+  if constexpr (std::numeric_limits<UInt>::digits >= 8)
+    {
+      static_assert( (std::bit_repeat<UInt>(0x34, 3) & UInt(0xff)) == 0x24u );
+      static_assert( (std::bit_repeat<UInt>(0x71, 2) & UInt(0xff)) == 0x55u );
+      static_assert( (std::bit_repeat<UInt>(0xf2, 2) & UInt(0xff)) == 0xaau );
+      static_assert( (std::bit_repeat<UInt>(0xb3, 5) & UInt(0xff)) == 0x73u );
+      static_assert( (std::bit_repeat<UInt>(0xb3, 8) & UInt(0xff)) == 0xb3u );
+    }
+  if constexpr (std::numeric_limits<UInt>::digits >= 16)
+    {
+      static_assert( (std::bit_repeat<UInt>(0x1734, 3) & UInt(0xffff)) == 
0x4924u );
+      static_assert( (std::bit_repeat<UInt>(0x2071, 2) & UInt(0xffff)) == 
0x5555u );
+      static_assert( (std::bit_repeat<UInt>(0x52f2, 2) & UInt(0xffff)) == 
0xaaaau );
+      static_assert( (std::bit_repeat<UInt>(0x07b3, 5) & UInt(0xffff)) == 
0xce73u );
+      static_assert( (std::bit_repeat<UInt>(0x21b3, 8) & UInt(0xffff)) == 
0xb3b3u );
+      static_assert( (std::bit_repeat<UInt>(0xa2b3u, 16) & UInt(0xffff)) == 
0xa2b3u );
+    }
+  if constexpr (std::numeric_limits<UInt>::digits >= 32)
+    {
+      static_assert( (std::bit_repeat<UInt>(0x12345634u, 3) & 
UInt(0xffffffffu)) == 0x24924924u );
+      static_assert( (std::bit_repeat<UInt>(0x23456771u, 2) & 
UInt(0xffffffffu)) == 0x55555555u );
+      static_assert( (std::bit_repeat<UInt>(0x345678f2u, 2) & 
UInt(0xffffffffu)) == 0xaaaaaaaau );
+      static_assert( (std::bit_repeat<UInt>(0x456789b3u, 5) & 
UInt(0xffffffffu)) == 0xe739ce73u );
+      static_assert( (std::bit_repeat<UInt>(0x56789ab3u, 8) & 
UInt(0xffffffffu)) == 0xb3b3b3b3u );
+      static_assert( (std::bit_repeat<UInt>(0x6789a2b3u, 16) & 
UInt(0xffffffffu)) == 0xa2b3a2b3u );
+      static_assert( (std::bit_repeat<UInt>(0x2a4dda0eu, 32) & 
UInt(0xffffffffu)) == 0x2a4dda0eu );
+    }
+  if constexpr (std::numeric_limits<UInt>::digits >= 64)
+    {
+      static_assert( (std::bit_repeat<UInt>(0x1122334455667734ull, 3) & 
UInt(0xffffffffffffffffull)) == 0x4924924924924924ull );
+      static_assert( (std::bit_repeat<UInt>(0x2233445566778871ull, 2) & 
UInt(0xffffffffffffffffull)) == 0x5555555555555555ull );
+      static_assert( (std::bit_repeat<UInt>(0x33445566778899f2ull, 2) & 
UInt(0xffffffffffffffffull)) == 0xaaaaaaaaaaaaaaaaull );
+      static_assert( (std::bit_repeat<UInt>(0x445566778899aab3ull, 5) & 
UInt(0xffffffffffffffffull)) == 0x39ce739ce739ce73ull );
+      static_assert( (std::bit_repeat<UInt>(0x5566778899aabbb3ull, 8) & 
UInt(0xffffffffffffffffull)) == 0xb3b3b3b3b3b3b3b3ull );
+      static_assert( (std::bit_repeat<UInt>(0x66778899aabba2b3ull, 16) & 
UInt(0xffffffffffffffffull)) == 0xa2b3a2b3a2b3a2b3ull );
+      static_assert( (std::bit_repeat<UInt>(0x778899aa2a4dda0eull, 32) & 
UInt(0xffffffffffffffffull)) == 0x2a4dda0e2a4dda0eull );
+    }
+  if constexpr (std::numeric_limits<UInt>::digits == 128)
+    {
+      static_assert( std::bit_repeat<UInt>(1, 2)
+                    == (UInt(0x5555555555555555ull) << 64) | 
0x5555555555555555ull );
+      static_assert( std::bit_repeat<UInt>(2, 2)
+                    == (UInt(0xaaaaaaaaaaaaaaaaull) << 64) | 
0xaaaaaaaaaaaaaaaaull );
+    }
+  static_assert( bit_repeat_valid<UInt, 1>() );
+  static_assert( bit_repeat_valid<UInt, 17>() );
+  static_assert( bit_repeat_valid<UInt, digits>() );
+  static_assert( bit_repeat_valid<UInt, digits * 8>() );
+  static_assert( !bit_repeat_valid<UInt, 0>() );
+  static_assert( !bit_repeat_valid<UInt, -1>() );
+  static_assert( !bit_repeat_valid<UInt, -5>() );
+
+  return x;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_repeat(T, N) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+  
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_reverse.cc 
b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_reverse.cc
new file mode 100644
index 000000000000..babb848dbe6e
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/bit/bit.permute/bit_reverse.cc
@@ -0,0 +1,73 @@
+// { dg-do compile { target c++29 } }
+
+#include <bit>
+#include <limits>
+
+template<typename UInt>
+constexpr auto
+test(UInt x)
+-> decltype(std::bit_reverse(x))
+{
+  constexpr unsigned digits = std::numeric_limits<UInt>::digits;
+  static_assert( std::bit_reverse(UInt(0)) == UInt(0) );
+  static_assert( std::bit_reverse(UInt(~UInt(0))) == UInt(~UInt(0)) );
+  static_assert( std::bit_reverse(UInt(1)) == UInt(1) << (digits - 1) );
+  static_assert( std::bit_reverse(UInt(UInt(1) << (digits - 1))) == UInt(1) );
+  if constexpr (std::numeric_limits<UInt>::digits == 8)
+    static_assert( std::bit_reverse<UInt>(0x34u) == 0x2cu );
+  if constexpr (std::numeric_limits<UInt>::digits == 16)
+    static_assert( std::bit_reverse<UInt>(0x1234u) == 0x2c48u );
+  if constexpr (std::numeric_limits<UInt>::digits == 32)
+    static_assert( std::bit_reverse<UInt>(0x01234567u) == 0xe6a2c480u );
+  if constexpr (std::numeric_limits<UInt>::digits == 64)
+    static_assert( std::bit_reverse<UInt>(0x0123456789abcdefull) == 
0xf7b3d591e6a2c480ull );
+  if constexpr (std::numeric_limits<UInt>::digits == 128)
+    static_assert( std::bit_reverse<UInt>((UInt(0x0123456789abcdefull) << 64)
+                                         | 0x2468ace013579bdfull)
+                  == ((UInt(0xfbd9eac807351624ull) << 64)
+                      | 0xf7b3d591e6a2c480ull) );
+  if (std::bit_reverse(std::bit_reverse(x)) == x)
+    return x;
+  return 0;
+}
+
+static_assert( test( (unsigned char)123 ) );
+static_assert( test( (unsigned short)12345 ) );
+static_assert( test( (unsigned int)1234567890 ) );
+static_assert( test( 123456789UL ) );
+static_assert( test( ~123456789ULL ) );
+
+// std::bit_reverse(T) shall not participate in overload resolution
+// unless T is an unsigned integer type.
+struct X { constexpr bool did_not_match() { return true; } };
+constexpr X test(...) { return X{}; }
+static_assert( test( (bool)0 ).did_not_match() );
+static_assert( test( (char)0 ).did_not_match() );
+static_assert( test( (int)0 ).did_not_match() );
+static_assert( test( (char16_t)0 ).did_not_match() );
+static_assert( test( (float)0 ).did_not_match() );
+static_assert( test( (void*)0 ).did_not_match() );
+static_assert( test( X{} ).did_not_match() );
+enum E : unsigned { e };
+static_assert( test( e ).did_not_match() );
+  
+#if !defined(__STRICT_ANSI__) && defined __SIZEOF_INT128__
+static_assert( test( (unsigned __int128)3 ) );
+static_assert( test( (__int128)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_0)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_0)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_0)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_1)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_1)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_1)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_2)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_2)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_2)0 ).did_not_match() );
+#endif
+#if defined(__GLIBCXX_TYPE_INT_N_3)
+static_assert( test( (unsigned __GLIBCXX_TYPE_INT_N_3)1 ) );
+static_assert( test( (__GLIBCXX_TYPE_INT_N_3)0 ).did_not_match() );
+#endif

Reply via email to