-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[libc++] Simplify vector<bool> fill constructors #160521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this 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.
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) ChangesFull diff: https://github.com/llvm/llvm-project/pull/160521.diff 1 Files Affected:
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;
}
}
|
e924a4a
to
87ec9d5
Compare
#include <benchmark/benchmark.h> | ||
#include <vector> | ||
|
||
static void BM_vector_bool_size_ctor(benchmark::State& state) { |
There was a problem hiding this comment.
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"?
There was a problem hiding this comment.
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.
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 ```
#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).