Skip to content

Commit cf38f04

Browse files
committed
Replace __libcpp_{ctz,clz} with __builtin_{ctzg,clzg}
1 parent 4b19db6 commit cf38f04

File tree

7 files changed

+33
-147
lines changed

7 files changed

+33
-147
lines changed

libcxx/include/__algorithm/sort.h

+9-9
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,10 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos(
357357
// Swap one pair on each iteration as long as both bitsets have at least one
358358
// element for swapping.
359359
while (__left_bitset != 0 && __right_bitset != 0) {
360-
difference_type __tz_left = __libcpp_ctz(__left_bitset);
361-
__left_bitset = __libcpp_blsr(__left_bitset);
362-
difference_type __tz_right = __libcpp_ctz(__right_bitset);
363-
__right_bitset = __libcpp_blsr(__right_bitset);
360+
difference_type __tz_left = std::__countr_zero(__left_bitset);
361+
__left_bitset = std::__libcpp_blsr(__left_bitset);
362+
difference_type __tz_right = std::__countr_zero(__right_bitset);
363+
__right_bitset = std::__libcpp_blsr(__right_bitset);
364364
_Ops::iter_swap(__first + __tz_left, __last - __tz_right);
365365
}
366366
}
@@ -456,7 +456,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within(
456456
// Swap within the left side. Need to find set positions in the reverse
457457
// order.
458458
while (__left_bitset != 0) {
459-
difference_type __tz_left = __detail::__block_size - 1 - __libcpp_clz(__left_bitset);
459+
difference_type __tz_left = __detail::__block_size - 1 - std::__countl_zero(__left_bitset);
460460
__left_bitset &= (static_cast<uint64_t>(1) << __tz_left) - 1;
461461
_RandomAccessIterator __it = __first + __tz_left;
462462
if (__it != __lm1) {
@@ -469,7 +469,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within(
469469
// Swap within the right side. Need to find set positions in the reverse
470470
// order.
471471
while (__right_bitset != 0) {
472-
difference_type __tz_right = __detail::__block_size - 1 - __libcpp_clz(__right_bitset);
472+
difference_type __tz_right = __detail::__block_size - 1 - std::__countl_zero(__right_bitset);
473473
__right_bitset &= (static_cast<uint64_t>(1) << __tz_right) - 1;
474474
_RandomAccessIterator __it = __lm1 - __tz_right;
475475
if (__it != __first) {
@@ -831,11 +831,11 @@ inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
831831
if (__n == 0)
832832
return 0;
833833
if (sizeof(__n) <= sizeof(unsigned))
834-
return sizeof(unsigned) * CHAR_BIT - 1 - __libcpp_clz(static_cast<unsigned>(__n));
834+
return sizeof(unsigned) * CHAR_BIT - 1 - std::__countl_zero(static_cast<unsigned>(__n));
835835
if (sizeof(__n) <= sizeof(unsigned long))
836-
return sizeof(unsigned long) * CHAR_BIT - 1 - __libcpp_clz(static_cast<unsigned long>(__n));
836+
return sizeof(unsigned long) * CHAR_BIT - 1 - std::__countl_zero(static_cast<unsigned long>(__n));
837837
if (sizeof(__n) <= sizeof(unsigned long long))
838-
return sizeof(unsigned long long) * CHAR_BIT - 1 - __libcpp_clz(static_cast<unsigned long long>(__n));
838+
return sizeof(unsigned long long) * CHAR_BIT - 1 - std::__countl_zero(static_cast<unsigned long long>(__n));
839839

840840
_Number __log2 = 0;
841841
while (__n > 1) {

libcxx/include/__bit/countl.h

-62
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
// TODO: __builtin_clzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
10-
// refactor this code to exclusively use __builtin_clzg.
11-
129
#ifndef _LIBCPP___BIT_COUNTL_H
1310
#define _LIBCPP___BIT_COUNTL_H
1411

@@ -27,69 +24,10 @@ _LIBCPP_PUSH_MACROS
2724

2825
_LIBCPP_BEGIN_NAMESPACE_STD
2926

30-
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned __x) _NOEXCEPT {
31-
return __builtin_clz(__x);
32-
}
33-
34-
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long __x) _NOEXCEPT {
35-
return __builtin_clzl(__x);
36-
}
37-
38-
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long long __x) _NOEXCEPT {
39-
return __builtin_clzll(__x);
40-
}
41-
42-
#if _LIBCPP_HAS_INT128
43-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x) _NOEXCEPT {
44-
# if __has_builtin(__builtin_clzg)
45-
return __builtin_clzg(__x);
46-
# else
47-
// The function is written in this form due to C++ constexpr limitations.
48-
// The algorithm:
49-
// - Test whether any bit in the high 64-bits is set
50-
// - No bits set:
51-
// - The high 64-bits contain 64 leading zeros,
52-
// - Add the result of the low 64-bits.
53-
// - Any bits set:
54-
// - The number of leading zeros of the input is the number of leading
55-
// zeros in the high 64-bits.
56-
return ((__x >> 64) == 0) ? (64 + __builtin_clzll(static_cast<unsigned long long>(__x)))
57-
: __builtin_clzll(static_cast<unsigned long long>(__x >> 64));
58-
# endif
59-
}
60-
#endif // _LIBCPP_HAS_INT128
61-
6227
template <class _Tp>
6328
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT {
6429
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__countl_zero requires an unsigned integer type");
65-
#if __has_builtin(__builtin_clzg)
6630
return __builtin_clzg(__t, numeric_limits<_Tp>::digits);
67-
#else // __has_builtin(__builtin_clzg)
68-
if (__t == 0)
69-
return numeric_limits<_Tp>::digits;
70-
71-
if (sizeof(_Tp) <= sizeof(unsigned int))
72-
return std::__libcpp_clz(static_cast<unsigned int>(__t)) -
73-
(numeric_limits<unsigned int>::digits - numeric_limits<_Tp>::digits);
74-
else if (sizeof(_Tp) <= sizeof(unsigned long))
75-
return std::__libcpp_clz(static_cast<unsigned long>(__t)) -
76-
(numeric_limits<unsigned long>::digits - numeric_limits<_Tp>::digits);
77-
else if (sizeof(_Tp) <= sizeof(unsigned long long))
78-
return std::__libcpp_clz(static_cast<unsigned long long>(__t)) -
79-
(numeric_limits<unsigned long long>::digits - numeric_limits<_Tp>::digits);
80-
else {
81-
int __ret = 0;
82-
int __iter = 0;
83-
const unsigned int __ulldigits = numeric_limits<unsigned long long>::digits;
84-
while (true) {
85-
__t = std::__rotl(__t, __ulldigits);
86-
if ((__iter = std::__countl_zero(static_cast<unsigned long long>(__t))) != __ulldigits)
87-
break;
88-
__ret += __iter;
89-
}
90-
return __ret + __iter;
91-
}
92-
#endif // __has_builtin(__builtin_clzg)
9331
}
9432

9533
#if _LIBCPP_STD_VER >= 20

libcxx/include/__bit/countr.h

-49
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
// TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
10-
// refactor this code to exclusively use __builtin_ctzg.
11-
129
#ifndef _LIBCPP___BIT_COUNTR_H
1310
#define _LIBCPP___BIT_COUNTR_H
1411

1512
#include <__assert>
16-
#include <__bit/rotate.h>
1713
#include <__concepts/arithmetic.h>
1814
#include <__config>
1915
#include <__type_traits/is_unsigned.h>
@@ -28,55 +24,10 @@ _LIBCPP_PUSH_MACROS
2824

2925
_LIBCPP_BEGIN_NAMESPACE_STD
3026

31-
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned __x) _NOEXCEPT {
32-
return __builtin_ctz(__x);
33-
}
34-
35-
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long __x) _NOEXCEPT {
36-
return __builtin_ctzl(__x);
37-
}
38-
39-
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long long __x) _NOEXCEPT {
40-
return __builtin_ctzll(__x);
41-
}
42-
43-
// A constexpr implementation for C++11 and later (using clang extensions for constexpr support)
44-
// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case)
45-
template <class _Tp>
46-
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT {
47-
_LIBCPP_ASSERT_INTERNAL(__t != 0, "__countr_zero_impl called with zero value");
48-
static_assert(is_unsigned<_Tp>::value, "__countr_zero_impl only works with unsigned types");
49-
if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) {
50-
return std::__libcpp_ctz(static_cast<unsigned int>(__t));
51-
} else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) {
52-
return std::__libcpp_ctz(static_cast<unsigned long>(__t));
53-
} else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long long)) {
54-
return std::__libcpp_ctz(static_cast<unsigned long long>(__t));
55-
} else {
56-
#if _LIBCPP_STD_VER == 11
57-
unsigned long long __ull = static_cast<unsigned long long>(__t);
58-
const unsigned int __ulldigits = numeric_limits<unsigned long long>::digits;
59-
return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull);
60-
#else
61-
int __ret = 0;
62-
const unsigned int __ulldigits = numeric_limits<unsigned long long>::digits;
63-
while (static_cast<unsigned long long>(__t) == 0uLL) {
64-
__ret += __ulldigits;
65-
__t >>= __ulldigits;
66-
}
67-
return __ret + std::__libcpp_ctz(static_cast<unsigned long long>(__t));
68-
#endif
69-
}
70-
}
71-
7227
template <class _Tp>
7328
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT {
7429
static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types");
75-
#if __has_builtin(__builtin_ctzg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19.
7630
return __builtin_ctzg(__t, numeric_limits<_Tp>::digits);
77-
#else
78-
return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits;
79-
#endif
8031
}
8132

