[gcc r17-3428] libstdc++: Make internal bit manipulation functions available in C++11.

Tomasz Kaminski via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <20260819144120.0875F4B9DB5C__40469.7664476529$1787150486$gmane$org@sourceware.org>
https://gcc.gnu.org/g:c092571209a0cc163374adc156a4fb179b27942e

commit r17-3428-gc092571209a0cc163374adc156a4fb179b27942e
Author: Tomasz Kamiński <[email protected]>
Date:   Wed Aug 5 10:11:23 2026 +0200

    libstdc++: Make internal bit manipulation functions available in C++11.
    
    For __countl_zero, __countr_zero, __popcount we split defintions
    using generic builtin (constexpr in C++11), and typed-builtin (constexpr
    since C++14). The __countl_one, __countr_one and __has_single bit, that
    are implemented with single return, as also left constexpr since C++11.
    
    Specializations of __countl_zero, __countr_zero, __popcount and __bit_width
    are provided for __rand_unit128. Using template specializations instead
    of separate overloads, allow them to be selected by __countl_one, and
    other functions that are implemented in terms of above. Despite being
    implemented in terms of __countl_zero, __bit_width is specialized to
    avoid dependency on __gnu_cxx::__int_traits.
    
    The implementation of __bit_floor uses (std::__bit_width(__x) - 1) instead
    of (_Nd - std::__countl_zero((_Tp)(__x >> 1)). This provide supports by
    __rand_uint128 by using new overload. For that type __bit_width(__x) -1,
    is more optimal that __bit_width(__x >> 1).
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/random.h (std::__rotr, std::__rotl, std::__bit_ceil):
            [__cplusplus >= 201103L]: Define as _GLIBCXX14_CONSTEXPR.
            (std::__countl_zero, std::__countr_zero, std::__popcount)
            [__cplusplus >= 201103L]: Split implementation using generic
            builtin, define other as _GLIBCXX14_CONSTEXPR.
            (std::__bit_width, std::__bit_floor) [__cplusplus >= 201103L]:
            Modify to use single return statement.
            * include/bits/random.tcc (std::__countl_zero, std::__countr_zero)
            (std::__popcount, std::__bit_width): Define explicit specializations
            for __detail::__rand_uint128.
            * include/std/bit (std::__generate_canonical_pow2)
            (std::__generate_canonical_any): Replace builtins call with
            <bit> function calls.
    
    Reviewed-by: Jonathan Wakely <[email protected]>
    Signed-off-by: Tomasz Kamiński <[email protected]>

Diff:
---
 libstdc++-v3/include/bits/random.h   | 43 ++++++++++++++++++--
 libstdc++-v3/include/bits/random.tcc | 17 +++-----
 libstdc++-v3/include/std/bit         | 79 ++++++++++++++++++++----------------
 3 files changed, 88 insertions(+), 51 deletions(-)

diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h
index b01b92862ccd..cfec087f0cd2 100644
--- a/libstdc++-v3/include/bits/random.h
+++ b/libstdc++-v3/include/bits/random.h
@@ -31,6 +31,7 @@
 #ifndef _RANDOM_H
 #define _RANDOM_H 1
 
+#include <bit>     // std::__bit_width
 #include <vector>
 #include <bits/ios_base.h>
 #include <bits/uniform_int_dist.h>
@@ -68,13 +69,13 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
 #endif
 
   /// @cond undocumented
-  // Implementation-space details.
-  namespace __detail
-  {
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wc++17-extensions"
 
 #ifndef __SIZEOF_INT128__
+  // Implementation-space details.
+  namespace __detail
+  {
     // Emulate 128-bit integer type, for the arithmetic ops used in <random>.
     // The __detail::__mod function needs: (type(a) * x + c) % m.
     // std::philox_engine needs multiplication and bitwise ops.
@@ -522,8 +523,42 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
       uint64_t _M_hi = 0;
       uint64_t _M_lo = 0;
     };
-#endif // ! __SIZEOF_INT128__
+  } // namespace __detail
+
+  template<>
+    constexpr int
+    __countl_zero(__detail::__rand_uint128 __val) noexcept
+    {
+      return __val._M_hi ? std::__countl_zero(__val._M_hi)
+			 : std::__countl_zero(__val._M_lo) + 64;
+    }
 
+  template<>
+    constexpr int
+    __countr_zero(__detail::__rand_uint128 __val) noexcept
+    {
+      return __val._M_lo ? std::__countr_zero(__val._M_lo)
+			 : std::__countr_zero(__val._M_hi) + 64;
+    }
+
+  template<>
+    constexpr int
+    __popcount(__detail::__rand_uint128 __val) noexcept
+    {
+      return std::__popcount(__val._M_hi) + std::__popcount(__val._M_lo);
+    }
+
+  template<>
+    constexpr int
+    __bit_width(__detail::__rand_uint128 __val) noexcept
+    {
+      return __val._M_hi ? std::__bit_width(__val._M_hi) + 64
+			 : std::__bit_width(__val._M_lo);
+    }
+
+#endif // ! __SIZEOF_INT128__
+  namespace __detail
+  {
     template<typename _UIntType, size_t __w,
 	     bool = __w < static_cast<size_t>
 			  (std::numeric_limits<_UIntType>::digits)>
diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
index 9690fdf7a8f9..b2b18e66f5f1 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -3706,10 +3706,10 @@ namespace __detail
       // Commented-out assignments below are of values specified in
       //  the Standard, but not used here for reasons noted.
       // r = 2;  // Redundant, we only support radix 2.
-      using _Rng = decltype(_Urbg::max());
-      const _Rng __rng_range_less_1 = _Urbg::max() - _Urbg::min();
+      using _URng = typename make_unsigned<decltype(_Urbg::max())>::type;
+      const _URng __rng_range_less_1(_Urbg::max() - _Urbg::min());
       // R = _UInt(__rng_range_less_1) + 1;  // May wrap to 0.
-      const auto __log2_R = __builtin_popcountg(__rng_range_less_1);
+      const auto __log2_R = std::__popcount(__rng_range_less_1);
       const auto __log2_uint_max = sizeof(_UInt) * __CHAR_BIT__;
       // rd = _UInt(1) << __d;  // Could overflow, UB.
       const unsigned __k = (__d + __log2_R - 1) / __log2_R;
@@ -3804,8 +3804,7 @@ namespace __detail
       // Cannot overflow, as _Urbg::max() - _Urbg::min() is not power of
       // two minus one
       constexpr _UIntR __R = _UIntR(_Urbg::max() - _Urbg::min()) + 1;
-      constexpr unsigned __log2R
-	= sizeof(_UIntR) * __CHAR_BIT__ - __builtin_clzg(__R) - 1;
+      constexpr unsigned __log2R = std::__bit_width(__R) - 1;
       // We overstimate number of required bits, by computing
       // m such that m * log2(R) >= d, so:
       // R^m >= (2 ^ log2(R)) ^ m == 2 ^ (log2(R) * m) >= 2^d
@@ -3872,13 +3871,7 @@ namespace __detail
 
 	  // __abits is maximum bit width of the value, that can
 	  // be multiplied by R^l without overflowing 128 bit integer
-	  _GLIBCXX_GEN_CANON_CONST unsigned __bwRl
-#ifndef __SIZEOF_INT128__
-	    = __Rl._M_hi ? 128 - __builtin_clzg(__Rl._M_hi)
-			 : 64 - __builtin_clzg(__Rl._M_lo);
-#else
-	    = 128 - __builtin_clzg(__Rl);
-#endif
+	  _GLIBCXX_GEN_CANON_CONST unsigned __bwRl = std::__bit_width(__Rl);
 
 	  // For __R close to power of two, the actual __k may be smaller than __m,
 	  // and will use less than 128bits, default to two 32 bits chunks.
diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index 6ea0f6eef834..b735044ca18b 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -33,7 +33,7 @@
 #pragma GCC system_header
 #endif
 
-#if __cplusplus >= 201402L
+#if __cplusplus >= 201103L
 
 #include <concepts> // for std::integral
 #include <type_traits>
@@ -157,7 +157,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
 
   template<typename _Tp>
-    constexpr _Tp
+    _GLIBCXX14_CONSTEXPR _Tp
     __rotl(_Tp __x, int __s) noexcept
     {
       constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
@@ -179,7 +179,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    constexpr _Tp
+    _GLIBCXX14_CONSTEXPR _Tp
     __rotr(_Tp __x, int __s) noexcept
     {
       constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
@@ -200,16 +200,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return (__x << -__r) | (__x >> ((_Nd + __r) % _Nd)); // rotl(x, -r)
     }
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_clzg)
   template<typename _Tp>
     constexpr int
     __countl_zero(_Tp __x) noexcept
+    {
+      return __builtin_clzg(__x, __gnu_cxx::__int_traits<_Tp>::__digits);
+    }
+#else
+  template<typename _Tp>
+    _GLIBCXX14_CONSTEXPR int
+    __countl_zero(_Tp __x) noexcept
     {
       using __gnu_cxx::__int_traits;
       constexpr auto _Nd = __int_traits<_Tp>::__digits;
-
-#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_clzg)
-      return __builtin_clzg(__x, _Nd);
-#else
       if (__x == 0)
         return _Nd;
 
@@ -247,8 +251,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  unsigned long long __low = __x & __max_ull;
 	  return (_Nd - _Nd_ull) + __builtin_clzll(__low);
 	}
-#endif
     }
+#endif
 
   template<typename _Tp>
     constexpr int
@@ -257,16 +261,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return std::__countl_zero<_Tp>((_Tp)~__x);
     }
 
