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:
>        /**
>

Reply via email to