1*bb722a7dSDimitry Andric //===-- Implementation of the C++20 bit header -----------------*- C++ -*-===//
2*bb722a7dSDimitry Andric //
3*bb722a7dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*bb722a7dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*bb722a7dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*bb722a7dSDimitry Andric //
7*bb722a7dSDimitry Andric //===----------------------------------------------------------------------===//
8*bb722a7dSDimitry Andric // This is inspired by LLVM ADT/bit.h header.
9*bb722a7dSDimitry Andric // Some functions are missing, we can add them as needed (popcount, byteswap).
10*bb722a7dSDimitry Andric
11*bb722a7dSDimitry Andric #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
12*bb722a7dSDimitry Andric #define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
13*bb722a7dSDimitry Andric
14*bb722a7dSDimitry Andric #include "src/__support/CPP/limits.h" // numeric_limits
15*bb722a7dSDimitry Andric #include "src/__support/CPP/type_traits.h"
16*bb722a7dSDimitry Andric #include "src/__support/macros/attributes.h"
17*bb722a7dSDimitry Andric #include "src/__support/macros/config.h"
18*bb722a7dSDimitry Andric #include "src/__support/macros/sanitizer.h"
19*bb722a7dSDimitry Andric
20*bb722a7dSDimitry Andric #include <stdint.h>
21*bb722a7dSDimitry Andric
22*bb722a7dSDimitry Andric namespace LIBC_NAMESPACE_DECL {
23*bb722a7dSDimitry Andric namespace cpp {
24*bb722a7dSDimitry Andric
25*bb722a7dSDimitry Andric #if __has_builtin(__builtin_memcpy_inline)
26*bb722a7dSDimitry Andric #define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
27*bb722a7dSDimitry Andric #endif
28*bb722a7dSDimitry Andric
29*bb722a7dSDimitry Andric // This implementation of bit_cast requires trivially-constructible To, to avoid
30*bb722a7dSDimitry Andric // UB in the implementation.
31*bb722a7dSDimitry Andric template <typename To, typename From>
32*bb722a7dSDimitry Andric LIBC_INLINE constexpr cpp::enable_if_t<
33*bb722a7dSDimitry Andric (sizeof(To) == sizeof(From)) &&
34*bb722a7dSDimitry Andric cpp::is_trivially_constructible<To>::value &&
35*bb722a7dSDimitry Andric cpp::is_trivially_copyable<To>::value &&
36*bb722a7dSDimitry Andric cpp::is_trivially_copyable<From>::value,
37*bb722a7dSDimitry Andric To>
bit_cast(const From & from)38*bb722a7dSDimitry Andric bit_cast(const From &from) {
39*bb722a7dSDimitry Andric MSAN_UNPOISON(&from, sizeof(From));
40*bb722a7dSDimitry Andric #if __has_builtin(__builtin_bit_cast)
41*bb722a7dSDimitry Andric return __builtin_bit_cast(To, from);
42*bb722a7dSDimitry Andric #else
43*bb722a7dSDimitry Andric To to;
44*bb722a7dSDimitry Andric char *dst = reinterpret_cast<char *>(&to);
45*bb722a7dSDimitry Andric const char *src = reinterpret_cast<const char *>(&from);
46*bb722a7dSDimitry Andric #if __has_builtin(__builtin_memcpy_inline)
47*bb722a7dSDimitry Andric __builtin_memcpy_inline(dst, src, sizeof(To));
48*bb722a7dSDimitry Andric #else
49*bb722a7dSDimitry Andric for (unsigned i = 0; i < sizeof(To); ++i)
50*bb722a7dSDimitry Andric dst[i] = src[i];
51*bb722a7dSDimitry Andric #endif // __has_builtin(__builtin_memcpy_inline)
52*bb722a7dSDimitry Andric return to;
53*bb722a7dSDimitry Andric #endif // __has_builtin(__builtin_bit_cast)
54*bb722a7dSDimitry Andric }
55*bb722a7dSDimitry Andric
56*bb722a7dSDimitry Andric template <typename T>
57*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>,
58*bb722a7dSDimitry Andric bool>
has_single_bit(T value)59*bb722a7dSDimitry Andric has_single_bit(T value) {
60*bb722a7dSDimitry Andric return (value != 0) && ((value & (value - 1)) == 0);
61*bb722a7dSDimitry Andric }
62*bb722a7dSDimitry Andric
63*bb722a7dSDimitry Andric // A temporary macro to add template function specialization when compiler
64*bb722a7dSDimitry Andric // builtin is available.
65*bb722a7dSDimitry Andric #define ADD_SPECIALIZATION(NAME, TYPE, BUILTIN) \
66*bb722a7dSDimitry Andric template <> [[nodiscard]] LIBC_INLINE constexpr int NAME<TYPE>(TYPE value) { \
67*bb722a7dSDimitry Andric static_assert(cpp::is_unsigned_v<TYPE>); \
68*bb722a7dSDimitry Andric return value == 0 ? cpp::numeric_limits<TYPE>::digits : BUILTIN(value); \
69*bb722a7dSDimitry Andric }
70*bb722a7dSDimitry Andric
71*bb722a7dSDimitry Andric /// Count number of 0's from the least significant bit to the most
72*bb722a7dSDimitry Andric /// stopping at the first 1.
73*bb722a7dSDimitry Andric ///
74*bb722a7dSDimitry Andric /// Only unsigned integral types are allowed.
75*bb722a7dSDimitry Andric ///
76*bb722a7dSDimitry Andric /// Returns cpp::numeric_limits<T>::digits on an input of 0.
77*bb722a7dSDimitry Andric // clang-19+, gcc-14+
78*bb722a7dSDimitry Andric #if __has_builtin(__builtin_ctzg)
79*bb722a7dSDimitry Andric template <typename T>
80*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
countr_zero(T value)81*bb722a7dSDimitry Andric countr_zero(T value) {
82*bb722a7dSDimitry Andric return __builtin_ctzg(value, cpp::numeric_limits<T>::digits);
83*bb722a7dSDimitry Andric }
84*bb722a7dSDimitry Andric #else
85*bb722a7dSDimitry Andric template <typename T>
86*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
countr_zero(T value)87*bb722a7dSDimitry Andric countr_zero(T value) {
88*bb722a7dSDimitry Andric if (!value)
89*bb722a7dSDimitry Andric return cpp::numeric_limits<T>::digits;
90*bb722a7dSDimitry Andric if (value & 0x1)
91*bb722a7dSDimitry Andric return 0;
92*bb722a7dSDimitry Andric // Bisection method.
93*bb722a7dSDimitry Andric unsigned zero_bits = 0;
94*bb722a7dSDimitry Andric unsigned shift = cpp::numeric_limits<T>::digits >> 1;
95*bb722a7dSDimitry Andric T mask = cpp::numeric_limits<T>::max() >> shift;
96*bb722a7dSDimitry Andric while (shift) {
97*bb722a7dSDimitry Andric if ((value & mask) == 0) {
98*bb722a7dSDimitry Andric value >>= shift;
99*bb722a7dSDimitry Andric zero_bits |= shift;
100*bb722a7dSDimitry Andric }
101*bb722a7dSDimitry Andric shift >>= 1;
102*bb722a7dSDimitry Andric mask >>= shift;
103*bb722a7dSDimitry Andric }
104*bb722a7dSDimitry Andric return static_cast<int>(zero_bits);
105*bb722a7dSDimitry Andric }
106*bb722a7dSDimitry Andric #if __has_builtin(__builtin_ctzs)
ADD_SPECIALIZATION(countr_zero,unsigned short,__builtin_ctzs)107*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countr_zero, unsigned short, __builtin_ctzs)
108*bb722a7dSDimitry Andric #endif
109*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countr_zero, unsigned int, __builtin_ctz)
110*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countr_zero, unsigned long, __builtin_ctzl)
111*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countr_zero, unsigned long long, __builtin_ctzll)
112*bb722a7dSDimitry Andric #endif // __has_builtin(__builtin_ctzg)
113*bb722a7dSDimitry Andric
114*bb722a7dSDimitry Andric /// Count number of 0's from the most significant bit to the least
115*bb722a7dSDimitry Andric /// stopping at the first 1.
116*bb722a7dSDimitry Andric ///
117*bb722a7dSDimitry Andric /// Only unsigned integral types are allowed.
118*bb722a7dSDimitry Andric ///
119*bb722a7dSDimitry Andric /// Returns cpp::numeric_limits<T>::digits on an input of 0.
120*bb722a7dSDimitry Andric // clang-19+, gcc-14+
121*bb722a7dSDimitry Andric #if __has_builtin(__builtin_clzg)
122*bb722a7dSDimitry Andric template <typename T>
123*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
124*bb722a7dSDimitry Andric countl_zero(T value) {
125*bb722a7dSDimitry Andric return __builtin_clzg(value, cpp::numeric_limits<T>::digits);
126*bb722a7dSDimitry Andric }
127*bb722a7dSDimitry Andric #else
128*bb722a7dSDimitry Andric template <typename T>
129*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
130*bb722a7dSDimitry Andric countl_zero(T value) {
131*bb722a7dSDimitry Andric if (!value)
132*bb722a7dSDimitry Andric return cpp::numeric_limits<T>::digits;
133*bb722a7dSDimitry Andric // Bisection method.
134*bb722a7dSDimitry Andric unsigned zero_bits = 0;
135*bb722a7dSDimitry Andric for (unsigned shift = cpp::numeric_limits<T>::digits >> 1; shift;
136*bb722a7dSDimitry Andric shift >>= 1) {
137*bb722a7dSDimitry Andric T tmp = value >> shift;
138*bb722a7dSDimitry Andric if (tmp)
139*bb722a7dSDimitry Andric value = tmp;
140*bb722a7dSDimitry Andric else
141*bb722a7dSDimitry Andric zero_bits |= shift;
142*bb722a7dSDimitry Andric }
143*bb722a7dSDimitry Andric return static_cast<int>(zero_bits);
144*bb722a7dSDimitry Andric }
145*bb722a7dSDimitry Andric #if __has_builtin(__builtin_clzs)
146*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countl_zero, unsigned short, __builtin_clzs)
147*bb722a7dSDimitry Andric #endif
148*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countl_zero, unsigned int, __builtin_clz)
149*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countl_zero, unsigned long, __builtin_clzl)
150*bb722a7dSDimitry Andric ADD_SPECIALIZATION(countl_zero, unsigned long long, __builtin_clzll)
151*bb722a7dSDimitry Andric #endif // __has_builtin(__builtin_clzg)
152*bb722a7dSDimitry Andric
153*bb722a7dSDimitry Andric #undef ADD_SPECIALIZATION
154*bb722a7dSDimitry Andric
155*bb722a7dSDimitry Andric /// Count the number of ones from the most significant bit to the first
156*bb722a7dSDimitry Andric /// zero bit.
157*bb722a7dSDimitry Andric ///
158*bb722a7dSDimitry Andric /// Ex. countl_one(0xFF0FFF00) == 8.
159*bb722a7dSDimitry Andric /// Only unsigned integral types are allowed.
160*bb722a7dSDimitry Andric ///
161*bb722a7dSDimitry Andric /// Returns cpp::numeric_limits<T>::digits on an input of all ones.
162*bb722a7dSDimitry Andric template <typename T>
163*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
countl_one(T value)164*bb722a7dSDimitry Andric countl_one(T value) {
165*bb722a7dSDimitry Andric return cpp::countl_zero<T>(static_cast<T>(~value));
166*bb722a7dSDimitry Andric }
167*bb722a7dSDimitry Andric
168*bb722a7dSDimitry Andric /// Count the number of ones from the least significant bit to the first
169*bb722a7dSDimitry Andric /// zero bit.
170*bb722a7dSDimitry Andric ///
171*bb722a7dSDimitry Andric /// Ex. countr_one(0x00FF00FF) == 8.
172*bb722a7dSDimitry Andric /// Only unsigned integral types are allowed.
173*bb722a7dSDimitry Andric ///
174*bb722a7dSDimitry Andric /// Returns cpp::numeric_limits<T>::digits on an input of all ones.
175*bb722a7dSDimitry Andric template <typename T>
176*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
countr_one(T value)177*bb722a7dSDimitry Andric countr_one(T value) {
178*bb722a7dSDimitry Andric return cpp::countr_zero<T>(static_cast<T>(~value));
179*bb722a7dSDimitry Andric }
180*bb722a7dSDimitry Andric
181*bb722a7dSDimitry Andric /// Returns the number of bits needed to represent value if value is nonzero.
182*bb722a7dSDimitry Andric /// Returns 0 otherwise.
183*bb722a7dSDimitry Andric ///
184*bb722a7dSDimitry Andric /// Ex. bit_width(5) == 3.
185*bb722a7dSDimitry Andric template <typename T>
186*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
bit_width(T value)187*bb722a7dSDimitry Andric bit_width(T value) {
188*bb722a7dSDimitry Andric return cpp::numeric_limits<T>::digits - cpp::countl_zero(value);
189*bb722a7dSDimitry Andric }
190*bb722a7dSDimitry Andric
191*bb722a7dSDimitry Andric /// Returns the largest integral power of two no greater than value if value is
192*bb722a7dSDimitry Andric /// nonzero. Returns 0 otherwise.
193*bb722a7dSDimitry Andric ///
194*bb722a7dSDimitry Andric /// Ex. bit_floor(5) == 4.
195*bb722a7dSDimitry Andric template <typename T>
196*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
bit_floor(T value)197*bb722a7dSDimitry Andric bit_floor(T value) {
198*bb722a7dSDimitry Andric if (!value)
199*bb722a7dSDimitry Andric return 0;
200*bb722a7dSDimitry Andric return static_cast<T>(T(1) << (cpp::bit_width(value) - 1));
201*bb722a7dSDimitry Andric }
202*bb722a7dSDimitry Andric
203*bb722a7dSDimitry Andric /// Returns the smallest integral power of two no smaller than value if value is
204*bb722a7dSDimitry Andric /// nonzero. Returns 1 otherwise.
205*bb722a7dSDimitry Andric ///
206*bb722a7dSDimitry Andric /// Ex. bit_ceil(5) == 8.
207*bb722a7dSDimitry Andric ///
208*bb722a7dSDimitry Andric /// The return value is undefined if the input is larger than the largest power
209*bb722a7dSDimitry Andric /// of two representable in T.
210*bb722a7dSDimitry Andric template <typename T>
211*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
bit_ceil(T value)212*bb722a7dSDimitry Andric bit_ceil(T value) {
213*bb722a7dSDimitry Andric if (value < 2)
214*bb722a7dSDimitry Andric return 1;
215*bb722a7dSDimitry Andric return static_cast<T>(T(1) << cpp::bit_width(value - 1U));
216*bb722a7dSDimitry Andric }
217*bb722a7dSDimitry Andric
218*bb722a7dSDimitry Andric // Rotate algorithms make use of "Safe, Efficient, and Portable Rotate in C/C++"
219*bb722a7dSDimitry Andric // from https://blog.regehr.org/archives/1063.
220*bb722a7dSDimitry Andric
221*bb722a7dSDimitry Andric // Forward-declare rotr so that rotl can use it.
222*bb722a7dSDimitry Andric template <typename T>
223*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
224*bb722a7dSDimitry Andric rotr(T value, int rotate);
225*bb722a7dSDimitry Andric
226*bb722a7dSDimitry Andric template <typename T>
227*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
rotl(T value,int rotate)228*bb722a7dSDimitry Andric rotl(T value, int rotate) {
229*bb722a7dSDimitry Andric constexpr int N = cpp::numeric_limits<T>::digits;
230*bb722a7dSDimitry Andric rotate = rotate % N;
231*bb722a7dSDimitry Andric if (!rotate)
232*bb722a7dSDimitry Andric return value;
233*bb722a7dSDimitry Andric if (rotate < 0)
234*bb722a7dSDimitry Andric return cpp::rotr<T>(value, -rotate);
235*bb722a7dSDimitry Andric return static_cast<T>((value << rotate) | (value >> (N - rotate)));
236*bb722a7dSDimitry Andric }
237*bb722a7dSDimitry Andric
238*bb722a7dSDimitry Andric template <typename T>
239*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
rotr(T value,int rotate)240*bb722a7dSDimitry Andric rotr(T value, int rotate) {
241*bb722a7dSDimitry Andric constexpr int N = cpp::numeric_limits<T>::digits;
242*bb722a7dSDimitry Andric rotate = rotate % N;
243*bb722a7dSDimitry Andric if (!rotate)
244*bb722a7dSDimitry Andric return value;
245*bb722a7dSDimitry Andric if (rotate < 0)
246*bb722a7dSDimitry Andric return cpp::rotl<T>(value, -rotate);
247*bb722a7dSDimitry Andric return static_cast<T>((value >> rotate) | (value << (N - rotate)));
248*bb722a7dSDimitry Andric }
249*bb722a7dSDimitry Andric
250*bb722a7dSDimitry Andric // TODO: Do we need this function at all? How is it different from
251*bb722a7dSDimitry Andric // 'static_cast'?
252*bb722a7dSDimitry Andric template <class To, class From>
bit_or_static_cast(const From & from)253*bb722a7dSDimitry Andric LIBC_INLINE constexpr To bit_or_static_cast(const From &from) {
254*bb722a7dSDimitry Andric if constexpr (sizeof(To) == sizeof(From)) {
255*bb722a7dSDimitry Andric return bit_cast<To>(from);
256*bb722a7dSDimitry Andric } else {
257*bb722a7dSDimitry Andric return static_cast<To>(from);
258*bb722a7dSDimitry Andric }
259*bb722a7dSDimitry Andric }
260*bb722a7dSDimitry Andric
261*bb722a7dSDimitry Andric /// Count number of 1's aka population count or Hamming weight.
262*bb722a7dSDimitry Andric ///
263*bb722a7dSDimitry Andric /// Only unsigned integral types are allowed.
264*bb722a7dSDimitry Andric // clang-19+, gcc-14+
265*bb722a7dSDimitry Andric #if __has_builtin(__builtin_popcountg)
266*bb722a7dSDimitry Andric template <typename T>
267*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
popcount(T value)268*bb722a7dSDimitry Andric popcount(T value) {
269*bb722a7dSDimitry Andric return __builtin_popcountg(value);
270*bb722a7dSDimitry Andric }
271*bb722a7dSDimitry Andric #else // !__has_builtin(__builtin_popcountg)
272*bb722a7dSDimitry Andric template <typename T>
273*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int>
popcount(T value)274*bb722a7dSDimitry Andric popcount(T value) {
275*bb722a7dSDimitry Andric int count = 0;
276*bb722a7dSDimitry Andric while (value) {
277*bb722a7dSDimitry Andric value &= value - 1;
278*bb722a7dSDimitry Andric ++count;
279*bb722a7dSDimitry Andric }
280*bb722a7dSDimitry Andric return count;
281*bb722a7dSDimitry Andric }
282*bb722a7dSDimitry Andric #define ADD_SPECIALIZATION(TYPE, BUILTIN) \
283*bb722a7dSDimitry Andric template <> \
284*bb722a7dSDimitry Andric [[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \
285*bb722a7dSDimitry Andric return BUILTIN(value); \
286*bb722a7dSDimitry Andric }
287*bb722a7dSDimitry Andric ADD_SPECIALIZATION(unsigned char, __builtin_popcount)
288*bb722a7dSDimitry Andric ADD_SPECIALIZATION(unsigned short, __builtin_popcount)
289*bb722a7dSDimitry Andric ADD_SPECIALIZATION(unsigned, __builtin_popcount)
290*bb722a7dSDimitry Andric ADD_SPECIALIZATION(unsigned long, __builtin_popcountl)
291*bb722a7dSDimitry Andric ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll)
292*bb722a7dSDimitry Andric #endif // __builtin_popcountg
293*bb722a7dSDimitry Andric #undef ADD_SPECIALIZATION
294*bb722a7dSDimitry Andric
295*bb722a7dSDimitry Andric } // namespace cpp
296*bb722a7dSDimitry Andric } // namespace LIBC_NAMESPACE_DECL
297*bb722a7dSDimitry Andric
298*bb722a7dSDimitry Andric #endif // LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
299