Skip to content

Conversation

@kazutakahirata
Copy link
Contributor

Without this patch, we implement 4-byte and 8-byte popcount as
structs.

This patch replaces the template trick with constexpr if, putting the
entire logic in the body of popcount.

Without this patch, we implement 4-byte and 8-byte popcount as
structs.

This patch replaces the template trick with constexpr if, putting the
entire logic in the body of popcount.
@llvmbot
Copy link
Member

llvmbot commented Jun 9, 2025

@llvm/pr-subscribers-llvm-adt

Author: Kazu Hirata (kazutakahirata)

Changes

Without this patch, we implement 4-byte and 8-byte popcount as
structs.

This patch replaces the template trick with constexpr if, putting the
entire logic in the body of popcount.


Full diff: https://github.com/llvm/llvm-project/pull/143339.diff

1 Files Affected:

  • (modified) llvm/include/llvm/ADT/bit.h (+9-19)
diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h
index b952825e574bc..d6e33c3e6133a 100644
--- a/llvm/include/llvm/ADT/bit.h
+++ b/llvm/include/llvm/ADT/bit.h
@@ -300,11 +300,12 @@ template <typename T> [[nodiscard]] T bit_ceil(T Value) {
   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) {
-    // Generic version, forward to 32 bits.
-    static_assert(SizeOfT <= 4, "Not implemented!");
+/// Count the number of set bits in a value.
+/// Ex. popcount(0xF000F000) = 8
+/// Returns 0 if the word is zero.
+template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
+[[nodiscard]] inline int popcount(T Value) noexcept {
+  if constexpr (sizeof(T) <= 4) {
 #if defined(__GNUC__)
     return (int)__builtin_popcount(Value);
 #else
@@ -313,11 +314,7 @@ template <typename T, std::size_t SizeOfT> struct PopulationCounter {
     v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
     return int(((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24);
 #endif
-  }
-};
-
-template <typename T> struct PopulationCounter<T, 8> {
-  static int count(T Value) {
+  } else if constexpr (sizeof(T) <= 8) {
 #if defined(__GNUC__)
     return (int)__builtin_popcountll(Value);
 #else
@@ -327,16 +324,9 @@ template <typename T> struct PopulationCounter<T, 8> {
     v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
     return int((uint64_t)(v * 0x0101010101010101ULL) >> 56);
 #endif
+  } else {
+    static_assert(sizeof(T) == 0, "T must be 8 bytes or less");
   }
-};
-} // namespace detail
-
-/// Count the number of set bits in a value.
-/// Ex. popcount(0xF000F000) = 8
-/// Returns 0 if the word is zero.
-template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
-[[nodiscard]] inline int popcount(T Value) noexcept {
-  return detail::PopulationCounter<T, sizeof(T)>::count(Value);
 }
 
 // Forward-declare rotr so that rotl can use it.

@kazutakahirata kazutakahirata merged commit 3dabeed into llvm:main Jun 9, 2025
9 checks passed
@kazutakahirata kazutakahirata deleted the cleanup_20250608_popcount branch June 9, 2025 05:38
tomtor pushed a commit to tomtor/llvm-project that referenced this pull request Jun 14, 2025
Without this patch, we implement 4-byte and 8-byte popcount as
structs.

This patch replaces the template trick with constexpr if, putting the
entire logic in the body of popcount.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants