1 //===-- Implementation of the C++20 bit header -----------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // This is inspired by LLVM ADT/bit.h header.
9 // Some functions are missing, we can add them as needed (popcount, byteswap).
11 #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
12 #define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
14 #include "src/__support/CPP/limits.h" // numeric_limits
15 #include "src/__support/CPP/type_traits.h"
16 #include "src/__support/macros/attributes.h"
17 #include "src/__support/macros/config.h"
18 #include "src/__support/macros/sanitizer.h"
22 namespace LIBC_NAMESPACE_DECL
{
25 #if __has_builtin(__builtin_memcpy_inline)
26 #define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
29 // This implementation of bit_cast requires trivially-constructible To, to avoid
30 // UB in the implementation.
31 template <typename To
, typename From
>
32 LIBC_INLINE
constexpr cpp::enable_if_t
<
33 (sizeof(To
) == sizeof(From
)) &&
34 cpp::is_trivially_constructible
<To
>::value
&&
35 cpp::is_trivially_copyable
<To
>::value
&&
36 cpp::is_trivially_copyable
<From
>::value
,
38 bit_cast(const From
&from
) {
39 MSAN_UNPOISON(&from
, sizeof(From
));
40 #if __has_builtin(__builtin_bit_cast)
41 return __builtin_bit_cast(To
, from
);
44 char *dst
= reinterpret_cast<char *>(&to
);
45 const char *src
= reinterpret_cast<const char *>(&from
);
46 #if __has_builtin(__builtin_memcpy_inline)
47 __builtin_memcpy_inline(dst
, src
, sizeof(To
));
49 for (unsigned i
= 0; i
< sizeof(To
); ++i
)
51 #endif // __has_builtin(__builtin_memcpy_inline)
53 #endif // __has_builtin(__builtin_bit_cast)
57 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>,
59 has_single_bit(T value
) {
60 return (value
!= 0) && ((value
& (value
- 1)) == 0);
63 // A temporary macro to add template function specialization when compiler
64 // builtin is available.
65 #define ADD_SPECIALIZATION(NAME, TYPE, BUILTIN) \
66 template <> [[nodiscard]] LIBC_INLINE constexpr int NAME<TYPE>(TYPE value) { \
67 static_assert(cpp::is_unsigned_v<TYPE>); \
68 return value == 0 ? cpp::numeric_limits<TYPE>::digits : BUILTIN(value); \
71 /// Count number of 0's from the least significant bit to the most
72 /// stopping at the first 1.
74 /// Only unsigned integral types are allowed.
76 /// Returns cpp::numeric_limits<T>::digits on an input of 0.
78 #if __has_builtin(__builtin_ctzg)
80 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
81 countr_zero(T value
) {
82 return __builtin_ctzg(value
, cpp::numeric_limits
<T
>::digits
);
86 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
87 countr_zero(T value
) {
89 return cpp::numeric_limits
<T
>::digits
;
93 unsigned zero_bits
= 0;
94 unsigned shift
= cpp::numeric_limits
<T
>::digits
>> 1;
95 T mask
= cpp::numeric_limits
<T
>::max() >> shift
;
97 if ((value
& mask
) == 0) {
106 #if __has_builtin(__builtin_ctzs)
107 ADD_SPECIALIZATION(countr_zero
, unsigned short, __builtin_ctzs
)
109 ADD_SPECIALIZATION(countr_zero
, unsigned int, __builtin_ctz
)
110 ADD_SPECIALIZATION(countr_zero
, unsigned long, __builtin_ctzl
)
111 ADD_SPECIALIZATION(countr_zero
, unsigned long long, __builtin_ctzll
)
112 #endif // __has_builtin(__builtin_ctzg)
114 /// Count number of 0's from the most significant bit to the least
115 /// stopping at the first 1.
117 /// Only unsigned integral types are allowed.
119 /// Returns cpp::numeric_limits<T>::digits on an input of 0.
120 // clang-19+, gcc-14+
121 #if __has_builtin(__builtin_clzg)
122 template <typename T
>
123 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
124 countl_zero(T value
) {
125 return __builtin_clzg(value
, cpp::numeric_limits
<T
>::digits
);
128 template <typename T
>
129 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
130 countl_zero(T value
) {
132 return cpp::numeric_limits
<T
>::digits
;
134 unsigned zero_bits
= 0;
135 for (unsigned shift
= cpp::numeric_limits
<T
>::digits
>> 1; shift
;
137 T tmp
= value
>> shift
;
145 #if __has_builtin(__builtin_clzs)
146 ADD_SPECIALIZATION(countl_zero
, unsigned short, __builtin_clzs
)
148 ADD_SPECIALIZATION(countl_zero
, unsigned int, __builtin_clz
)
149 ADD_SPECIALIZATION(countl_zero
, unsigned long, __builtin_clzl
)
150 ADD_SPECIALIZATION(countl_zero
, unsigned long long, __builtin_clzll
)
151 #endif // __has_builtin(__builtin_clzg)
153 #undef ADD_SPECIALIZATION
155 /// Count the number of ones from the most significant bit to the first
158 /// Ex. countl_one(0xFF0FFF00) == 8.
159 /// Only unsigned integral types are allowed.
161 /// Returns cpp::numeric_limits<T>::digits on an input of all ones.
162 template <typename T
>
163 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
164 countl_one(T value
) {
165 return cpp::countl_zero
<T
>(~value
);
168 /// Count the number of ones from the least significant bit to the first
171 /// Ex. countr_one(0x00FF00FF) == 8.
172 /// Only unsigned integral types are allowed.
174 /// Returns cpp::numeric_limits<T>::digits on an input of all ones.
175 template <typename T
>
176 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
177 countr_one(T value
) {
178 return cpp::countr_zero
<T
>(~value
);
181 /// Returns the number of bits needed to represent value if value is nonzero.
182 /// Returns 0 otherwise.
184 /// Ex. bit_width(5) == 3.
185 template <typename T
>
186 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
188 return cpp::numeric_limits
<T
>::digits
- cpp::countl_zero(value
);
191 /// Returns the largest integral power of two no greater than value if value is
192 /// nonzero. Returns 0 otherwise.
194 /// Ex. bit_floor(5) == 4.
195 template <typename T
>
196 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, T
>
200 return static_cast<T
>(T(1) << (cpp::bit_width(value
) - 1));
203 /// Returns the smallest integral power of two no smaller than value if value is
204 /// nonzero. Returns 1 otherwise.
206 /// Ex. bit_ceil(5) == 8.
208 /// The return value is undefined if the input is larger than the largest power
209 /// of two representable in T.
210 template <typename T
>
211 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, T
>
215 return static_cast<T
>(T(1) << cpp::bit_width(value
- 1U));
218 // Rotate algorithms make use of "Safe, Efficient, and Portable Rotate in C/C++"
219 // from https://blog.regehr.org/archives/1063.
221 // Forward-declare rotr so that rotl can use it.
222 template <typename T
>
223 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, T
>
224 rotr(T value
, int rotate
);
226 template <typename T
>
227 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, T
>
228 rotl(T value
, int rotate
) {
229 constexpr unsigned N
= cpp::numeric_limits
<T
>::digits
;
234 return cpp::rotr
<T
>(value
, -rotate
);
235 return (value
<< rotate
) | (value
>> (N
- rotate
));
238 template <typename T
>
239 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, T
>
240 rotr(T value
, int rotate
) {
241 constexpr unsigned N
= cpp::numeric_limits
<T
>::digits
;
246 return cpp::rotl
<T
>(value
, -rotate
);
247 return (value
>> rotate
) | (value
<< (N
- rotate
));
250 // TODO: Do we need this function at all? How is it different from
252 template <class To
, class From
>
253 LIBC_INLINE
constexpr To
bit_or_static_cast(const From
&from
) {
254 if constexpr (sizeof(To
) == sizeof(From
)) {
255 return bit_cast
<To
>(from
);
257 return static_cast<To
>(from
);
261 /// Count number of 1's aka population count or Hamming weight.
263 /// Only unsigned integral types are allowed.
264 // clang-19+, gcc-14+
265 #if __has_builtin(__builtin_popcountg)
266 template <typename T
>
267 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
269 return __builtin_popcountg(value
);
271 #else // !__has_builtin(__builtin_popcountg)
272 template <typename T
>
273 [[nodiscard
]] LIBC_INLINE
constexpr cpp::enable_if_t
<cpp::is_unsigned_v
<T
>, int>
282 #define ADD_SPECIALIZATION(TYPE, BUILTIN) \
284 [[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \
285 return BUILTIN(value); \
287 ADD_SPECIALIZATION(unsigned char, __builtin_popcount
)
288 ADD_SPECIALIZATION(unsigned short, __builtin_popcount
)
289 ADD_SPECIALIZATION(unsigned, __builtin_popcount
)
290 ADD_SPECIALIZATION(unsigned long, __builtin_popcountl
)
291 ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll
)
292 #endif // __builtin_popcountg
293 #undef ADD_SPECIALIZATION
296 } // namespace LIBC_NAMESPACE_DECL
298 #endif // LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H