-  template<typename _Tp>
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_ctzg)
+   template<typename _Tp>
     constexpr int
     __countr_zero(_Tp __x) noexcept
+    {
+      return __builtin_ctzg(__x, __gnu_cxx::__int_traits<_Tp>::__digits);
+    } 
+#else
+  template<typename _Tp>
+    _GLIBCXX14_CONSTEXPR int
+    __countr_zero(_Tp __x) noexcept
     {
       using __gnu_cxx::__int_traits;
       constexpr auto _Nd = __int_traits<_Tp>::__digits;
-
-#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_ctzg)
-      return __builtin_ctzg(__x, _Nd);
-#else
       if (__x == 0)
         return _Nd;
 
@@ -292,8 +300,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  unsigned long long __high = __x >> _Nd_ull;
 	  return __builtin_ctzll(__high) + _Nd_ull;
 	}
-#endif
     }
+#endif
 
   template<typename _Tp>
     constexpr int
@@ -302,13 +310,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return std::__countr_zero((_Tp)~__x);
     }
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_popcountg)
   template<typename _Tp>
     constexpr int
     __popcount(_Tp __x) noexcept
     {
-#if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_popcountg)
       return __builtin_popcountg(__x);
+    }
 #else
+  template<typename _Tp>
+    _GLIBCXX14_CONSTEXPR int
+    __popcount(_Tp __x) noexcept
+    {
       using __gnu_cxx::__int_traits;
       constexpr auto _Nd = __int_traits<_Tp>::__digits;
 
@@ -332,16 +345,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  unsigned long long __high = __x >> _Nd_ull;
 	  return __builtin_popcountll(__low) + __builtin_popcountll(__high);
 	}
