From 1bbff0e750e97cb64fe8afe6c91abc5b8a178fd9 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 08:46:45 +0100 Subject: [PATCH 1/4] Revert "[libc++] Remove dead implementation of is_nothrow_convertible and merge the remaining code into is_convertible.h (#137717)" This reverts commit e43e8ec7afbdf8b90204060b725d6990829b80a1. --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__type_traits/is_convertible.h | 10 --- .../__type_traits/is_nothrow_convertible.h | 62 +++++++++++++++++++ libcxx/include/module.modulemap.in | 4 ++ libcxx/include/type_traits | 1 + 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 libcxx/include/__type_traits/is_nothrow_convertible.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 43cefd5600646..6fcc06b44a151 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -836,6 +836,7 @@ set(files __type_traits/is_member_pointer.h __type_traits/is_nothrow_assignable.h __type_traits/is_nothrow_constructible.h + __type_traits/is_nothrow_convertible.h __type_traits/is_nothrow_destructible.h __type_traits/is_null_pointer.h __type_traits/is_object.h diff --git a/libcxx/include/__type_traits/is_convertible.h b/libcxx/include/__type_traits/is_convertible.h index f0a859f9cc16d..cef3c4a764914 100644 --- a/libcxx/include/__type_traits/is_convertible.h +++ b/libcxx/include/__type_traits/is_convertible.h @@ -26,16 +26,6 @@ template _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_convertible_v = __is_convertible(_From, _To); #endif -#if _LIBCPP_STD_VER >= 20 - -template -struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_convertible : bool_constant<__is_nothrow_convertible(_Tp, _Up)> {}; - -template -_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_convertible_v = __is_nothrow_convertible(_Tp, _Up); - -#endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TYPE_TRAITS_IS_CONVERTIBLE_H diff --git a/libcxx/include/__type_traits/is_nothrow_convertible.h b/libcxx/include/__type_traits/is_nothrow_convertible.h new file mode 100644 index 0000000000000..f114619296437 --- /dev/null +++ b/libcxx/include/__type_traits/is_nothrow_convertible.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H +#define _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H + +#include <__config> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_void.h> +#include <__type_traits/lazy.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +# if __has_builtin(__is_nothrow_convertible) + +template +struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_convertible : bool_constant<__is_nothrow_convertible(_Tp, _Up)> {}; + +template +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_convertible_v = __is_nothrow_convertible(_Tp, _Up); + +# else // __has_builtin(__is_nothrow_convertible) + +template +void __test_noexcept(_Tp) noexcept; + +template +bool_constant(std::declval<_Fm>()))> __is_nothrow_convertible_test(); + +template +struct __is_nothrow_convertible_helper : decltype(std::__is_nothrow_convertible_test<_Fm, _To>()) {}; + +template +struct is_nothrow_convertible + : _Or<_And, is_void<_Fm>>, + _Lazy<_And, is_convertible<_Fm, _To>, __is_nothrow_convertible_helper<_Fm, _To> > >::type {}; + +template +inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_Fm, _To>::value; + +# endif // __has_builtin(__is_nothrow_convertible) + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 7f625cefed1c2..8b14fd10484a9 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -232,6 +232,10 @@ module std_core [system] { header "__type_traits/is_nothrow_constructible.h" export std_core.type_traits.integral_constant } + module is_nothrow_convertible { + header "__type_traits/is_nothrow_convertible.h" + export std_core.type_traits.integral_constant + } module is_nothrow_destructible { header "__type_traits/is_nothrow_destructible.h" export std_core.type_traits.integral_constant diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index 9db7b2afb0cf3..b63f61cfefe8e 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -549,6 +549,7 @@ namespace std # include <__type_traits/common_reference.h> # include <__type_traits/is_bounded_array.h> # include <__type_traits/is_constant_evaluated.h> +# include <__type_traits/is_nothrow_convertible.h> # include <__type_traits/is_unbounded_array.h> # include <__type_traits/type_identity.h> # include <__type_traits/unwrap_ref.h> From 35e6998f5a6e5b89d0a5b0841e157061bdb71385 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 09:12:39 +0100 Subject: [PATCH 2/4] Revert "[libc++] Remove a few unused includes from <__bit/*> (#137934)" This reverts commit a6459debc06f9cb86940ff5cdae35a1f52e1ed19. --- libcxx/include/__bit/bit_floor.h | 1 + libcxx/include/__bit/countl.h | 1 + libcxx/include/__bit/countr.h | 1 + libcxx/include/__bit/popcount.h | 2 ++ 4 files changed, 5 insertions(+) diff --git a/libcxx/include/__bit/bit_floor.h b/libcxx/include/__bit/bit_floor.h index 6bcbc53fb4972..133e369504e43 100644 --- a/libcxx/include/__bit/bit_floor.h +++ b/libcxx/include/__bit/bit_floor.h @@ -12,6 +12,7 @@ #include <__bit/bit_log2.h> #include <__concepts/arithmetic.h> #include <__config> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header diff --git a/libcxx/include/__bit/countl.h b/libcxx/include/__bit/countl.h index 9499bf9b458ee..9c37749f92577 100644 --- a/libcxx/include/__bit/countl.h +++ b/libcxx/include/__bit/countl.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___BIT_COUNTL_H #define _LIBCPP___BIT_COUNTL_H +#include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> #include <__type_traits/is_unsigned_integer.h> diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index 7b311b83853c5..f87175971bed3 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___BIT_COUNTR_H #define _LIBCPP___BIT_COUNTR_H +#include <__assert> #include <__concepts/arithmetic.h> #include <__config> #include <__type_traits/is_unsigned.h> diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 9ae572d466ba7..622c8efd7938a 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -9,9 +9,11 @@ #ifndef _LIBCPP___BIT_POPCOUNT_H #define _LIBCPP___BIT_POPCOUNT_H +#include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> #include <__type_traits/is_unsigned.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header From cd7e7f3d321fe9c907587630a43964130867e98a Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 09:13:58 +0100 Subject: [PATCH 3/4] Revert "[libc++] Replace __libcpp_{ctz, clz} with __builtin_{ctzg, clzg} (#133920)" This reverts commit 9e3982d9ae8173171cd7247ee505e9c02079c6bf. --- libcxx/include/__algorithm/sort.h | 12 ++-- libcxx/include/__bit/countl.h | 62 +++++++++++++++++++ libcxx/include/__bit/countr.h | 49 +++++++++++++++ libcxx/include/__bit_reference | 4 +- libcxx/include/__charconv/to_chars_integral.h | 15 +++-- libcxx/include/__charconv/traits.h | 21 +++++-- libcxx/include/__hash_table | 2 +- 7 files changed, 144 insertions(+), 21 deletions(-) diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h index 06cb5b8ce7057..d7bc1381ba5e1 100644 --- a/libcxx/include/__algorithm/sort.h +++ b/libcxx/include/__algorithm/sort.h @@ -359,10 +359,10 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos( // Swap one pair on each iteration as long as both bitsets have at least one // element for swapping. while (__left_bitset != 0 && __right_bitset != 0) { - difference_type __tz_left = std::__countr_zero(__left_bitset); - __left_bitset = std::__libcpp_blsr(__left_bitset); - difference_type __tz_right = std::__countr_zero(__right_bitset); - __right_bitset = std::__libcpp_blsr(__right_bitset); + difference_type __tz_left = __libcpp_ctz(__left_bitset); + __left_bitset = __libcpp_blsr(__left_bitset); + difference_type __tz_right = __libcpp_ctz(__right_bitset); + __right_bitset = __libcpp_blsr(__right_bitset); _Ops::iter_swap(__first + __tz_left, __last - __tz_right); } } @@ -458,7 +458,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within( // Swap within the left side. Need to find set positions in the reverse // order. while (__left_bitset != 0) { - difference_type __tz_left = __detail::__block_size - 1 - std::__countl_zero(__left_bitset); + difference_type __tz_left = __detail::__block_size - 1 - __libcpp_clz(__left_bitset); __left_bitset &= (static_cast(1) << __tz_left) - 1; _RandomAccessIterator __it = __first + __tz_left; if (__it != __lm1) { @@ -471,7 +471,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within( // Swap within the right side. Need to find set positions in the reverse // order. while (__right_bitset != 0) { - difference_type __tz_right = __detail::__block_size - 1 - std::__countl_zero(__right_bitset); + difference_type __tz_right = __detail::__block_size - 1 - __libcpp_clz(__right_bitset); __right_bitset &= (static_cast(1) << __tz_right) - 1; _RandomAccessIterator __it = __lm1 - __tz_right; if (__it != __first) { diff --git a/libcxx/include/__bit/countl.h b/libcxx/include/__bit/countl.h index 9c37749f92577..d4df1d049b294 100644 --- a/libcxx/include/__bit/countl.h +++ b/libcxx/include/__bit/countl.h @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +// TODO: __builtin_clzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_clzg. + #ifndef _LIBCPP___BIT_COUNTL_H #define _LIBCPP___BIT_COUNTL_H @@ -24,10 +27,69 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned __x) _NOEXCEPT { + return __builtin_clz(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long __x) _NOEXCEPT { + return __builtin_clzl(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long long __x) _NOEXCEPT { + return __builtin_clzll(__x); +} + +#if _LIBCPP_HAS_INT128 +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x) _NOEXCEPT { +# if __has_builtin(__builtin_clzg) + return __builtin_clzg(__x); +# else + // The function is written in this form due to C++ constexpr limitations. + // The algorithm: + // - Test whether any bit in the high 64-bits is set + // - No bits set: + // - The high 64-bits contain 64 leading zeros, + // - Add the result of the low 64-bits. + // - Any bits set: + // - The number of leading zeros of the input is the number of leading + // zeros in the high 64-bits. + return ((__x >> 64) == 0) ? (64 + __builtin_clzll(static_cast(__x))) + : __builtin_clzll(static_cast(__x >> 64)); +# endif +} +#endif // _LIBCPP_HAS_INT128 + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT { static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__countl_zero requires an unsigned integer type"); +#if __has_builtin(__builtin_clzg) return __builtin_clzg(__t, numeric_limits<_Tp>::digits); +#else // __has_builtin(__builtin_clzg) + if (__t == 0) + return numeric_limits<_Tp>::digits; + + if (sizeof(_Tp) <= sizeof(unsigned int)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else if (sizeof(_Tp) <= sizeof(unsigned long)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else if (sizeof(_Tp) <= sizeof(unsigned long long)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else { + int __ret = 0; + int __iter = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (true) { + __t = std::__rotl(__t, __ulldigits); + if ((__iter = std::__countl_zero(static_cast(__t))) != __ulldigits) + break; + __ret += __iter; + } + return __ret + __iter; + } +#endif // __has_builtin(__builtin_clzg) } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index f87175971bed3..46c43921fc60d 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -6,10 +6,14 @@ // //===----------------------------------------------------------------------===// +// TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_ctzg. + #ifndef _LIBCPP___BIT_COUNTR_H #define _LIBCPP___BIT_COUNTR_H #include <__assert> +#include <__bit/rotate.h> #include <__concepts/arithmetic.h> #include <__config> #include <__type_traits/is_unsigned.h> @@ -24,10 +28,55 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned __x) _NOEXCEPT { + return __builtin_ctz(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long __x) _NOEXCEPT { + return __builtin_ctzl(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long long __x) _NOEXCEPT { + return __builtin_ctzll(__x); +} + +// A constexpr implementation for C++11 and later (using clang extensions for constexpr support) +// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__t != 0, "__countr_zero_impl called with zero value"); + static_assert(is_unsigned<_Tp>::value, "__countr_zero_impl only works with unsigned types"); + if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) { + return std::__libcpp_ctz(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) { + return std::__libcpp_ctz(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long long)) { + return std::__libcpp_ctz(static_cast(__t)); + } else { +#if _LIBCPP_STD_VER == 11 + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +#else + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); +#endif + } +} + template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types"); +#if __has_builtin(__builtin_ctzg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19. return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else + return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index a3e6defd405f8..552e0f5e4d799 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -165,7 +165,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void flip() _NOEXCEPT { *__seg_ ^= __mask_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> operator&() const _NOEXCEPT { - return __bit_iterator<_Cp, false>(__seg_, static_cast(std::__countr_zero(__mask_))); + return __bit_iterator<_Cp, false>(__seg_, static_cast(std::__libcpp_ctz(__mask_))); } private: @@ -234,7 +234,7 @@ public: } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, true> operator&() const _NOEXCEPT { - return __bit_iterator<_Cp, true>(__seg_, static_cast(std::__countr_zero(__mask_))); + return __bit_iterator<_Cp, true>(__seg_, static_cast(std::__libcpp_ctz(__mask_))); } private: diff --git a/libcxx/include/__charconv/to_chars_integral.h b/libcxx/include/__charconv/to_chars_integral.h index f10cc3566875a..238c96d7c7a04 100644 --- a/libcxx/include/__charconv/to_chars_integral.h +++ b/libcxx/include/__charconv/to_chars_integral.h @@ -114,8 +114,9 @@ struct _LIBCPP_HIDDEN __integral<2> { template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int __width(_Tp __value) _NOEXCEPT { // If value == 0 still need one digit. If the value != this has no - // effect since the code scans for the most significant bit set. - return numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1); + // effect since the code scans for the most significant bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1); } template @@ -149,8 +150,9 @@ struct _LIBCPP_HIDDEN __integral<8> { template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int __width(_Tp __value) _NOEXCEPT { // If value == 0 still need one digit. If the value != this has no - // effect since the code scans for the most significat bit set. - return ((numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1)) + 2) / 3; + // effect since the code scans for the most significat bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return ((numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1)) + 2) / 3; } template @@ -184,8 +186,9 @@ struct _LIBCPP_HIDDEN __integral<16> { template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int __width(_Tp __value) _NOEXCEPT { // If value == 0 still need one digit. If the value != this has no - // effect since the code scans for the most significat bit set. - return (numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1) + 3) / 4; + // effect since the code scans for the most significat bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return (numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1) + 3) / 4; } template diff --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h index 9fd0092ca79c3..085a3f7886f31 100644 --- a/libcxx/include/__charconv/traits.h +++ b/libcxx/include/__charconv/traits.h @@ -43,9 +43,12 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t(__v | 1))) * 1233 >> 12; + auto __t = (32 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; return __t - (__v < __itoa::__pow10_32[__t]) + 1; } @@ -66,9 +69,12 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t(__v | 1))) * 1233 >> 12; + auto __t = (64 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; return __t - (__v < __itoa::__pow10_64[__t]) + 1; } @@ -90,12 +96,15 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); // There's always a bit set in the upper 64-bits. - auto __t = (128 - std::__countl_zero(static_cast(__v >> 64))) * 1233 >> 12; + auto __t = (128 - std::__libcpp_clz(static_cast(__v >> 64))) * 1233 >> 12; _LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds"); // __t is adjusted since the lookup table misses the lower entries. return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1; diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index aefa8e19c1864..fca58ca296067 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -147,7 +147,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __constrain_hash(size_t __h, size_t __bc) { } inline _LIBCPP_HIDE_FROM_ABI size_t __next_hash_pow2(size_t __n) { - return __n < 2 ? __n : (size_t(1) << (numeric_limits::digits - std::__countl_zero(__n - 1))); + return __n < 2 ? __n : (size_t(1) << (numeric_limits::digits - __libcpp_clz(__n - 1))); } template From d8e13f75406ed6a3708832f53f9d35bff26324cb Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 09:18:34 +0100 Subject: [PATCH 4/4] Revert "[libc++] Replace __libcpp_popcount by __builtin_popcountg (#133937)" This reverts commit 703cfe745b96751c1204bcffe4e56038c809247f. --- libcxx/include/__bit/popcount.h | 43 +++++++++++++++++++ .../include/__stop_token/atomic_unique_lock.h | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 622c8efd7938a..b1d93caab0081 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +// TODO: __builtin_popcountg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_popcountg. + #ifndef _LIBCPP___BIT_POPCOUNT_H #define _LIBCPP___BIT_POPCOUNT_H @@ -24,10 +27,50 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned __x) _NOEXCEPT { + return __builtin_popcount(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned long __x) _NOEXCEPT { + return __builtin_popcountl(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned long long __x) _NOEXCEPT { + return __builtin_popcountll(__x); +} + +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount_impl(_Tp __t) _NOEXCEPT { + if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) { + return std::__libcpp_popcount(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) { + return std::__libcpp_popcount(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long long)) { + return std::__libcpp_popcount(static_cast(__t)); + } else { +#if _LIBCPP_STD_VER == 11 + return __t != 0 ? std::__libcpp_popcount(static_cast(__t)) + + std::__popcount_impl<_Tp>(__t >> numeric_limits::digits) + : 0; +#else + int __ret = 0; + while (__t != 0) { + __ret += std::__libcpp_popcount(static_cast(__t)); + __t >>= std::numeric_limits::digits; + } + return __ret; +#endif + } +} + template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { static_assert(is_unsigned<_Tp>::value, "__popcount only works with unsigned types"); +#if __has_builtin(__builtin_popcountg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19. return __builtin_popcountg(__t); +#else + return std::__popcount_impl(__t); +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__stop_token/atomic_unique_lock.h b/libcxx/include/__stop_token/atomic_unique_lock.h index 05e8f223167f1..a698260ac7bbd 100644 --- a/libcxx/include/__stop_token/atomic_unique_lock.h +++ b/libcxx/include/__stop_token/atomic_unique_lock.h @@ -28,7 +28,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD // and LockedBit is the value of State when the lock bit is set, e.g 1 << 2 template class _LIBCPP_AVAILABILITY_SYNC __atomic_unique_lock { - static_assert(std::__popcount(static_cast(_LockedBit)) == 1, + static_assert(std::__libcpp_popcount(static_cast(_LockedBit)) == 1, "LockedBit must be an integer where only one bit is set"); std::atomic<_State>& __state_;