On Tue, 26 Nov 2024 at 15:43, Jan Hubicka <hubi...@ucw.cz> wrote: > > Hi, > here is updated patch. > > I am not ceratin if: > const size_t __diffmax > = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_CharT); > really needs "/ sizeof (_CharT)". I think we only need to be able to > compute the difference between two entries in multiplies of sizeof(_CharT)? > However it is consistent with what std::vector does. Do we really need > to be also able to represent differences in number of bytes? > > I was also thinking about API change implication. I hope that indeed > real code does not need knowing max size and it is mostly needed to let > GCC to VRP optimize the memory allocations. > > I also noticed that this patch trigger empty-loop.C failure which I > originaly attributed to different change. I filled PR117764 on that. > We are no longer able to eliminate empty loops early, but we still > optimize them late. > > I also changed empty() to do the test directly (as done by std::vector > and friends) instead of computing size. I do not think having > __builtin_unreachable range check is useful there, so this should save > some compile-time effort.
Yes, that makes sense. > Bootstrapped/regtested x86_64-linux, OK? Looks good, OK for trunk, thanks. > > libstdc++-v3/ChangeLog: > > * include/bits/basic_string.h (basic_string::size(), > basic_string::length(), basic_string::capacity()): Add > __builtin_unreachable to declare value ranges. > (basic_string::empty): Inline test. > (basic_string::max_size()): Account correctly the terminating 0 > and limits implied by ptrdiff_t. > > gcc/testsuite/ChangeLog: > > * g++.dg/tree-ssa/empty-loop.C: xfail optimization at cddce2 and check > it happens at cddce3. > * g++.dg/tree-ssa/string-1.C: New test. > > diff --git a/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C > b/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C > index ed4a603bf5b..b7e7e27cc04 100644 > --- a/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C > +++ b/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C > @@ -30,5 +30,8 @@ int foo (vector<string> &v, list<string> &l, set<string> > &s, map<int, string> &m > > return 0; > } > -/* { dg-final { scan-tree-dump-not "if" "cddce2"} } */ > +/* Adding __builtin_unreachable to std::string::size() prevents cddce2 from > + eliminating the loop early, see PR117764. */ > +/* { dg-final { scan-tree-dump-not "if" "cddce2" { xfail *-*-* } } } */ > +/* { dg-final { scan-tree-dump-not "if" "cddce3"} } */ > > diff --git a/gcc/testsuite/g++.dg/tree-ssa/string-1.C > b/gcc/testsuite/g++.dg/tree-ssa/string-1.C > new file mode 100644 > index 00000000000..d38c23a7628 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/tree-ssa/string-1.C > @@ -0,0 +1,9 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O3 -std=c++20 -fdump-tree-optimized" } */ > +#include <string> > +std::string > +test (std::string &a) > +{ > + return a; > +} > +/* { dg-final { scan-tree-dump-not "throw" "optimized" } } */ > diff --git a/libstdc++-v3/include/bits/basic_string.h > b/libstdc++-v3/include/bits/basic_string.h > index f5b320099b1..17b973c8b45 100644 > --- a/libstdc++-v3/include/bits/basic_string.h > +++ b/libstdc++-v3/include/bits/basic_string.h > @@ -1079,20 +1079,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR > size_type > size() const _GLIBCXX_NOEXCEPT > - { return _M_string_length; } > + { > + size_type __sz = _M_string_length; > + if (__sz > max_size ()) > + __builtin_unreachable (); > + return __sz; > + } > > /// Returns the number of characters in the string, not including any > /// null-termination. > _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR > size_type > length() const _GLIBCXX_NOEXCEPT > - { return _M_string_length; } > + { return size(); } > > /// Returns the size() of the largest possible %string. > _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR > size_type > max_size() const _GLIBCXX_NOEXCEPT > - { return (_Alloc_traits::max_size(_M_get_allocator()) - 1) / 2; } > + { > + const size_t __diffmax > + = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_CharT); > + const size_t __allocmax = _Alloc_traits::max_size(_M_get_allocator()); > + return (std::min)(__diffmax, __allocmax) - 1; > + } > > /** > * @brief Resizes the %string to the specified number of characters. > @@ -1184,8 +1194,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > size_type > capacity() const _GLIBCXX_NOEXCEPT > { > - return _M_is_local() ? size_type(_S_local_capacity) > - : _M_allocated_capacity; > + size_t __sz = _M_is_local() ? size_type(_S_local_capacity) > + : _M_allocated_capacity; > + if (__sz < _S_local_capacity || __sz > max_size ()) > + __builtin_unreachable (); > + return __sz; > } > > /** > @@ -1234,7 +1247,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR > bool > empty() const _GLIBCXX_NOEXCEPT > - { return this->size() == 0; } > + { return _M_string_length == 0; } > > // Element access: > /** >