Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[libc++] Add some _LIBCPP_ASSUMEs for bounded iterators #109033

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
Loading
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions 4 libcxx/include/__assert
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
// optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a
// discussion.
#if __has_builtin(__builtin_assume)
# define _LIBCPP_ASSUME(expression) \
(_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wassume") \
__builtin_assume(static_cast<bool>(expression)) _LIBCPP_DIAGNOSTIC_POP)
# define _LIBCPP_ASSUME(expression) __builtin_assume(static_cast<bool>(expression))
#else
# define _LIBCPP_ASSUME(expression) ((void)0)
#endif
Expand Down
12 changes: 12 additions & 0 deletions 12 libcxx/include/__iterator/bounded_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ struct __bounded_iter {
__begin <= __current, "__bounded_iter(current, begin, end): current and begin are inconsistent");
_LIBCPP_ASSERT_INTERNAL(
__current <= __end, "__bounded_iter(current, begin, end): current and end are inconsistent");

// Add assumptions to help the compiler reason about bounds checks. For example, std::vector sets the end of
// the __bounded_iter's valid range to the capacity of the vector, not vector::end(). To translate container-end
// fenceposts into hardening-end fenceposts, we must know that container-end <= hardening-end.
pointer __begin_ptr = std::__to_address(__begin);
pointer __current_ptr = std::__to_address(__current);
pointer __end_ptr = std::__to_address(__end);
_LIBCPP_ASSUME(__begin_ptr <= __current_ptr);
_LIBCPP_ASSUME(__current_ptr <= __end_ptr);
ldionne marked this conversation as resolved.
Show resolved Hide resolved
(void)__begin_ptr;
(void)__current_ptr;
(void)__end_ptr;
}

template <class _It>
Expand Down
12 changes: 11 additions & 1 deletion 12 libcxx/include/__vector/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,11 @@ class vector {

_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __make_iter(pointer __p) _NOEXCEPT {
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
// `__bounded_iter` will tell the compiler that `__p` is bounded by `__begin_` and `__end_cap`, but nothing a priori
// relates `__p` to `__end_`.
_LIBCPP_ASSERT_INTERNAL(__p <= this->__end_, "vector::__make_iter passed an invalid pointer");
_LIBCPP_ASSUME(__p <= this->__end_);

// Bound the iterator according to the capacity, rather than the size.
//
// Vector guarantees that iterators stay valid as long as no reallocation occurs even if new elements are inserted
Expand All @@ -678,7 +683,12 @@ class vector {

_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator __make_iter(const_pointer __p) const _NOEXCEPT {
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
// Bound the iterator according to the capacity, rather than the size.
// `__bounded_iter` will tell the compiler that `__p` is bounded by `__begin_` and `__end_cap`, but nothing a priori
// relates `__p` to `__end_`.
_LIBCPP_ASSERT_INTERNAL(__p <= this->__end_, "vector::__make_iter passed an invalid pointer");
_LIBCPP_ASSUME(__p <= this->__end_);

// Bound the iterator according to the capacity, rather than the size. See above.
return std::__make_bounded_iter(
std::__wrap_iter<const_pointer>(__p),
std::__wrap_iter<const_pointer>(this->__begin_),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,27 @@ void sequence_container_benchmarks(std::string container) {
}
});
}

/////////////////////////
// General usage patterns
/////////////////////////
bench("iterate-whole-container", [cheap](auto& st) {
auto const size = st.range(0);
std::vector<ValueType> in;
std::generate_n(std::back_inserter(in), size, cheap);
DoNotOptimizeData(in);

Container c(in.begin(), in.end());
DoNotOptimizeData(c);

auto use = [](auto& element) { benchmark::DoNotOptimize(element); };

for ([[maybe_unused]] auto _ : st) {
for (auto it = c.begin(); it != c.end(); ++it) {
use(*it);
}
}
});
}

} // namespace support
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.