Skip to content

Conversation

philnik777
Copy link
Contributor

@philnik777 philnik777 commented Sep 24, 2025

#119632 introduced a code size and performance regression. This was verified by running the included benchmark against trunk and trunk with #119632 reverted. Instead of actually reverting that patch, we can inline __construct_at_end into the few places it's used instead, simplifying the implementation further (by not handling special cases we never actually encounter).

Benchmark                   Baseline    Candidate    Difference    % Difference
------------------------  ----------  -----------  ------------  --------------
BM_vector_bool_size_ctor       29.91         8.56        -21.35          -71.37

@ldionne ldionne marked this pull request as ready for review September 24, 2025 14:33
@ldionne ldionne requested a review from a team as a code owner September 24, 2025 14:33
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.

Can you please add a simple benchmark and also explain that we believe #119632 introduced a slight regression in some cases when the compiler could previously inline constructors -- for context.

@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Sep 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 24, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

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

1 Files Affected:

  • (modified) libcxx/include/__vector/vector_bool.h (+8-19)
diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index 7b82906769255..66f5fd9498eec 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -478,7 +478,6 @@ class vector<bool, _Allocator> {
     return (__new_size + (__bits_per_word - 1)) & ~((size_type)__bits_per_word - 1);
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __new_size) const;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_at_end(size_type __n, bool __x);
   template <class _InputIterator, class _Sentinel>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
   __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n);
@@ -567,20 +566,6 @@ vector<bool, _Allocator>::__recommend(size_type __new_size) const {
   return std::max<size_type>(2 * __cap, __align_it(__new_size));
 }
 
-//  Default constructs __n objects starting at __end_
-//  Precondition:  size() + __n <= capacity()
-//  Postcondition:  size() == size() + __n
-template <class _Allocator>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
-vector<bool, _Allocator>::__construct_at_end(size_type __n, bool __x) {
-  _LIBCPP_ASSERT_INTERNAL(
-      capacity() >= size() + __n, "vector<bool>::__construct_at_end called with insufficient capacity");
-  std::fill_n(end(), __n, __x);
-  this->__size_ += __n;
-  if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero
-    std::fill_n(end(), __bits_per_word - end().__ctz_, 0);
-}
-
 template <class _Allocator>
 template <class _InputIterator, class _Sentinel>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void
@@ -613,7 +598,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n)
     : __begin_(nullptr), __size_(0), __cap_(0) {
   if (__n > 0) {
     __vallocate(__n);
-    __construct_at_end(__n, false);
+    std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0));
+    __size_ = __n;
   }
 }
 
@@ -623,7 +609,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
     : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   if (__n > 0) {
     __vallocate(__n);
-    __construct_at_end(__n, false);
+    std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0));
+    __size_ = __n;
   }
 }
 #endif
@@ -633,7 +620,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
     : __begin_(nullptr), __size_(0), __cap_(0) {
   if (__n > 0) {
     __vallocate(__n);
-    __construct_at_end(__n, __x);
+    std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0) - __x);
+    __size_ = __n;
   }
 }
 
@@ -643,7 +631,8 @@ vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const all
     : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   if (__n > 0) {
     __vallocate(__n);
-    __construct_at_end(__n, __x);
+    std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0) - __x);
+    __size_ = __n;
   }
 }
 

#include <benchmark/benchmark.h>
#include <vector>

static void BM_vector_bool_size_ctor(benchmark::State& state) {
Copy link
Member

Choose a reason for hiding this comment

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

I assume it doesn't work to use the generic sequence benchmarks since vector<bool> is "special"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, exactly. I wanted to use them first, but vector<bool> isn't a sequence container, so the benchmarks don't work properly.

@philnik777 philnik777 merged commit 96a7c9b into llvm:main Sep 25, 2025
71 of 73 checks passed
@philnik777 philnik777 deleted the simplify_vector_bool branch September 25, 2025 17:48
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
llvm#119632 introduced a code size and performance regression. This was
verified by running the included benchmark against trunk and trunk with
llvm#119632 reverted. Instead of actually reverting that patch, we can
inline `__construct_at_end` into the few places it's used instead,
simplifying the implementation further (by not handling special cases we
never actually encounter).

```
Benchmark                   Baseline    Candidate    Difference    % Difference
------------------------  ----------  -----------  ------------  --------------
BM_vector_bool_size_ctor       29.91         8.56        -21.35          -71.37
```
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