[1/2] libstdc++: Expand supported operations for __rand_uint128.
Checks
Commit Message
This patch adds following operations to __rand_uint128:
* explicit operator bool
* operator- with __rand_uint128
* operator* with uint64_t for _M_hi != 0
* operator/ with uint64_t
The division is currently stubbed by converting to __rand_uint128.
When __rand_uint128 is used, the platform does not provide native 128bit
integer types, thus random number generators will return at most 64bit
integer. In consequence, __generate_cannonical_any will use these
overloads when multiplying by result of generator invocation.
libstdc++-v3/ChangeLog:
* include/bits/random.h (__rand_uint128::operator bool):
(__rand_uint128::operator-=(const type& __r))
(__rand_uint128::operator-(type __l, const type& __r)):
Implement.
(__rand_uint128::operator/=(uint64_t __r))
(__rand_uint128::operator/(type __l, uint64_t __r)):
Define by converting to type.
(__rand_uint128::operator*=(const type& __r)): Remove
precondition and handle _M_hi != 0.
---
Tested on x86_64-linux, with following patch.
OK for trunk?
libstdc++-v3/include/bits/random.h | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
Comments
On Tue, 2 Jun 2026 at 15:04, Tomasz Kamiński <tkaminsk@redhat.com> wrote:
>
> This patch adds following operations to __rand_uint128:
> * explicit operator bool
> * operator- with __rand_uint128
> * operator* with uint64_t for _M_hi != 0
> * operator/ with uint64_t
> The division is currently stubbed by converting to __rand_uint128.
>
> When __rand_uint128 is used, the platform does not provide native 128bit
> integer types, thus random number generators will return at most 64bit
> integer. In consequence, __generate_cannonical_any will use these
> overloads when multiplying by result of generator invocation.
>
> libstdc++-v3/ChangeLog:
>
> * include/bits/random.h (__rand_uint128::operator bool):
> (__rand_uint128::operator-=(const type& __r))
> (__rand_uint128::operator-(type __l, const type& __r)):
> Implement.
> (__rand_uint128::operator/=(uint64_t __r))
> (__rand_uint128::operator/(type __l, uint64_t __r)):
> Define by converting to type.
> (__rand_uint128::operator*=(const type& __r)): Remove
> precondition and handle _M_hi != 0.
> ---
> Tested on x86_64-linux, with following patch.
> OK for trunk?
OK
>
> libstdc++-v3/include/bits/random.h | 28 ++++++++++++++++++++++++++--
> 1 file changed, 26 insertions(+), 2 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h
> index a0592a00763..fd7b8b4fb20 100644
> --- a/libstdc++-v3/include/bits/random.h
> +++ b/libstdc++-v3/include/bits/random.h
> @@ -90,6 +90,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> __rand_uint128(const __rand_uint128&) = default;
> __rand_uint128& operator=(const __rand_uint128&) = default;
>
> + constexpr explicit
> + operator bool() const noexcept
> + { return _M_lo || _M_hi; }
> +
> _GLIBCXX14_CONSTEXPR type&
> operator=(uint64_t __x) noexcept
> { return *this = type(__x); }
> @@ -134,6 +138,13 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> operator+(type __l, uint64_t __r) noexcept
> { return __l += type(__r); }
>
> + _GLIBCXX14_CONSTEXPR type&
> + operator-=(const type& __r) noexcept
> + {
> + _M_hi -= __r._M_hi + __builtin_sub_overflow(_M_lo, __r._M_lo, &_M_lo);
> + return *this;
> + }
> +
> // Subtraction with 64-bit operand
> _GLIBCXX14_CONSTEXPR type&
> operator-=(uint64_t __r) noexcept
> @@ -142,6 +153,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> return *this;
> }
>
> + friend _GLIBCXX14_CONSTEXPR type
> + operator-(type __l, const type& __r) noexcept
> + { return __l -= __r; }
> +
> friend _GLIBCXX14_CONSTEXPR type
> operator-(type __l, uint64_t __r) noexcept
> { return __l -= __r; }
> @@ -172,7 +187,6 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> }
>
> // Multiplication with a 64-bit operand is simpler.
> - // pre: _M_hi == 0
> _GLIBCXX14_CONSTEXPR type&
> operator*=(uint64_t __x) noexcept
> {
> @@ -190,7 +204,9 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> // These bits are the low half of _M_hi and the high half of _M_lo.
> uint64_t __mid
> = (__l0x1 & __mask) + (__l1x0 & __mask) + (__l1x1 >> 32);
> - _M_hi = __l0x0 + (__l0x1 >> 32) + (__l1x0 >> 32) + (__mid >> 32);
> +
> + _M_hi *= __x;
> + _M_hi += __l0x0 + (__l0x1 >> 32) + (__l1x0 >> 32) + (__mid >> 32);
> _M_lo = (__mid << 32) + (__l1x1 & __mask);
> return *this;
> }
> @@ -296,6 +312,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> return *this;
> }
>
> + _GLIBCXX14_CONSTEXPR type&
> + operator/=(uint64_t __r) noexcept
> + { return *this /= type(__r); }
> +
> // Currently only supported for 64-bit operands.
> _GLIBCXX14_CONSTEXPR type&
> operator%=(uint64_t __m) noexcept
> @@ -345,6 +365,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
> operator/(type __l, const type& __r) noexcept
> { return __l /= __r; }
>
> + friend _GLIBCXX14_CONSTEXPR type
> + operator/(type __l, uint64_t __r) noexcept
> + { return __l /= __r; }
> +
> friend _GLIBCXX14_CONSTEXPR type
> operator%(type __l, uint64_t __m) noexcept
> { return __l %= __m; }
> --
> 2.54.0
>
@@ -90,6 +90,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
__rand_uint128(const __rand_uint128&) = default;
__rand_uint128& operator=(const __rand_uint128&) = default;
+ constexpr explicit
+ operator bool() const noexcept
+ { return _M_lo || _M_hi; }
+
_GLIBCXX14_CONSTEXPR type&
operator=(uint64_t __x) noexcept
{ return *this = type(__x); }
@@ -134,6 +138,13 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
operator+(type __l, uint64_t __r) noexcept
{ return __l += type(__r); }
+ _GLIBCXX14_CONSTEXPR type&
+ operator-=(const type& __r) noexcept
+ {
+ _M_hi -= __r._M_hi + __builtin_sub_overflow(_M_lo, __r._M_lo, &_M_lo);
+ return *this;
+ }
+
// Subtraction with 64-bit operand
_GLIBCXX14_CONSTEXPR type&
operator-=(uint64_t __r) noexcept
@@ -142,6 +153,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
return *this;
}
+ friend _GLIBCXX14_CONSTEXPR type
+ operator-(type __l, const type& __r) noexcept
+ { return __l -= __r; }
+
friend _GLIBCXX14_CONSTEXPR type
operator-(type __l, uint64_t __r) noexcept
{ return __l -= __r; }
@@ -172,7 +187,6 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
}
// Multiplication with a 64-bit operand is simpler.
- // pre: _M_hi == 0
_GLIBCXX14_CONSTEXPR type&
operator*=(uint64_t __x) noexcept
{
@@ -190,7 +204,9 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
// These bits are the low half of _M_hi and the high half of _M_lo.
uint64_t __mid
= (__l0x1 & __mask) + (__l1x0 & __mask) + (__l1x1 >> 32);
- _M_hi = __l0x0 + (__l0x1 >> 32) + (__l1x0 >> 32) + (__mid >> 32);
+
+ _M_hi *= __x;
+ _M_hi += __l0x0 + (__l0x1 >> 32) + (__l1x0 >> 32) + (__mid >> 32);
_M_lo = (__mid << 32) + (__l1x1 & __mask);
return *this;
}
@@ -296,6 +312,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
return *this;
}
+ _GLIBCXX14_CONSTEXPR type&
+ operator/=(uint64_t __r) noexcept
+ { return *this /= type(__r); }
+
// Currently only supported for 64-bit operands.
_GLIBCXX14_CONSTEXPR type&
operator%=(uint64_t __m) noexcept
@@ -345,6 +365,10 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
operator/(type __l, const type& __r) noexcept
{ return __l /= __r; }
+ friend _GLIBCXX14_CONSTEXPR type
+ operator/(type __l, uint64_t __r) noexcept
+ { return __l /= __r; }
+
friend _GLIBCXX14_CONSTEXPR type
operator%(type __l, uint64_t __m) noexcept
{ return __l %= __m; }