Skip to content

Commit d692380

Browse files
[ADT] Define countr_zero in terms of popcount (NFC) (#158519)
We can express the fallback mechanism of llvm::countr_zero a lot more concisely with llvm::popcount. Since llvm::countr_zero now requires llvm::popcount, this patch moves llvm::popcount earlier.
1 parent 7b0d910 commit d692380

File tree

1 file changed

+32
-42
lines changed
  • llvm/include/llvm/ADT

1 file changed

+32
-42
lines changed

llvm/include/llvm/ADT/bit.h

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,35 @@ template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
148148
return (Value != 0) && ((Value & (Value - 1)) == 0);
149149
}
150150

151+
/// Count the number of set bits in a value.
152+
/// Ex. popcount(0xF000F000) = 8
153+
/// Returns 0 if Value is zero.
154+
template <typename T> [[nodiscard]] inline int popcount(T Value) noexcept {
155+
static_assert(std::is_unsigned_v<T>, "T must be an unsigned integer type");
156+
static_assert(sizeof(T) <= 8, "T must be 8 bytes or less");
157+
158+
if constexpr (sizeof(T) <= 4) {
159+
#if defined(__GNUC__)
160+
return (int)__builtin_popcount(Value);
161+
#else
162+
uint32_t V = Value;
163+
V = V - ((V >> 1) & 0x55555555);
164+
V = (V & 0x33333333) + ((V >> 2) & 0x33333333);
165+
return int(((V + (V >> 4) & 0xF0F0F0F) * 0x1010101) >> 24);
166+
#endif
167+
} else {
168+
#if defined(__GNUC__)
169+
return (int)__builtin_popcountll(Value);
170+
#else
171+
uint64_t V = Value;
172+
V = V - ((V >> 1) & 0x5555555555555555ULL);
173+
V = (V & 0x3333333333333333ULL) + ((V >> 2) & 0x3333333333333333ULL);
174+
V = (V + (V >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
175+
return int((uint64_t)(V * 0x0101010101010101ULL) >> 56);
176+
#endif
177+
}
178+
}
179+
151180
/// Count number of 0's from the least significant bit to the most
152181
/// stopping at the first 1.
153182
///
@@ -179,19 +208,9 @@ template <typename T> [[nodiscard]] int countr_zero(T Val) {
179208
#endif
180209
}
181210

182-
// Fall back to the bisection method.
183-
unsigned ZeroBits = 0;
184-
T Shift = std::numeric_limits<T>::digits >> 1;
185-
T Mask = std::numeric_limits<T>::max() >> Shift;
186-
while (Shift) {
187-
if ((Val & Mask) == 0) {
188-
Val >>= Shift;
189-
ZeroBits |= Shift;
190-
}
191-
Shift >>= 1;
192-
Mask >>= Shift;
193-
}
194-
return ZeroBits;
211+
// Fallback to popcount. "(Val & -Val) - 1" is a bitmask with all bits below
212+
// the least significant 1 set.
213+
return llvm::popcount(static_cast<std::make_unsigned_t<T>>((Val & -Val) - 1));
195214
}
196215

197216
/// Count number of 0's from the most significant bit to the least
@@ -300,35 +319,6 @@ template <typename T> [[nodiscard]] T bit_ceil(T Value) {
300319
return T(1) << llvm::bit_width<T>(Value - 1u);
301320
}
302321

303-
/// Count the number of set bits in a value.
304-
/// Ex. popcount(0xF000F000) = 8
305-
/// Returns 0 if the word is zero.
306-
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
307-
[[nodiscard]] inline int popcount(T Value) noexcept {
308-
if constexpr (sizeof(T) <= 4) {
309-
#if defined(__GNUC__)
310-
return (int)__builtin_popcount(Value);
311-
#else
312-
uint32_t v = Value;
313-
v = v - ((v >> 1) & 0x55555555);
314-
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
315-
return int(((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24);
316-
#endif
317-
} else if constexpr (sizeof(T) <= 8) {
318-
#if defined(__GNUC__)
319-
return (int)__builtin_popcountll(Value);
320-
#else
321-
uint64_t v = Value;
322-
v = v - ((v >> 1) & 0x5555555555555555ULL);
323-
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
324-
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
325-
return int((uint64_t)(v * 0x0101010101010101ULL) >> 56);
326-
#endif
327-
} else {
328-
static_assert(sizeof(T) == 0, "T must be 8 bytes or less");
329-
}
330-
}
331-
332322
// Forward-declare rotr so that rotl can use it.
333323
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
334324
[[nodiscard]] constexpr T rotr(T V, int R);

0 commit comments

Comments
 (0)