-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[ADT] Add llvm::countr_zero_constexpr #164188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ADT] Add llvm::countr_zero_constexpr #164188
Conversation
This patch implements llvm::countr_zero_constexpr, a constexpr version of llvm::countr_zero, in terms of llvm::popcount while making llvm::popcount a constexpr function at the same time. The new function is intended to serve as a marker. When we switch to C++20, we will most likely go through functions in llvm/ADT/bit.h and replace them with their counterparts from <bit>. With llvm::countr_zero_constexpr, we can easily replace its use with std::countr_zero. This patch reimplements ConstantLog2 in terms of the new function.
@llvm/pr-subscribers-llvm-adt @llvm/pr-subscribers-llvm-support Author: Kazu Hirata (kazutakahirata) ChangesThis patch implements llvm::countr_zero_constexpr, a constexpr version The new function is intended to serve as a marker. When we switch to This patch reimplements ConstantLog2 in terms of the new function. Full diff: https://github.com/llvm/llvm-project/pull/164188.diff 3 Files Affected:
diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h
index 8b60b6998ca0b..2ea6c2a7f0a1d 100644
--- a/llvm/include/llvm/ADT/bit.h
+++ b/llvm/include/llvm/ADT/bit.h
@@ -151,7 +151,8 @@ template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
/// Count the number of set bits in a value.
/// Ex. popcount(0xF000F000) = 8
/// Returns 0 if Value is zero.
-template <typename T> [[nodiscard]] inline int popcount(T Value) noexcept {
+template <typename T>
+[[nodiscard]] constexpr inline int popcount(T Value) noexcept {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned integer type");
static_assert(sizeof(T) <= 8, "T must be 8 bytes or less");
@@ -177,6 +178,22 @@ template <typename T> [[nodiscard]] inline int popcount(T Value) noexcept {
}
}
+/// Count number of 0's from the least significant bit to the most
+/// stopping at the first 1.
+///
+/// A constexpr version of countr_zero.
+///
+/// Only unsigned integral types are allowed.
+///
+/// Returns std::numeric_limits<T>::digits on an input of 0.
+template <typename T> [[nodiscard]] constexpr int countr_zero_constexpr(T Val) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ // "(Val & -Val) - 1" is a bitmask with all bits below
+ // the least significant 1 set.
+ return llvm::popcount(static_cast<std::make_unsigned_t<T>>((Val & -Val) - 1));
+}
+
/// Count number of 0's from the least significant bit to the most
/// stopping at the first 1.
///
@@ -208,9 +225,7 @@ template <typename T> [[nodiscard]] int countr_zero(T Val) {
#endif
}
- // Fallback to popcount. "(Val & -Val) - 1" is a bitmask with all bits below
- // the least significant 1 set.
- return llvm::popcount(static_cast<std::make_unsigned_t<T>>((Val & -Val) - 1));
+ return countr_zero_constexpr(Val);
}
/// Count number of 0's from the most significant bit to the least
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 412323354525b..9bbb8a2a30541 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -316,11 +316,9 @@ inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
/// Valid only for positive powers of two.
template <size_t kValue> constexpr size_t ConstantLog2() {
static_assert(llvm::isPowerOf2_64(kValue), "Value is not a valid power of 2");
- return 1 + ConstantLog2<kValue / 2>();
+ return llvm::countr_zero_constexpr(kValue);
}
-template <> constexpr size_t ConstantLog2<1>() { return 0; }
-
template <size_t kValue>
LLVM_DEPRECATED("Use ConstantLog2 instead", "ConstantLog2")
constexpr size_t CTLog2() {
diff --git a/llvm/unittests/ADT/BitTest.cpp b/llvm/unittests/ADT/BitTest.cpp
index 5b3df918e62b0..e8041bb6f7f58 100644
--- a/llvm/unittests/ADT/BitTest.cpp
+++ b/llvm/unittests/ADT/BitTest.cpp
@@ -286,6 +286,28 @@ TEST(BitTest, BitCeilConstexpr) {
static_assert(llvm::bit_ceil_constexpr(257u) == 512);
}
+TEST(BitTest, CountrZeroConstexpr) {
+ static_assert(llvm::countr_zero_constexpr(0u) == 32);
+ static_assert(llvm::countr_zero_constexpr(1u) == 0);
+ static_assert(llvm::countr_zero_constexpr(2u) == 1);
+ static_assert(llvm::countr_zero_constexpr(3u) == 0);
+ static_assert(llvm::countr_zero_constexpr(4u) == 2);
+ static_assert(llvm::countr_zero_constexpr(8u) == 3);
+ static_assert(llvm::countr_zero_constexpr(0x80000000u) == 31);
+
+ static_assert(llvm::countr_zero_constexpr(0ull) == 64);
+ static_assert(llvm::countr_zero_constexpr(1ull) == 0);
+ static_assert(llvm::countr_zero_constexpr(0x100000000ull) == 32);
+ static_assert(llvm::countr_zero_constexpr(0x8000000000000000ull) == 63);
+
+ static_assert(
+ llvm::countr_zero_constexpr(std::numeric_limits<uint16_t>::max()) == 0);
+ static_assert(
+ llvm::countr_zero_constexpr(std::numeric_limits<uint32_t>::max()) == 0);
+ static_assert(
+ llvm::countr_zero_constexpr(std::numeric_limits<uint64_t>::max()) == 0);
+}
+
TEST(BitTest, CountlZero) {
uint8_t Z8 = 0;
uint16_t Z16 = 0;
|
@kuhar Please take a look again. Thanks! |
✅ With the latest revision this PR passed the C/C++ code formatter. |
This patch implements llvm::countr_zero_constexpr, a constexpr version
of llvm::countr_zero, in terms of llvm::popcount while making
llvm::popcount a constexpr function at the same time.
The new function is intended to serve as a marker. When we switch to
C++20, we will most likely go through functions in llvm/ADT/bit.h and
replace them with their counterparts from . With
llvm::countr_zero_constexpr, we can easily replace its use with
std::countr_zero.
This patch reimplements ConstantLog2 in terms of the new function.