Skip to content

Commit ffeea66

Browse files
[ADT] Add llvm::countr_zero_constexpr
This commit introduces llvm::countr_zero_constexpr as a constexpr version of llvm::countr_zero. The existing llvm::countr_zero is not constexpr due to its use of _BitScanForward. I'm planning to use the new function in PointerLikeTypeTraits.h as a replacement for ConstantLog2.
1 parent 193df2a commit ffeea66

File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed

llvm/include/llvm/ADT/bit.h

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,27 @@ template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
154154
/// Only unsigned integral types are allowed.
155155
///
156156
/// Returns std::numeric_limits<T>::digits on an input of 0.
157+
template <typename T> [[nodiscard]] constexpr int countr_zero_constexpr(T Val) {
158+
static_assert(std::is_unsigned_v<T>,
159+
"Only unsigned integral types are allowed.");
160+
if (!Val)
161+
return std::numeric_limits<T>::digits;
162+
163+
// Use the bisection method.
164+
unsigned ZeroBits = 0;
165+
T Shift = std::numeric_limits<T>::digits >> 1;
166+
T Mask = std::numeric_limits<T>::max() >> Shift;
167+
while (Shift) {
168+
if ((Val & Mask) == 0) {
169+
Val >>= Shift;
170+
ZeroBits |= Shift;
171+
}
172+
Shift >>= 1;
173+
Mask >>= Shift;
174+
}
175+
return ZeroBits;
176+
}
177+
157178
template <typename T> [[nodiscard]] int countr_zero(T Val) {
158179
static_assert(std::is_unsigned_v<T>,
159180
"Only unsigned integral types are allowed.");
@@ -179,19 +200,8 @@ template <typename T> [[nodiscard]] int countr_zero(T Val) {
179200
#endif
180201
}
181202

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;
203+
// Fall back to the constexpr implementation.
204+
return countr_zero_constexpr(Val);
195205
}
196206

197207
/// Count number of 0's from the most significant bit to the least

llvm/unittests/ADT/BitTest.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,26 @@ TEST(BitTest, CountlZero) {
279279
}
280280
}
281281

282+
TEST(BitTest, CountrZeroConstexpr) {
283+
constexpr uint8_t Z8 = 0;
284+
constexpr uint16_t Z16 = 0;
285+
constexpr uint32_t Z32 = 0;
286+
constexpr uint64_t Z64 = 0;
287+
static_assert(llvm::countr_zero_constexpr(Z8) == 8, "");
288+
static_assert(llvm::countr_zero_constexpr(Z16) == 16, "");
289+
static_assert(llvm::countr_zero_constexpr(Z32) == 32, "");
290+
static_assert(llvm::countr_zero_constexpr(Z64) == 64, "");
291+
292+
constexpr uint8_t NZ8 = 42;
293+
constexpr uint16_t NZ16 = 42;
294+
constexpr uint32_t NZ32 = 42;
295+
constexpr uint64_t NZ64 = 42;
296+
static_assert(llvm::countr_zero_constexpr(NZ8) == 1, "");
297+
static_assert(llvm::countr_zero_constexpr(NZ16) == 1, "");
298+
static_assert(llvm::countr_zero_constexpr(NZ32) == 1, "");
299+
static_assert(llvm::countr_zero_constexpr(NZ64) == 1, "");
300+
}
301+
282302
TEST(BitTest, CountrZero) {
283303
uint8_t Z8 = 0;
284304
uint16_t Z16 = 0;

0 commit comments

Comments
 (0)