Skip to content

Commit 30f7c5d

Browse files
[ADT] Add bit_width_constexpr (#161775)
This patch adds llvm::bit_width_constexpr, a constexpr version of llvm::bit_width. 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::bit_width_constexpr, we can easily replace its use with std::bit_width. This patch refactors a couple of places. Specifically: - bitWidth in BitmaskEnum.h is replaced with the new function. - bitsRequired in PointerUnion.h is redefined in terms of the new function. I've used Compiler Explorer to check the equivalence: https://godbolt.org/z/1oKMK9Ez7
1 parent cd32b9b commit 30f7c5d

File tree

4 files changed

+43
-6
lines changed

4 files changed

+43
-6
lines changed

llvm/include/llvm/ADT/BitmaskEnum.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <utility>
1515

1616
#include "llvm/ADT/STLForwardCompat.h"
17+
#include "llvm/ADT/bit.h"
1718
#include "llvm/Support/MathExtras.h"
1819

1920
/// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can
@@ -138,10 +139,6 @@ template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {
138139
return U;
139140
}
140141

141-
constexpr unsigned bitWidth(uint64_t Value) {
142-
return Value ? 1 + bitWidth(Value >> 1) : 0;
143-
}
144-
145142
template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
146143
constexpr bool operator!(E Val) {
147144
return Val == static_cast<E>(0);
@@ -220,7 +217,7 @@ e &operator>>=(e &lhs, e rhs) {
220217
// Enable bitmask enums in namespace ::llvm and all nested namespaces.
221218
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
222219
template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
223-
constexpr unsigned BitWidth = BitmaskEnumDetail::bitWidth(
220+
constexpr unsigned BitWidth = llvm::bit_width_constexpr(
224221
uint64_t{llvm::to_underlying(E::LLVM_BITMASK_LARGEST_ENUMERATOR)});
225222

226223
} // namespace llvm

llvm/include/llvm/ADT/PointerUnion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace pointer_union_detail {
3131
/// Determine the number of bits required to store integers with values < n.
3232
/// This is ceil(log2(n)).
3333
constexpr int bitsRequired(unsigned n) {
34-
return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
34+
return n == 0 ? 0 : llvm::bit_width_constexpr(n - 1);
3535
}
3636

3737
template <typename... Ts> constexpr int lowBitsAvailable() {

llvm/include/llvm/ADT/bit.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,23 @@ template <typename T> [[nodiscard]] int bit_width(T Value) {
292292
return std::numeric_limits<T>::digits - llvm::countl_zero(Value);
293293
}
294294

295+
/// Returns the number of bits needed to represent Value if Value is nonzero.
296+
/// Returns 0 otherwise.
297+
///
298+
/// A constexpr version of bit_width.
299+
///
300+
/// Ex. bit_width_constexpr(5) == 3.
301+
template <typename T> [[nodiscard]] constexpr int bit_width_constexpr(T Value) {
302+
static_assert(std::is_unsigned_v<T>,
303+
"Only unsigned integral types are allowed.");
304+
int Width = 0;
305+
while (Value > 0) {
306+
Value >>= 1;
307+
++Width;
308+
}
309+
return Width;
310+
}
311+
295312
/// Returns the largest integral power of two no greater than Value if Value is
296313
/// nonzero. Returns 0 otherwise.
297314
///

llvm/unittests/ADT/BitTest.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,29 @@ TEST(BitTest, BitWidth) {
247247
EXPECT_EQ(64, llvm::bit_width(uint64_t(0xffffffffffffffffull)));
248248
}
249249

250+
TEST(BitTest, BitWidthConstexpr) {
251+
static_assert(llvm::bit_width_constexpr(0u) == 0);
252+
static_assert(llvm::bit_width_constexpr(1u) == 1);
253+
static_assert(llvm::bit_width_constexpr(2u) == 2);
254+
static_assert(llvm::bit_width_constexpr(3u) == 2);
255+
static_assert(llvm::bit_width_constexpr(4u) == 3);
256+
static_assert(llvm::bit_width_constexpr(5u) == 3);
257+
static_assert(llvm::bit_width_constexpr(6u) == 3);
258+
static_assert(llvm::bit_width_constexpr(7u) == 3);
259+
static_assert(llvm::bit_width_constexpr(8u) == 4);
260+
261+
static_assert(llvm::bit_width_constexpr(255u) == 8);
262+
static_assert(llvm::bit_width_constexpr(256u) == 9);
263+
static_assert(llvm::bit_width_constexpr(257u) == 9);
264+
265+
static_assert(
266+
llvm::bit_width_constexpr(std::numeric_limits<uint16_t>::max()) == 16);
267+
static_assert(
268+
llvm::bit_width_constexpr(std::numeric_limits<uint32_t>::max()) == 32);
269+
static_assert(
270+
llvm::bit_width_constexpr(std::numeric_limits<uint64_t>::max()) == 64);
271+
}
272+
250273
TEST(BitTest, CountlZero) {
251274
uint8_t Z8 = 0;
252275
uint16_t Z16 = 0;

0 commit comments

Comments
 (0)