From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 808CF3857348; Wed, 31 May 2023 20:20:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 808CF3857348 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1685564405; bh=v06IQsqHRvwRIF4xDlER4dUXpDNnnZBJxi+Aa+ejX5M=; h=From:To:Subject:Date:From; b=Z8OM0bk0XY+ekx2wz/wVE87srlJIzzudDSXviSXd0cAa3Bykisbv8/X9w7Qd1bldm gXGzjexUgV9T3O97uXZs541u1FYNClrmwfvzpdbLWfc8lcOr4aD8GotN++DvHacGIo J6VtM/9ZKhzojyJ2Q+KXAS4j4BgODdaAQGVhxCFw= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r14-1452] libstdc++: Express std::vector's size() <= capacity() invariant in code X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: a239a35075ffd8b34f1db72c22998a625ff962b5 X-Git-Newrev: fb409a15d9babc78fe1d9957afcbaf1102cce58f Message-Id: <20230531202005.808CF3857348@sourceware.org> Date: Wed, 31 May 2023 20:20:05 +0000 (GMT) List-Id: https://gcc.gnu.org/g:fb409a15d9babc78fe1d9957afcbaf1102cce58f commit r14-1452-gfb409a15d9babc78fe1d9957afcbaf1102cce58f Author: Jonathan Wakely Date: Thu May 25 09:57:46 2023 +0100 libstdc++: Express std::vector's size() <= capacity() invariant in code This adds optimizer hints so that GCC knows that size() <= capacity() is always true. This allows the compiler to optimize away re-allocating paths when assigning new values to the vector without resizing it, e.g., vec.assign(vec.size(), new_val). libstdc++-v3/ChangeLog: * include/bits/stl_vector.h (_Vector_base::_M_invariant()): New function. (vector::size(), vector::capacity()): Call _M_invariant(). * testsuite/23_containers/vector/capacity/invariant.cc: New test. * testsuite/23_containers/vector/types/1.cc: Add suppression for false positive warning (PR110060). Diff: --- libstdc++-v3/include/bits/stl_vector.h | 30 +++++++++++++++++++--- .../23_containers/vector/capacity/invariant.cc | 16 ++++++++++++ .../testsuite/23_containers/vector/types/1.cc | 2 +- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index acb29396d26..e593be443bc 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -388,6 +388,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } protected: + + __attribute__((__always_inline__)) + _GLIBCXX20_CONSTEXPR void + _M_invariant() const + { +#if __OPTIMIZE__ + if (this->_M_impl._M_finish < this->_M_impl._M_start) + __builtin_unreachable(); + if (this->_M_impl._M_finish > this->_M_impl._M_end_of_storage) + __builtin_unreachable(); + + size_t __sz = this->_M_impl._M_finish - this->_M_impl._M_start; + size_t __cap = this->_M_impl._M_end_of_storage - this->_M_impl._M_start; + if (__sz > __cap) + __builtin_unreachable(); +#endif + } + _GLIBCXX20_CONSTEXPR void _M_create_storage(size_t __n) @@ -987,7 +1005,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type size() const _GLIBCXX_NOEXCEPT - { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } + { + _Base::_M_invariant(); + return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); + } /** Returns the size() of the largest possible %vector. */ _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR @@ -1073,8 +1094,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type capacity() const _GLIBCXX_NOEXCEPT - { return size_type(this->_M_impl._M_end_of_storage - - this->_M_impl._M_start); } + { + _Base::_M_invariant(); + return size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + } /** * Returns true if the %vector is empty. (Thus begin() would diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/invariant.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/invariant.cc new file mode 100644 index 00000000000..d68db694add --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/invariant.cc @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-O3 -g0" } +// { dg-final { scan-assembler-not "_Znw" } } +// GCC should be able to optimize away the paths involving reallocation. + +#include + +void fill(std::vector& vec) +{ + vec.assign(vec.size(), 0); +} + +void fill_val(std::vector& vec, int i) +{ + vec.assign(vec.size(), i); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/types/1.cc b/libstdc++-v3/testsuite/23_containers/vector/types/1.cc index 079e5af9556..9be07d9fd5c 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/types/1.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/types/1.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-options "-Wno-unused-result" } +// { dg-options "-Wno-unused-result -Wno-stringop-overread" } #include #include