[llvm] [orc-rt] Add substitutes for std::countl_zero and std::bit_width. (PR #157076)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 5 04:17:27 PDT 2025


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/157076

These can be used until the ORC runtime can assume c++-20 or greater.

>From 588e692b2fedce151b1ca8194499a81e98304faa Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Fri, 5 Sep 2025 21:11:42 +1000
Subject: [PATCH] [orc-rt] Add substitutes for std::countl_zero and
 std::bit_width.

These can be used until the ORC runtime can assume c++-20 or greater.
---
 orc-rt/include/orc-rt/bit.h   | 23 +++++++++++
 orc-rt/unittests/bit-test.cpp | 74 +++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/orc-rt/include/orc-rt/bit.h b/orc-rt/include/orc-rt/bit.h
index d86c047e0973f..241a529436de5 100644
--- a/orc-rt/include/orc-rt/bit.h
+++ b/orc-rt/include/orc-rt/bit.h
@@ -17,6 +17,7 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <limits>
 #include <type_traits>
 #if defined(_MSC_VER) && !defined(_DEBUG)
 #include <stdlib.h>
@@ -105,6 +106,28 @@ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
   }
 }
 
+/// Calculates the number of leading zeros.
+template <typename T, typename _ = std::enable_if_t<std::is_unsigned_v<T>>>
+[[nodiscard]] constexpr int countl_zero(T Val) noexcept {
+  if (!Val)
+    return std::numeric_limits<T>::digits;
+
+  unsigned ZeroBits = 0;
+  for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
+    T Tmp = Val >> Shift;
+    if (Tmp)
+      Val = Tmp;
+    else
+      ZeroBits |= Shift;
+  }
+  return ZeroBits;
+}
+
+template <typename T, typename _ = std::enable_if_t<std::is_unsigned_v<T>>>
+[[nodiscard]] constexpr int bit_width(T x) noexcept {
+  return std::numeric_limits<T>::digits - countl_zero(x);
+}
+
 } // namespace orc_rt
 
 #endif // ORC_RT_BIT_H
diff --git a/orc-rt/unittests/bit-test.cpp b/orc-rt/unittests/bit-test.cpp
index 86e4633a5b505..fabf62b771365 100644
--- a/orc-rt/unittests/bit-test.cpp
+++ b/orc-rt/unittests/bit-test.cpp
@@ -77,3 +77,77 @@ TEST(BitTest, byte_swap_64) {
   ADD_FAILURE() << "BYTE_ORDER is neither BIG_ENDIAN nor LITTLE_ENDIAN.";
 #endif
 }
+
+TEST(BitTest, CountlZero) {
+  uint8_t Z8 = 0;
+  uint16_t Z16 = 0;
+  uint32_t Z32 = 0;
+  uint64_t Z64 = 0;
+  EXPECT_EQ(8, llvm::countl_zero(Z8));
+  EXPECT_EQ(16, llvm::countl_zero(Z16));
+  EXPECT_EQ(32, llvm::countl_zero(Z32));
+  EXPECT_EQ(64, llvm::countl_zero(Z64));
+
+  uint8_t NZ8 = 42;
+  uint16_t NZ16 = 42;
+  uint32_t NZ32 = 42;
+  uint64_t NZ64 = 42;
+  EXPECT_EQ(2, llvm::countl_zero(NZ8));
+  EXPECT_EQ(10, llvm::countl_zero(NZ16));
+  EXPECT_EQ(26, llvm::countl_zero(NZ32));
+  EXPECT_EQ(58, llvm::countl_zero(NZ64));
+
+  EXPECT_EQ(8, llvm::countl_zero(0x00F000FFu));
+  EXPECT_EQ(8, llvm::countl_zero(0x00F12345u));
+  for (unsigned i = 0; i <= 30; ++i) {
+    EXPECT_EQ(int(31 - i), llvm::countl_zero(1u << i));
+  }
+
+  EXPECT_EQ(8, llvm::countl_zero(0x00F1234500F12345ULL));
+  EXPECT_EQ(1, llvm::countl_zero(1ULL << 62));
+  for (unsigned i = 0; i <= 62; ++i) {
+    EXPECT_EQ(int(63 - i), llvm::countl_zero(1ULL << i));
+  }
+}
+
+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)));
+}



More information about the llvm-commits mailing list