-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[libc++] Add assumption for align of begin and end pointers of vector. #108961
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
@llvm/pr-subscribers-libcxx Author: Florian Hahn (fhahn) ChangesMissing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. See #101372 for a discussion of missed range check optimizations in hardened mode. Once #108958 lands, the created Full diff: https://github.com/llvm/llvm-project/pull/108961.diff 1 Files Affected:
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 7d3aac5989a48c..720b46d573c954 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -1027,6 +1027,10 @@ private:
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {}
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __add_alignment_assumption(pointer __p) _NOEXCEPT {
+ return static_cast<pointer>(__builtin_assume_aligned(__p, alignof(decltype(*__p))));
+ }
};
#if _LIBCPP_STD_VER >= 17
@@ -1418,25 +1422,25 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::assign(size_type __n
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::begin() _NOEXCEPT {
- return __make_iter(this->__begin_);
+ return __make_iter(__add_alignment_assumption(this->__begin_));
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::const_iterator
vector<_Tp, _Allocator>::begin() const _NOEXCEPT {
- return __make_iter(this->__begin_);
+ return __make_iter(__add_alignment_assumption(this->__begin_));
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::end() _NOEXCEPT {
- return __make_iter(this->__end_);
+ return __make_iter(__add_alignment_assumption(this->__end_));
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::const_iterator
vector<_Tp, _Allocator>::end() const _NOEXCEPT {
- return __make_iter(this->__end_);
+ return __make_iter(__add_alignment_assumption(this->__end_));
}
template <class _Tp, class _Allocator>
|
libcxx/include/vector
Outdated
|
||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __add_alignment_assumption(pointer __p) _NOEXCEPT { | ||
return static_cast<pointer>(__builtin_assume_aligned(__p, alignof(decltype(*__p)))); | ||
} |
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.
Does this work with fancy pointers? Also, shouldn't the compiler be able to infer this?
Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM. See llvm#101372 for a discussion of missed range check optimizations in hardened mode. Once llvm#108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine.
83f60da
to
94c2ede
Compare
Otherwise, this prevents us from being able to declare a flat_map containing an incomplete type.
@@ -15,9 +15,7 @@ | |||
#include <__config> |
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.
@huixie90 Do these changes look correct to you? Is there a reason why you used ranges::iterator_t
in the first place?
Use known bits to remove redundant alignment assumptions. Libc++ now adds alignment assumptions for std::vector::begin() and std::vector::end(), so I expect we will see quite a bit more assumptions in C++ [1]. Try to clean up some redundant ones to start with. [1] llvm#108961
Use known bits to remove redundant alignment assumptions. Libc++ now adds alignment assumptions for std::vector::begin() and std::vector::end(), so I expect we will see quite a bit more assumptions in C++ [1]. Try to clean up some redundant ones to start with. [1] llvm#108961
Use known bits to remove redundant alignment assumptions. Libc++ now adds alignment assumptions for std::vector::begin() and std::vector::end(), so I expect we will see quite a bit more assumptions in C++ [1]. Try to clean up some redundant ones to start with. [1] llvm#108961
@@ -775,6 +780,17 @@ class _LIBCPP_TEMPLATE_VIS vector { | |||
} | |||
|
|||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(vector&, false_type) _NOEXCEPT {} | |||
|
|||
static _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __add_alignment_assumption(pointer __p) _NOEXCEPT { |
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.
Similarly to #118837 (review) I think this one needs _LIBCPP_NO_CFI
since we're potentially static_cast'ing uninitialized memory (for the end pointer).
(Apologies for the late notice, we're a bit behind on libc++.)
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.
Ack. I'd be curious to see how this failure can be reproduced. Is it just a matter of adding a -fsanitize=cfi
job to our pre-commit CI?
CF #124837
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.
Also #124839 for adding NO_CFI
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 haven't tried to reproduce it on the libc++ tests directly, but it should be possible. I think we're currently only using a subset of the cfi checks: -fsanitize=cfi-vcall -fsanitize=cfi-derived-cast -fsanitize=cfi-unrelated-cast
. The annoying thing is that cfi requires (thin) lto.
#ifndef _LIBCPP_CXX03_LANG | ||
if constexpr (is_pointer<pointer>::value) { |
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.
@ldionne Are we using constexpr if
in C++11/14 as a compiler extension here? I've also noticed several other usages of constexpr if
in C++14 mode in libc++.
Does this imply that we can generally use constexpr if
within the context of C++11/14 in libc++?
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, it's fine to use compiler extensions in the library as long as our supported compilers implement them.
Missing information about begin and end pointers of std::vector can lead to missed optimizations in LLVM.
This patch adds alignment assumptions at the point where the begin and end pointers are loaded. If the pointers would not have the same alignment, end might never get hit when incrementing begin.
See #101372 for a discussion of missed range check optimizations in hardened mode.
Once #108958 lands, the created
llvm.assume
calls for the alignment should be folded into theload
instructions, resulting in no extra instructions after InstCombine.