[llvm] eaabc1b - [ADT] Add bit_floor, bit_ceil, and bit_width to bit.h
Kazu Hirata via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 20 19:34:49 PST 2023
Author: Kazu Hirata
Date: 2023-01-20T19:34:42-08:00
New Revision: eaabc1bbeaa057bac3fe699bebda1472dc2ae03b
URL: https://github.com/llvm/llvm-project/commit/eaabc1bbeaa057bac3fe699bebda1472dc2ae03b
DIFF: https://github.com/llvm/llvm-project/commit/eaabc1bbeaa057bac3fe699bebda1472dc2ae03b.diff
LOG: [ADT] Add bit_floor, bit_ceil, and bit_width to bit.h
This patch adds C++20-style bit_floor, bit_ceil, and bit_width.
In a subsequent patch, I'm going to define PowerOf2Floor in
MathExtras.h in terms of bit_floor.
Unfortunately, PowerOf2Ceil isn't quite the same as bit_ceil because
PowerOf2Ceil(0) == 0, whereas bit_ceil(0) == 1.
MathExtras.h does not have a function directly corresponding to
bit_width, but Log2_32(X) + 1, which occurs in a few places, can be
replaced with bit_width(X).
Differential Revision: https://reviews.llvm.org/D142179
Added:
Modified:
llvm/include/llvm/ADT/bit.h
llvm/unittests/ADT/BitTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h
index 126e57ea6a27..39bb508ccdff 100644
--- a/llvm/include/llvm/ADT/bit.h
+++ b/llvm/include/llvm/ADT/bit.h
@@ -217,6 +217,43 @@ template <typename T> int countr_one(T Value) {
return llvm::countr_zero<T>(~Value);
}
+/// Returns the number of bits needed to represent Value if Value is nonzero.
+/// Returns 0 otherwise.
+///
+/// Ex. bit_width(5) == 3.
+template <typename T> int bit_width(T Value) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ return std::numeric_limits<T>::digits - llvm::countl_zero(Value);
+}
+
+/// Returns the largest integral power of two no greater than Value if Value is
+/// nonzero. Returns 0 otherwise.
+///
+/// Ex. bit_floor(5) == 4.
+template <typename T> T bit_floor(T Value) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ if (!Value)
+ return 0;
+ return T(1) << (llvm::bit_width(Value) - 1);
+}
+
+/// Returns the smallest integral power of two no smaller than Value if Value is
+/// nonzero. Returns 0 otherwise.
+///
+/// Ex. bit_ceil(5) == 8.
+///
+/// The return value is undefined if the input is larger than the largest power
+/// of two representable in T.
+template <typename T> T bit_ceil(T Value) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ if (Value < 2)
+ return 1;
+ return T(1) << llvm::bit_width<T>(Value - 1u);
+}
+
namespace detail {
template <typename T, std::size_t SizeOfT> struct PopulationCounter {
static int count(T Value) {
diff --git a/llvm/unittests/ADT/BitTest.cpp b/llvm/unittests/ADT/BitTest.cpp
index 7f154d75b353..08ec31f23071 100644
--- a/llvm/unittests/ADT/BitTest.cpp
+++ b/llvm/unittests/ADT/BitTest.cpp
@@ -48,6 +48,127 @@ TEST(BitTest, HasSingleBit) {
EXPECT_TRUE(llvm::has_single_bit(static_cast<uint16_t>(kValueS16)));
}
+TEST(BitTest, BitFloor) {
+ EXPECT_EQ(0u, llvm::bit_floor(uint8_t(0)));
+ EXPECT_EQ(0u, llvm::bit_floor(uint16_t(0)));
+ EXPECT_EQ(0u, llvm::bit_floor(uint32_t(0)));
+ EXPECT_EQ(0u, llvm::bit_floor(uint64_t(0)));
+
+ EXPECT_EQ(1u, llvm::bit_floor(uint8_t(1)));
+ EXPECT_EQ(1u, llvm::bit_floor(uint16_t(1)));
+ EXPECT_EQ(1u, llvm::bit_floor(uint32_t(1)));
+ EXPECT_EQ(1u, llvm::bit_floor(uint64_t(1)));
+
+ EXPECT_EQ(2u, llvm::bit_floor(uint8_t(2)));
+ EXPECT_EQ(2u, llvm::bit_floor(uint16_t(2)));
+ EXPECT_EQ(2u, llvm::bit_floor(uint32_t(2)));
+ EXPECT_EQ(2u, llvm::bit_floor(uint64_t(2)));
+
+ EXPECT_EQ(2u, llvm::bit_floor(uint8_t(3)));
+ EXPECT_EQ(2u, llvm::bit_floor(uint16_t(3)));
+ EXPECT_EQ(2u, llvm::bit_floor(uint32_t(3)));
+ EXPECT_EQ(2u, llvm::bit_floor(uint64_t(3)));
+
+ EXPECT_EQ(4u, llvm::bit_floor(uint8_t(4)));
+ EXPECT_EQ(4u, llvm::bit_floor(uint16_t(4)));
+ EXPECT_EQ(4u, llvm::bit_floor(uint32_t(4)));
+ EXPECT_EQ(4u, llvm::bit_floor(uint64_t(4)));
+
+ EXPECT_EQ(0x40u, llvm::bit_floor(uint8_t(0x7f)));
+ EXPECT_EQ(0x4000u, llvm::bit_floor(uint16_t(0x7fff)));
+ EXPECT_EQ(0x40000000u, llvm::bit_floor(uint32_t(0x7fffffffu)));
+ EXPECT_EQ(0x4000000000000000ull,
+ llvm::bit_floor(uint64_t(0x7fffffffffffffffull)));
+
+ EXPECT_EQ(0x80u, llvm::bit_floor(uint8_t(0x80)));
+ EXPECT_EQ(0x8000u, llvm::bit_floor(uint16_t(0x8000)));
+ EXPECT_EQ(0x80000000u, llvm::bit_floor(uint32_t(0x80000000u)));
+ EXPECT_EQ(0x8000000000000000ull,
+ llvm::bit_floor(uint64_t(0x8000000000000000ull)));
+
+ EXPECT_EQ(0x80u, llvm::bit_floor(uint8_t(0xff)));
+ EXPECT_EQ(0x8000u, llvm::bit_floor(uint16_t(0xffff)));
+ EXPECT_EQ(0x80000000u, llvm::bit_floor(uint32_t(0xffffffffu)));
+ EXPECT_EQ(0x8000000000000000ull,
+ llvm::bit_floor(uint64_t(0xffffffffffffffffull)));
+}
+
+TEST(BitTest, BitCeil) {
+ EXPECT_EQ(1u, llvm::bit_ceil(uint8_t(0)));
+ EXPECT_EQ(1u, llvm::bit_ceil(uint16_t(0)));
+ EXPECT_EQ(1u, llvm::bit_ceil(uint32_t(0)));
+ EXPECT_EQ(1u, llvm::bit_ceil(uint64_t(0)));
+
+ EXPECT_EQ(1u, llvm::bit_ceil(uint8_t(1)));
+ EXPECT_EQ(1u, llvm::bit_ceil(uint16_t(1)));
+ EXPECT_EQ(1u, llvm::bit_ceil(uint32_t(1)));
+ EXPECT_EQ(1u, llvm::bit_ceil(uint64_t(1)));
+
+ EXPECT_EQ(2u, llvm::bit_ceil(uint8_t(2)));
+ EXPECT_EQ(2u, llvm::bit_ceil(uint16_t(2)));
+ EXPECT_EQ(2u, llvm::bit_ceil(uint32_t(2)));
+ EXPECT_EQ(2u, llvm::bit_ceil(uint64_t(2)));
+
+ EXPECT_EQ(4u, llvm::bit_ceil(uint8_t(3)));
+ EXPECT_EQ(4u, llvm::bit_ceil(uint16_t(3)));
+ EXPECT_EQ(4u, llvm::bit_ceil(uint32_t(3)));
+ EXPECT_EQ(4u, llvm::bit_ceil(uint64_t(3)));
+
+ EXPECT_EQ(4u, llvm::bit_ceil(uint8_t(4)));
+ EXPECT_EQ(4u, llvm::bit_ceil(uint16_t(4)));
+ EXPECT_EQ(4u, llvm::bit_ceil(uint32_t(4)));
+ EXPECT_EQ(4u, llvm::bit_ceil(uint64_t(4)));
+
+ // The result is the largest representable value for each type.
+ EXPECT_EQ(0x80u, llvm::bit_ceil(uint8_t(0x7f)));
+ EXPECT_EQ(0x8000u, llvm::bit_ceil(uint16_t(0x7fff)));
+ EXPECT_EQ(0x80000000u, llvm::bit_ceil(uint32_t(0x7fffffffu)));
+ EXPECT_EQ(0x8000000000000000ull,
+ llvm::bit_ceil(uint64_t(0x7fffffffffffffffull)));
+}
+
+TEST(BitTest, BitWidth) {
+ EXPECT_EQ(0, llvm::bit_width(uint8_t(0)));
+ EXPECT_EQ(0, llvm::bit_width(uint16_t(0)));
+ EXPECT_EQ(0, llvm::bit_width(uint32_t(0)));
+ EXPECT_EQ(0, llvm::bit_width(uint64_t(0)));
+
+ EXPECT_EQ(1, llvm::bit_width(uint8_t(1)));
+ EXPECT_EQ(1, llvm::bit_width(uint16_t(1)));
+ EXPECT_EQ(1, llvm::bit_width(uint32_t(1)));
+ EXPECT_EQ(1, llvm::bit_width(uint64_t(1)));
+
+ EXPECT_EQ(2, llvm::bit_width(uint8_t(2)));
+ EXPECT_EQ(2, llvm::bit_width(uint16_t(2)));
+ EXPECT_EQ(2, llvm::bit_width(uint32_t(2)));
+ EXPECT_EQ(2, llvm::bit_width(uint64_t(2)));
+
+ EXPECT_EQ(2, llvm::bit_width(uint8_t(3)));
+ EXPECT_EQ(2, llvm::bit_width(uint16_t(3)));
+ EXPECT_EQ(2, llvm::bit_width(uint32_t(3)));
+ EXPECT_EQ(2, llvm::bit_width(uint64_t(3)));
+
+ EXPECT_EQ(3, llvm::bit_width(uint8_t(4)));
+ EXPECT_EQ(3, llvm::bit_width(uint16_t(4)));
+ EXPECT_EQ(3, llvm::bit_width(uint32_t(4)));
+ EXPECT_EQ(3, llvm::bit_width(uint64_t(4)));
+
+ EXPECT_EQ(7, llvm::bit_width(uint8_t(0x7f)));
+ EXPECT_EQ(15, llvm::bit_width(uint16_t(0x7fff)));
+ EXPECT_EQ(31, llvm::bit_width(uint32_t(0x7fffffffu)));
+ EXPECT_EQ(63, llvm::bit_width(uint64_t(0x7fffffffffffffffull)));
+
+ EXPECT_EQ(8, llvm::bit_width(uint8_t(0x80)));
+ EXPECT_EQ(16, llvm::bit_width(uint16_t(0x8000)));
+ EXPECT_EQ(32, llvm::bit_width(uint32_t(0x80000000u)));
+ EXPECT_EQ(64, llvm::bit_width(uint64_t(0x8000000000000000ull)));
+
+ EXPECT_EQ(8, llvm::bit_width(uint8_t(0xff)));
+ EXPECT_EQ(16, llvm::bit_width(uint16_t(0xffff)));
+ EXPECT_EQ(32, llvm::bit_width(uint32_t(0xffffffffu)));
+ EXPECT_EQ(64, llvm::bit_width(uint64_t(0xffffffffffffffffull)));
+}
+
TEST(BitTest, CountlZero) {
uint8_t Z8 = 0;
uint16_t Z16 = 0;
More information about the llvm-commits
mailing list