[gcc r15-5735] optimize basic_string
Jan Hubicka
hubicka@gcc.gnu.org
Wed Nov 27 22:57:31 GMT 2024
https://gcc.gnu.org/g:1046c32de4956c3d706a2ff8683582fd21b8f360
commit r15-5735-g1046c32de4956c3d706a2ff8683582fd21b8f360
Author: Jan Hubicka <hubicka@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:
/**
More information about the Libstdc++-cvs
mailing list