8233
#if _LIBCPP_STD_VER >= 20

libcxx/include/__bit_reference

+2-2
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public:
165165

166166
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void flip() _NOEXCEPT { *__seg_ ^= __mask_; }
167167
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> operator&() const _NOEXCEPT {
168-
return __bit_iterator<_Cp, false>(__seg_, static_cast<unsigned>(std::__libcpp_ctz(__mask_)));
168+
return __bit_iterator<_Cp, false>(__seg_, static_cast<unsigned>(std::__countr_zero(__mask_)));
169169
}
170170

171171
private:
@@ -234,7 +234,7 @@ public:
234234
}
235235

236236
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, true> operator&() const _NOEXCEPT {
237-
return __bit_iterator<_Cp, true>(__seg_, static_cast<unsigned>(std::__libcpp_ctz(__mask_)));
237+
return __bit_iterator<_Cp, true>(__seg_, static_cast<unsigned>(std::__countr_zero(__mask_)));
238238
}
239239

240240
private:

libcxx/include/__charconv/to_chars_integral.h

+6-9
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,8 @@ struct _LIBCPP_HIDDEN __integral<2> {
118118
template <typename _Tp>
119119
_LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {
120120
// If value == 0 still need one digit. If the value != this has no
121-
// effect since the code scans for the most significant bit set. (Note
122-
// that __libcpp_clz doesn't work for 0.)
123-
return numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1);
121+
// effect since the code scans for the most significant bit set.
122+
return numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1);
124123
}
125124

