diff --git a/llvm/include/llvm/ADT/BitmaskEnum.h b/llvm/include/llvm/ADT/BitmaskEnum.h index 7214f25b0aa10..d464cbcfcdffd 100644 --- a/llvm/include/llvm/ADT/BitmaskEnum.h +++ b/llvm/include/llvm/ADT/BitmaskEnum.h @@ -14,6 +14,7 @@ #include #include "llvm/ADT/STLForwardCompat.h" +#include "llvm/ADT/bit.h" #include "llvm/Support/MathExtras.h" /// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can @@ -138,10 +139,6 @@ template constexpr std::underlying_type_t Underlying(E Val) { return U; } -constexpr unsigned bitWidth(uint64_t Value) { - return Value ? 1 + bitWidth(Value >> 1) : 0; -} - template ::value>> constexpr bool operator!(E Val) { return Val == static_cast(0); @@ -220,7 +217,7 @@ e &operator>>=(e &lhs, e rhs) { // Enable bitmask enums in namespace ::llvm and all nested namespaces. LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); template ::value>> -constexpr unsigned BitWidth = BitmaskEnumDetail::bitWidth( +constexpr unsigned BitWidth = llvm::bit_width_constexpr( uint64_t{llvm::to_underlying(E::LLVM_BITMASK_LARGEST_ENUMERATOR)}); } // namespace llvm diff --git a/llvm/include/llvm/ADT/PointerUnion.h b/llvm/include/llvm/ADT/PointerUnion.h index ca0e1ed3d49d1..7b66177373011 100644 --- a/llvm/include/llvm/ADT/PointerUnion.h +++ b/llvm/include/llvm/ADT/PointerUnion.h @@ -31,7 +31,7 @@ namespace pointer_union_detail { /// Determine the number of bits required to store integers with values < n. /// This is ceil(log2(n)). constexpr int bitsRequired(unsigned n) { - return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0; + return n == 0 ? 0 : llvm::bit_width_constexpr(n - 1); } template constexpr int lowBitsAvailable() { diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h index 67c0a1c3300fa..66c4f94813241 100644 --- a/llvm/include/llvm/ADT/bit.h +++ b/llvm/include/llvm/ADT/bit.h @@ -292,6 +292,23 @@ template [[nodiscard]] int bit_width(T Value) { return std::numeric_limits::digits - llvm::countl_zero(Value); } +/// Returns the number of bits needed to represent Value if Value is nonzero. +/// Returns 0 otherwise. +/// +/// A constexpr version of bit_width. +/// +/// Ex. bit_width_constexpr(5) == 3. +template [[nodiscard]] constexpr int bit_width_constexpr(T Value) { + static_assert(std::is_unsigned_v, + "Only unsigned integral types are allowed."); + int Width = 0; + while (Value > 0) { + Value >>= 1; + ++Width; + } + return Width; +} + /// Returns the largest integral power of two no greater than Value if Value is /// nonzero. Returns 0 otherwise. /// diff --git a/llvm/unittests/ADT/BitTest.cpp b/llvm/unittests/ADT/BitTest.cpp index 88ae36c44bdb9..eaed4e1fe327d 100644 --- a/llvm/unittests/ADT/BitTest.cpp +++ b/llvm/unittests/ADT/BitTest.cpp @@ -247,6 +247,29 @@ TEST(BitTest, BitWidth) { EXPECT_EQ(64, llvm::bit_width(uint64_t(0xffffffffffffffffull))); } +TEST(BitTest, BitWidthConstexpr) { + static_assert(llvm::bit_width_constexpr(0u) == 0); + static_assert(llvm::bit_width_constexpr(1u) == 1); + static_assert(llvm::bit_width_constexpr(2u) == 2); + static_assert(llvm::bit_width_constexpr(3u) == 2); + static_assert(llvm::bit_width_constexpr(4u) == 3); + static_assert(llvm::bit_width_constexpr(5u) == 3); + static_assert(llvm::bit_width_constexpr(6u) == 3); + static_assert(llvm::bit_width_constexpr(7u) == 3); + static_assert(llvm::bit_width_constexpr(8u) == 4); + + static_assert(llvm::bit_width_constexpr(255u) == 8); + static_assert(llvm::bit_width_constexpr(256u) == 9); + static_assert(llvm::bit_width_constexpr(257u) == 9); + + static_assert( + llvm::bit_width_constexpr(std::numeric_limits::max()) == 16); + static_assert( + llvm::bit_width_constexpr(std::numeric_limits::max()) == 32); + static_assert( + llvm::bit_width_constexpr(std::numeric_limits::max()) == 64); +} + TEST(BitTest, CountlZero) { uint8_t Z8 = 0; uint16_t Z16 = 0;