[libc++] Add assumption for align of begin and end pointers of vector. (#108961)
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 https://github.com/llvm/llvm-project/issues/101372 for a discussion of missed range check optimizations in hardened mode. Once https://github.com/llvm/llvm-project/pull/108958 lands, the created `llvm.assume` calls for the alignment should be folded into the `load` instructions, resulting in no extra instructions after InstCombine. Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
This commit is contained in:
@@ -15,9 +15,7 @@
|
||||
#include <__config>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__type_traits/maybe_const.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/pair.h>
|
||||
|
||||
@@ -41,9 +39,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
||||
template <class _Owner, class _KeyContainer, class _MappedContainer, bool _Const>
|
||||
struct __key_value_iterator {
|
||||
private:
|
||||
using __key_iterator _LIBCPP_NODEBUG = ranges::iterator_t<const _KeyContainer>;
|
||||
using __mapped_iterator _LIBCPP_NODEBUG = ranges::iterator_t<__maybe_const<_Const, _MappedContainer>>;
|
||||
using __reference _LIBCPP_NODEBUG = _If<_Const, typename _Owner::const_reference, typename _Owner::reference>;
|
||||
using __key_iterator _LIBCPP_NODEBUG = typename _KeyContainer::const_iterator;
|
||||
using __mapped_iterator _LIBCPP_NODEBUG =
|
||||
_If<_Const, typename _MappedContainer::const_iterator, typename _MappedContainer::iterator>;
|
||||
using __reference _LIBCPP_NODEBUG = _If<_Const, typename _Owner::const_reference, typename _Owner::reference>;
|
||||
|
||||
struct __arrow_proxy {
|
||||
__reference __ref_;
|
||||
@@ -71,8 +70,8 @@ public:
|
||||
_LIBCPP_HIDE_FROM_ABI __key_value_iterator() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __key_value_iterator(__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, !_Const> __i)
|
||||
requires _Const && convertible_to<ranges::iterator_t<_KeyContainer>, __key_iterator> &&
|
||||
convertible_to<ranges::iterator_t<_MappedContainer>, __mapped_iterator>
|
||||
requires _Const && convertible_to<typename _KeyContainer::iterator, __key_iterator> &&
|
||||
convertible_to<typename _MappedContainer::iterator, __mapped_iterator>
|
||||
: __key_iter_(std::move(__i.__key_iter_)), __mapped_iter_(std::move(__i.__mapped_iter_)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __key_value_iterator(__key_iterator __key_iter, __mapped_iterator __mapped_iter)
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <__type_traits/is_constructible.h>
|
||||
#include <__type_traits/is_nothrow_assignable.h>
|
||||
#include <__type_traits/is_nothrow_constructible.h>
|
||||
#include <__type_traits/is_pointer.h>
|
||||
#include <__type_traits/is_same.h>
|
||||
#include <__type_traits/is_trivially_relocatable.h>
|
||||
#include <__type_traits/type_identity.h>
|
||||
@@ -341,13 +342,17 @@ public:
|
||||
//
|
||||
// Iterators
|
||||
//
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __make_iter(this->__begin_); }
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
|
||||
return __make_iter(this->__begin_);
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT {
|
||||
return __make_iter(__add_alignment_assumption(this->__begin_));
|
||||
}
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT {
|
||||
return __make_iter(__add_alignment_assumption(this->__begin_));
|
||||
}
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT {
|
||||
return __make_iter(__add_alignment_assumption(this->__end_));
|
||||
}
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __make_iter(this->__end_); }
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT {
|
||||
return __make_iter(this->__end_);
|
||||
return __make_iter(__add_alignment_assumption(this->__end_));
|
||||
}
|
||||
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT {
|
||||
@@ -775,6 +780,17 @@ private:
|
||||
}
|
||||
|
||||
_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 {
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
if constexpr (is_pointer<pointer>::value) {
|
||||
if (!__libcpp_is_constant_evaluated()) {
|
||||
return static_cast<pointer>(__builtin_assume_aligned(__p, alignof(decltype(*__p))));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return __p;
|
||||
}
|
||||
};
|
||||
|
||||
#if _LIBCPP_STD_VER >= 17
|
||||
|
||||
Reference in New Issue
Block a user