126125
template <typename _Tp>
@@ -154,9 +153,8 @@ struct _LIBCPP_HIDDEN __integral<8> {
154153
template <typename _Tp>
155154
_LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {
156155
// If value == 0 still need one digit. If the value != this has no
157-
// effect since the code scans for the most significat bit set. (Note
158-
// that __libcpp_clz doesn't work for 0.)
159-
return ((numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1)) + 2) / 3;
156+
// effect since the code scans for the most significat bit set.
157+
return ((numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1)) + 2) / 3;
160158
}
161159

162160
template <typename _Tp>
@@ -190,9 +188,8 @@ struct _LIBCPP_HIDDEN __integral<16> {
190188
template <typename _Tp>
191189
_LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {
192190
// If value == 0 still need one digit. If the value != this has no
193-
// effect since the code scans for the most significat bit set. (Note
194-
// that __libcpp_clz doesn't work for 0.)
195-
return (numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1) + 3) / 4;
191+
// effect since the code scans for the most significat bit set.
192+
return (numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1) + 3) / 4;
196193
}
197194

198195
template <typename _Tp>

libcxx/include/__charconv/traits.h

+15-15
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) <= sizeof(uin
4545
///
4646
/// The algorithm is based on
4747
/// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
48-
/// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that
49-
/// function requires its input to have at least one bit set the value of
50-
/// zero is set to one. This means the first element of the lookup table is
51-
/// zero.
48+
/// Instead of using IntegerLogBase2 it uses __countl_zero. Previously, it
49+
/// used __libcpp_clz. Since that function requires its input to have at
50+
/// least one bit set the value of zero is set to one. This means the first
51+
/// element of the lookup table is zero.
5252
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
53-
auto __t = (32 - std::__libcpp_clz(static_cast<type>(__v | 1))) * 1233 >> 12;
53+
auto __t = (32 - std::__countl_zero(static_cast<type>(__v | 1))) * 1233 >> 12;
5454
return __t - (__v < __itoa::__pow10_32[__t]) + 1;
5555
}
5656

