Skip to content

Conversation

@winner245
Copy link
Contributor

@winner245 winner245 commented Feb 24, 2025

This patch refactors the all() and any() methods in bitset to eliminate redundant code while preserving the performance. Code generation remains unchanged, as verified on Compiler Explorer.

@winner245 winner245 force-pushed the simplify-bitset-any-all branch from 30e237c to 097854d Compare February 24, 2025 03:40
@winner245 winner245 force-pushed the simplify-bitset-any-all branch from 097854d to 509e87c Compare March 3, 2025 22:48
@winner245 winner245 marked this pull request as ready for review March 12, 2025 23:26
@winner245 winner245 requested a review from a team as a code owner March 12, 2025 23:26
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 12, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 12, 2025

@llvm/pr-subscribers-libcxx

Author: Peng Liu (winner245)

Changes

The any() and all() member functions of bitset are implemented using the same bitwise logic as std::find() with __bit_iterator optimizations. Therefore, we can simplify any() and all() to one line by directly calling std::find, and inline them within the class.


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

1 Files Affected:

  • (modified) libcxx/include/bitset (+8-48)
diff --git a/libcxx/include/bitset b/libcxx/include/bitset
index f905b6f274e3f..8d0a5ec67a748 100644
--- a/libcxx/include/bitset
+++ b/libcxx/include/bitset
@@ -224,8 +224,12 @@ protected:
     return to_ullong(integral_constant < bool, _Size< sizeof(unsigned long long) * CHAR_BIT>());
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT {
+    return std::find(__make_iter(0), __make_iter(_Size), false) == __make_iter(_Size);
+  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT {
+    return std::find(__make_iter(0), __make_iter(_Size), true) != __make_iter(_Size);
+  }
   _LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;
 
 private:
@@ -388,40 +392,6 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const {
   return __r;
 }
 
-template <size_t _N_words, size_t _Size>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<_N_words, _Size>::all() const _NOEXCEPT {
-  // do middle whole words
-  size_t __n                  = _Size;
-  __const_storage_pointer __p = __first_;
-  for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
-    if (~*__p)
-      return false;
-  // do last partial word
-  if (__n > 0) {
-    __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
-    if (~*__p & __m)
-      return false;
-  }
-  return true;
-}
-
-template <size_t _N_words, size_t _Size>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool __bitset<_N_words, _Size>::any() const _NOEXCEPT {
-  // do middle whole words
-  size_t __n                  = _Size;
-  __const_storage_pointer __p = __first_;
-  for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
-    if (*__p)
-      return true;
-  // do last partial word
-  if (__n > 0) {
-    __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
-    if (*__p & __m)
-      return true;
-  }
-  return false;
-}
-
 template <size_t _N_words, size_t _Size>
 inline size_t __bitset<_N_words, _Size>::__hash_code() const _NOEXCEPT {
   size_t __h = 0;
@@ -713,8 +683,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI bool operator!=(const bitset& __rhs) const _NOEXCEPT;
 #  endif
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool test(size_t __pos) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT;
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return __base::all(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT { return __base::any(); }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool none() const _NOEXCEPT { return !any(); }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator<<(size_t __pos) const _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator>>(size_t __pos) const _NOEXCEPT;
@@ -901,16 +871,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool bitset<_Size>::test(siz
   return (*this)[__pos];
 }
 
-template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool bitset<_Size>::all() const _NOEXCEPT {
-  return __base::all();
-}
-
-template <size_t _Size>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool bitset<_Size>::any() const _NOEXCEPT {
-  return __base::any();
-}
-
 template <size_t _Size>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size>
 bitset<_Size>::operator<<(size_t __pos) const _NOEXCEPT {

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but can you please confirm that the codegen is the same?

@ldionne ldionne added the pending-ci Merging the PR is only pending completion of CI label May 12, 2025
@winner245
Copy link
Contributor Author

In terms of codegen (https://godbolt.org/z/cdEbbTTnY at -O2), I found that the previous implementation generates more efficient assembly as it directly checks the underlying storage. In contrast, my proposed implementation introduces function calls to std::__find and __bit_iterator, resulting in additional stack operations. This indicates that the original implementation has advantages in terms of performance. I will explore ways to refactor it while maintaining efficiency.

@ldionne ldionne removed the pending-ci Merging the PR is only pending completion of CI label May 14, 2025
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes since this degrades codegen.

@winner245 winner245 force-pushed the simplify-bitset-any-all branch 2 times, most recently from 669261f to 28fb22d Compare May 17, 2025 16:15
@winner245 winner245 changed the title [libc++] Simplify bitset::{any, all} [libc++] Refactor bitset::{any, all} May 17, 2025
@winner245
Copy link
Contributor Author

winner245 commented May 17, 2025

The new refactoring yields exactly the same code in terms of codegen, as verified on https://godbolt.org/z/xx8hb4sPM.

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the refactoring! I have a minor suggestion but LGTM otherwise.

_LIBCPP_HIDE_FROM_ABI size_t __hash_code() const _NOEXCEPT;

private:
struct __bit_not {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't block this patch on it, however it might be nice to consider a follow-up refactoring.

We have a __bit_not in valarray here: https://github.com/llvm/llvm-project/blob/main/libcxx/include/valarray#L491

We could provide a single __bit_not in https://github.com/llvm/llvm-project/blob/main/libcxx/include/__functional/operations.h#L220 and use it from both valarray and bitset.

@winner245 winner245 force-pushed the simplify-bitset-any-all branch from 28fb22d to 018d34e Compare May 21, 2025 19:27
@github-actions
Copy link

github-actions bot commented May 21, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@winner245 winner245 force-pushed the simplify-bitset-any-all branch from 018d34e to 255b057 Compare May 21, 2025 19:31
@winner245 winner245 force-pushed the simplify-bitset-any-all branch from 255b057 to f26d014 Compare May 21, 2025 19:35
@ldionne ldionne merged commit 4ad230b into llvm:main May 28, 2025
329 of 379 checks passed
@winner245 winner245 deleted the simplify-bitset-any-all branch June 1, 2025 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants