Skip to content

Commit f37614b

Browse files
[llvm] Move bit counting functions to bit.h (NFC)
This patch provides C++20-style countl_zero, countr_zero, countl_one, and countr_one in bit.h. Existing functions like countLeadingZeros become wrappers around the new functions. Note that I cannot quite declare countLeadingZeros as: template <class T> using countLeadingZeros = countl_zero<T>; because countl_zero returns int, whereas countLeadingZeros returns unsigned. Differential Revision: https://reviews.llvm.org/D142078
1 parent 71283fd commit f37614b

File tree

3 files changed

+277
-131
lines changed

3 files changed

+277
-131
lines changed

llvm/include/llvm/ADT/bit.h

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <cstdint>
1818
#include <cstring>
19+
#include <limits>
1920
#include <type_traits>
2021

2122
namespace llvm {
@@ -40,6 +41,181 @@ constexpr inline bool has_single_bit(T Value) noexcept {
4041
return (Value != 0) && ((Value & (Value - 1)) == 0);
4142
}
4243

44+
#ifdef _MSC_VER
45+
// Declare these intrinsics manually rather including intrin.h. It's very
46+
// expensive, and bit.h is popular via MathExtras.h.
47+
// #include <intrin.h>
48+
extern "C" {
49+
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
50+
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
51+
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
52+
unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
53+
}
54+
#endif
55+
56+
namespace detail {
57+
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
58+
static unsigned count(T Val) {
59+
if (!Val)
60+
return std::numeric_limits<T>::digits;
61+
if (Val & 0x1)
62+
return 0;
63+
64+
// Bisection method.
65+
unsigned ZeroBits = 0;
66+
T Shift = std::numeric_limits<T>::digits >> 1;
67+
T Mask = std::numeric_limits<T>::max() >> Shift;
68+
while (Shift) {
69+
if ((Val & Mask) == 0) {
70+
Val >>= Shift;
71+
ZeroBits |= Shift;
72+
}
73+
Shift >>= 1;
74+
Mask >>= Shift;
75+
}
76+
return ZeroBits;
77+
}
78+
};
79+
80+
#if defined(__GNUC__) || defined(_MSC_VER)
81+
template <typename T> struct TrailingZerosCounter<T, 4> {
82+
static unsigned count(T Val) {
83+
if (Val == 0)
84+
return 32;
85+
86+
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
87+
return __builtin_ctz(Val);
88+
#elif defined(_MSC_VER)
89+
unsigned long Index;
90+
_BitScanForward(&Index, Val);
91+
return Index;
92+
#endif
93+
}
94+
};
95+
96+
#if !defined(_MSC_VER) || defined(_M_X64)
97+
template <typename T> struct TrailingZerosCounter<T, 8> {
98+
static unsigned count(T Val) {
99+
if (Val == 0)
100+
return 64;
101+
102+
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
103+
return __builtin_ctzll(Val);
104+
#elif defined(_MSC_VER)
105+
unsigned long Index;
106+
_BitScanForward64(&Index, Val);
107+
return Index;
108+
#endif
109+
}
110+
};
111+
#endif
112+
#endif
113+
} // namespace detail
114+
115+
/// Count number of 0's from the least significant bit to the most
116+
/// stopping at the first 1.
117+
///
118+
/// Only unsigned integral types are allowed.
119+
///
120+
/// Returns std::numeric_limits<T>::digits on an input of 0.
121+
template <typename T> int countr_zero(T Val) {
122+
static_assert(std::is_unsigned_v<T>,
123+
"Only unsigned integral types are allowed.");
124+
return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val);
125+
}
126+
127+
namespace detail {
128+
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
129+
static unsigned count(T Val) {
130+
if (!Val)
131+
return std::numeric_limits<T>::digits;
132+
133+
// Bisection method.
134+
unsigned ZeroBits = 0;
135+
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
136+
T Tmp = Val >> Shift;
137+
if (Tmp)
138+
Val = Tmp;
139+
else
140+
ZeroBits |= Shift;
141+
}
142+
return ZeroBits;
143+
}
144+
};
145+
146+
#if defined(__GNUC__) || defined(_MSC_VER)
147+
template <typename T> struct LeadingZerosCounter<T, 4> {
148+
static unsigned count(T Val) {
149+
if (Val == 0)
150+
return 32;
151+
152+
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
153+
return __builtin_clz(Val);
154+
#elif defined(_MSC_VER)
155+
unsigned long Index;
156+
_BitScanReverse(&Index, Val);
157+
return Index ^ 31;
158+
#endif
159+
}
160+
};
161+
162+
#if !defined(_MSC_VER) || defined(_M_X64)
163+
template <typename T> struct LeadingZerosCounter<T, 8> {
164+
static unsigned count(T Val) {
165+
if (Val == 0)
166+
return 64;
167+
168+
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
169+
return __builtin_clzll(Val);
170+
#elif defined(_MSC_VER)
171+
unsigned long Index;
172+
_BitScanReverse64(&Index, Val);
173+
return Index ^ 63;
174+
#endif
175+
}
176+
};
177+
#endif
178+
#endif
179+
} // namespace detail
180+
181+
/// Count number of 0's from the most significant bit to the least
182+
/// stopping at the first 1.
183+
///
184+
/// Only unsigned integral types are allowed.
185+
///
186+
/// Returns std::numeric_limits<T>::digits on an input of 0.
187+
template <typename T> int countl_zero(T Val) {
188+
static_assert(std::is_unsigned_v<T>,
189+
"Only unsigned integral types are allowed.");
190+
return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val);
191+
}
192+
193+
/// Count the number of ones from the most significant bit to the first
194+
/// zero bit.
195+
///
196+
/// Ex. countl_one(0xFF0FFF00) == 8.
197+
/// Only unsigned integral types are allowed.
198+
///
199+
/// Returns std::numeric_limits<T>::digits on an input of all ones.
200+
template <typename T> int countl_one(T Value) {
201+
static_assert(std::is_unsigned_v<T>,
202+
"Only unsigned integral types are allowed.");
203+
return llvm::countl_zero<T>(~Value);
204+
}
205+
206+
/// Count the number of ones from the least significant bit to the first
207+
/// zero bit.
208+
///
209+
/// Ex. countr_one(0x00FF00FF) == 8.
210+
/// Only unsigned integral types are allowed.
211+
///
212+
/// Returns std::numeric_limits<T>::digits on an input of all ones.
213+
template <typename T> int countr_one(T Value) {
214+
static_assert(std::is_unsigned_v<T>,
215+
"Only unsigned integral types are allowed.");
216+
return llvm::countr_zero<T>(~Value);
217+
}
218+
43219
namespace detail {
44220
template <typename T, std::size_t SizeOfT> struct PopulationCounter {
45221
static int count(T Value) {

llvm/include/llvm/Support/MathExtras.h

Lines changed: 5 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,13 @@
1414
#define LLVM_SUPPORT_MATHEXTRAS_H
1515

1616
#include "llvm/ADT/bit.h"
17-
#include "llvm/Support/Compiler.h"
1817
#include <cassert>
1918
#include <climits>
2019
#include <cstdint>
2120
#include <cstring>
2221
#include <limits>
2322
#include <type_traits>
2423

25-
#ifdef _MSC_VER
26-
// Declare these intrinsics manually rather including intrin.h. It's very
27-
// expensive, and MathExtras.h is popular.
28-
// #include <intrin.h>
29-
extern "C" {
30-
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
31-
unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask);
32-
unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask);
33-
unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask);
34-
}
35-
#endif
36-
3724
namespace llvm {
3825

3926
/// The behavior an operation has on an input of 0.
@@ -80,65 +67,6 @@ constexpr float ef = 2.71828183F, // (0x1.5bf0a8P+1) https://oeis.org/A
8067
phif = 1.61803399F; // (0x1.9e377aP+0) https://oeis.org/A001622
8168
} // namespace numbers
8269

83-
namespace detail {
84-
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
85-
static unsigned count(T Val) {
86-
if (!Val)
87-
return std::numeric_limits<T>::digits;
88-
if (Val & 0x1)
89-
return 0;
90-
91-
// Bisection method.
92-
unsigned ZeroBits = 0;
93-
T Shift = std::numeric_limits<T>::digits >> 1;
94-
T Mask = std::numeric_limits<T>::max() >> Shift;
95-
while (Shift) {
96-
if ((Val & Mask) == 0) {
97-
Val >>= Shift;
98-
ZeroBits |= Shift;
99-
}
100-
Shift >>= 1;
101-
Mask >>= Shift;
102-
}
103-
return ZeroBits;
104-
}
105-
};
106-
107-
#if defined(__GNUC__) || defined(_MSC_VER)
108-
template <typename T> struct TrailingZerosCounter<T, 4> {
109-
static unsigned count(T Val) {
110-
if (Val == 0)
111-
return 32;
112-
113-
#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
114-
return __builtin_ctz(Val);
115-
#elif defined(_MSC_VER)
116-
unsigned long Index;
117-
_BitScanForward(&Index, Val);
118-
return Index;
119-
#endif
120-
}
121-
};
122-
123-
#if !defined(_MSC_VER) || defined(_M_X64)
124-
template <typename T> struct TrailingZerosCounter<T, 8> {
125-
static unsigned count(T Val) {
126-
if (Val == 0)
127-
return 64;
128-
129-
#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
130-
return __builtin_ctzll(Val);
131-
#elif defined(_MSC_VER)
132-
unsigned long Index;
133-
_BitScanForward64(&Index, Val);
134-
return Index;
135-
#endif
136-
}
137-
};
138-
#endif
139-
#endif
140-
} // namespace detail
141-
14270
/// Count number of 0's from the least significant bit to the most
14371
/// stopping at the first 1.
14472
///
@@ -148,62 +76,8 @@ template <typename T> struct TrailingZerosCounter<T, 8> {
14876
template <typename T> unsigned countTrailingZeros(T Val) {
14977
static_assert(std::is_unsigned_v<T>,
15078
"Only unsigned integral types are allowed.");
151-
return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val);
152-
}
153-
154-
namespace detail {
155-
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
156-
static unsigned count(T Val) {
157-
if (!Val)
158-
return std::numeric_limits<T>::digits;
159-
160-
// Bisection method.
161-
unsigned ZeroBits = 0;
162-
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
163-
T Tmp = Val >> Shift;
164-
if (Tmp)
165-
Val = Tmp;
166-
else
167-
ZeroBits |= Shift;
168-
}
169-
return ZeroBits;
170-
}
171-
};
172-
173-
#if defined(__GNUC__) || defined(_MSC_VER)
174-
template <typename T> struct LeadingZerosCounter<T, 4> {
175-
static unsigned count(T Val) {
176-
if (Val == 0)
177-
return 32;
178-
179-
#if __has_builtin(__builtin_clz) || defined(__GNUC__)
180-
return __builtin_clz(Val);
181-
#elif defined(_MSC_VER)
182-
unsigned long Index;
183-
_BitScanReverse(&Index, Val);
184-
return Index ^ 31;
185-
#endif
186-
}
187-
};
188-
189-
#if !defined(_MSC_VER) || defined(_M_X64)
190-
template <typename T> struct LeadingZerosCounter<T, 8> {
191-
static unsigned count(T Val) {
192-
if (Val == 0)
193-
return 64;
194-
195-
#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
196-
return __builtin_clzll(Val);
197-
#elif defined(_MSC_VER)
198-
unsigned long Index;
199-
_BitScanReverse64(&Index, Val);
200-
return Index ^ 63;
201-
#endif
202-
}
203-
};
204-
#endif
205-
#endif
206-
} // namespace detail
79+
return llvm::countr_zero(Val);
80+
}
20781