@@ -71,12 +71,12 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(uin
7171
///
7272
/// The algorithm is based on
7373
/// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
74-
/// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that
75-
/// function requires its input to have at least one bit set the value of
76-
/// zero is set to one. This means the first element of the lookup table is
77-
/// zero.
74+
/// Instead of using IntegerLogBase2 it uses __countl_zero. Previously, it
75+
/// used __libcpp_clz. Since that function requires its input to have at
76+
/// least one bit set the value of zero is set to one. This means the first
77+
/// element of the lookup table is zero.
7878
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
79-
auto __t = (64 - std::__libcpp_clz(static_cast<type>(__v | 1))) * 1233 >> 12;
79+
auto __t = (64 - std::__countl_zero(static_cast<type>(__v | 1))) * 1233 >> 12;
8080
return __t - (__v < __itoa::__pow10_64[__t]) + 1;
8181
}
8282

@@ -98,15 +98,15 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(__u
9898
///
9999
/// The algorithm is based on
100100
/// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
101-
/// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that
102-
/// function requires its input to have at least one bit set the value of
103-
/// zero is set to one. This means the first element of the lookup table is
104-
/// zero.
101+
/// Instead of using IntegerLogBase2 it uses __countl_zero. Previously, it
102+
/// used __libcpp_clz. Since that function requires its input to have at
103+
/// least one bit set the value of zero is set to one. This means the first
104+
/// element of the lookup table is zero.
105105
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
106106
_LIBCPP_ASSERT_INTERNAL(
107107
__v > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
108108
// There's always a bit set in the upper 64-bits.
109-
auto __t = (128 - std::__libcpp_clz(static_cast<uint64_t>(__v >> 64))) * 1233 >> 12;
109+
auto __t = (128 - std::__countl_zero(static_cast<uint64_t>(__v >> 64))) * 1233 >> 12;
110110
_LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds");
111111
// __t is adjusted since the lookup table misses the lower entries.
112112
return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1;

libcxx/include/__hash_table

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __constrain_hash(size_t __h, size_t __bc) {
147147
}
148148

149149
inline _LIBCPP_HIDE_FROM_ABI size_t __next_hash_pow2(size_t __n) {
150-
return __n < 2 ? __n : (size_t(1) << (numeric_limits<size_t>::digits - __libcpp_clz(__n - 1)));
150+
return __n < 2 ? __n : (size_t(1) << (numeric_limits<size_t>::digits - std::__countl_zero(__n - 1)));
151151
}
152152

153153
template <class _Tp, class _Hash, class _Equal, class _Alloc>

0 commit comments

Comments
 (0)