-#endif
     }
+#endif
 
   template<typename _Tp>
     constexpr bool
     __has_single_bit(_Tp __x) noexcept
     { return std::__popcount(__x) == 1; }
 
+  template<typename _Tp>
+    constexpr int
+    __bit_width(_Tp __x) noexcept
+    {
+      return __gnu_cxx::__int_traits<_Tp>::__digits - std::__countl_zero(__x);
+    }
+
   template<typename _Tp>
     constexpr _Tp
+    __bit_floor(_Tp __x) noexcept
+    {
+      return (__x == 0) ? (_Tp)0 : ((_Tp)1u << (std::__bit_width(__x) - 1));
+    }
+
+  template<typename _Tp>
+    _GLIBCXX14_CONSTEXPR _Tp
     __bit_ceil(_Tp __x) noexcept
     {
       using __gnu_cxx::__int_traits;
@@ -372,24 +399,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return (_Tp)1u << __shift_exponent;
     }
 
-  template<typename _Tp>
-    constexpr _Tp
-    __bit_floor(_Tp __x) noexcept
-    {
-      constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
-      if (__x == 0)
-        return 0;
-      return (_Tp)1u << (_Nd - std::__countl_zero((_Tp)(__x >> 1)));
-    }
-
-  template<typename _Tp>
-    constexpr int
-    __bit_width(_Tp __x) noexcept
-    {
-      constexpr auto _Nd = __gnu_cxx::__int_traits<_Tp>::__digits;
-      return _Nd - std::__countl_zero(__x);
-    }
-
 #pragma GCC diagnostic pop
   /// @endcond
 
@@ -499,5 +508,5 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
-#endif // C++14
+#endif // C++11
 #endif // _GLIBCXX_BIT
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.