diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h index 8b60b6998ca0b..5971b75045b6b 100644 --- a/llvm/include/llvm/ADT/bit.h +++ b/llvm/include/llvm/ADT/bit.h @@ -151,7 +151,7 @@ template >> /// Count the number of set bits in a value. /// Ex. popcount(0xF000F000) = 8 /// Returns 0 if Value is zero. -template [[nodiscard]] inline int popcount(T Value) noexcept { +template [[nodiscard]] constexpr int popcount(T Value) noexcept { static_assert(std::is_unsigned_v, "T must be an unsigned integer type"); static_assert(sizeof(T) <= 8, "T must be 8 bytes or less"); @@ -178,7 +178,23 @@ template [[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. +/// stopping at the first 1. +/// +/// A constexpr version of countr_zero. +/// +/// Only unsigned integral types are allowed. +/// +/// Returns std::numeric_limits::digits on an input of 0. +template [[nodiscard]] constexpr int countr_zero_constexpr(T Val) { + static_assert(std::is_unsigned_v, + "Only unsigned integral types are allowed."); + // "(Val & -Val) - 1" generates a mask with all bits set up to (but not + // including) the least significant set bit of Val. + return llvm::popcount(static_cast>((Val & -Val) - 1)); +} + +/// Count number of 0's from the least significant bit to the most +/// stopping at the first 1. /// /// Only unsigned integral types are allowed. /// @@ -208,9 +224,7 @@ template [[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>((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 constexpr size_t ConstantLog2() { static_assert(llvm::isPowerOf2_64(kValue), "Value is not a valid power of 2"); - return 1 + ConstantLog2(); + return llvm::countr_zero_constexpr(kValue); } -template <> constexpr size_t ConstantLog2<1>() { return 0; } - template 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::max()) == 0); + static_assert( + llvm::countr_zero_constexpr(std::numeric_limits::max()) == 0); + static_assert( + llvm::countr_zero_constexpr(std::numeric_limits::max()) == 0); +} + TEST(BitTest, CountlZero) { uint8_t Z8 = 0; uint16_t Z16 = 0;