20882
/// Count number of 0's from the most significant bit to the least
20983
/// stopping at the first 1.
@@ -214,7 +88,7 @@ template <typename T> struct LeadingZerosCounter<T, 8> {
21488
template <typename T> unsigned countLeadingZeros(T Val) {
21589
static_assert(std::is_unsigned_v<T>,
21690
"Only unsigned integral types are allowed.");
217-
return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val);
91+
return llvm::countl_zero(Val);
21892
}
21993

22094
/// Get the index of the first set bit starting from the least
@@ -465,7 +339,7 @@ constexpr inline bool isPowerOf2_64(uint64_t Value) {
465339
template <typename T> unsigned countLeadingOnes(T Value) {
466340
static_assert(std::is_unsigned_v<T>,
467341
"Only unsigned integral types are allowed.");
468-
return countLeadingZeros<T>(~Value);
342+
return llvm::countl_one<T>(Value);
469343
}
470344

471345
/// Count the number of ones from the least significant bit to the first
@@ -478,7 +352,7 @@ template <typename T> unsigned countLeadingOnes(T Value) {
478352
template <typename T> unsigned countTrailingOnes(T Value) {
479353
static_assert(std::is_unsigned_v<T>,
480354
"Only unsigned integral types are allowed.");
481-
return countTrailingZeros<T>(~Value);
355+
return llvm::countr_one<T>(Value);
482356
}
483357

484358
/// Count the number of set bits in a value.

0 commit comments

Comments
 (0)