Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions llvm/include/llvm/ADT/bit.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ 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 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");

Expand All @@ -178,7 +178,23 @@ 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.
/// 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" generates a mask with all bits set up to (but not
// including) the least significant set bit of Val.
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.
///
/// Only unsigned integral types are allowed.
///
Expand Down Expand Up @@ -208,9 +224,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
Expand Down
4 changes: 1 addition & 3 deletions llvm/include/llvm/Support/MathExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
22 changes: 22 additions & 0 deletions llvm/unittests/ADT/BitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading