https://gcc.gnu.org/g:1046c32de4956c3d706a2ff8683582fd21b8f360

commit r15-5735-g1046c32de4956c3d706a2ff8683582fd21b8f360
Author: Jan Hubicka <hubi...@ucw.cz>
Date:   Wed Nov 27 23:52:37 2024 +0100

    optimize basic_string
    
    Add __builtin_unreachable conditionls to declare value ranges of
    basic_string::length().  FIx max_size() to return actual max size
    using logic similar to std::vector. Aviod use of size() in empty()
    to save some compile time overhead.
    
    As disucced, max_size() change is technically ABI breaking, but
    hopefully this does not really matter in practice.
    
    Change of length() breaks empty-loop testcase where we now optimize the
    loop only after inlining, so template is updated to check cddce3 instead
    of cddce2. This is PR117764.
    
    With these chages we now optimize out unused strings as tested in
    string-1.C
    
    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()): Implement directly
            (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:
---
 gcc/testsuite/g++.dg/tree-ssa/empty-loop.C |  5 ++++-
 gcc/testsuite/g++.dg/tree-ssa/string-1.C   |  9 +++++++++
 libstdc++-v3/include/bits/basic_string.h   | 25 +++++++++++++++++++------
 3 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C 
b/gcc/testsuite/g++.dg/tree-ssa/empty-loop.C
index ed4a603bf5b3..b7e7e27cc042 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 000000000000..d38c23a7628b
--- /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 f5b320099b17..17b973c8b45c 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