https://gcc.gnu.org/g:9c5505a35d9d71705464f9254f55407192d31ec3

commit r15-9047-g9c5505a35d9d71705464f9254f55407192d31ec3
Author: Jan Hubicka <hubi...@ucw.cz>
Date:   Sun Mar 30 23:49:49 2025 +0200

    Optimize string constructor
    
    this patch improves code generation on string constructors.  We currently 
have
    _M_construct which takes as a parameter two iterators (begin/end pointers to
    other string) and produces new string.  This patch adds special case of
    constructor where instead of begining/end pointers we readily know the 
string
    size and also special case when we know that source is 0 terminated.  This
    happens commonly when producing stirng copies. Moreover currently ipa-prop 
is
    not able to propagate information that beg-end is known constant (copied 
string
    size) which makes it impossible for inliner to spot the common case where
    string size is known to be shorter than 15 bytes and fits in local buffer.
    
    Finally I made new constructor inline. Because it is explicitely 
instantiated
    without C++20 constexpr we do not produce implicit instantiation (as 
required
    by standard) which prevents inlining, ipa-modref and any other IPA analysis 
to
    happen.  I think we need to make many of the other functions inline, since
    optimization accross string manipulation is quite important. There is 
PR94960
    to track this issue.
    
    Bootstrapped/regtested x86_64-linux, OK?
    
    libstdc++-v3/ChangeLog:
    
            PR tree-optimization/103827
            PR tree-optimization/80331
            PR tree-optimization/87502
    
            * config/abi/pre/gnu.ver: Add version for _M_construct<bool>
            * include/bits/basic_string.h: (basic_string::_M_construct<bool>): 
Declare.
            (basic_string constructors): Use it.
            * include/bits/basic_string.tcc: 
(basic_string::_M_construct<bool>): New template.
            * src/c++11/string-inst.cc: Instantated S::_M_construct<bool>.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/tree-ssa/pr80331.C: New test.
            * g++.dg/tree-ssa/pr87502.C: New test.

Diff:
---
 gcc/testsuite/g++.dg/tree-ssa/pr80331.C    |  8 ++++++++
 gcc/testsuite/g++.dg/tree-ssa/pr87502.C    | 15 +++++++++++++++
 libstdc++-v3/config/abi/pre/gnu.ver        |  3 +++
 libstdc++-v3/include/bits/basic_string.h   | 10 ++++++++--
 libstdc++-v3/include/bits/basic_string.tcc | 25 +++++++++++++++++++++++++
 libstdc++-v3/src/c++11/string-inst.cc      |  8 ++++++++
 6 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr80331.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr80331.C
new file mode 100644
index 000000000000..85034504f2f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr80331.C
@@ -0,0 +1,8 @@
+// { dg-do compile }
+// { dg-additional-options "-O2 -fdump-tree-optimized" }
+#include<string>
+int sain() {
+  const std::string remove_me("remove_me");
+  return 0;
+}
+// { dg-final { scan-tree-dump-not "remove_me" "optimized" } }
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr87502.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr87502.C
new file mode 100644
index 000000000000..ad3e9d254044
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr87502.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-additional-options "-O2 -fdump-tree-optimized" }
+#include <string>
+
+
+__attribute__ ((pure))
+extern int foo (const std::string &);
+
+int
+bar ()
+{
+  return foo ("abc") + foo (std::string("abc"));
+}
+// We used to add terminating zero explicitely instead of using fact
+// that memcpy source is already 0 terminated.
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver 
b/libstdc++-v3/config/abi/pre/gnu.ver
index adadc62e3533..eb230290313c 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2540,6 +2540,9 @@ GLIBCXX_3.4.34 {
     
_ZNSt8__format25__locale_encoding_to_utf8ERKSt6localeSt17basic_string_viewIcSt11char_traitsIcEEPv;
     # __sso_string constructor and destructor
     _ZNSt12__sso_string[CD][12]Ev;
+    # void std::__cxx11::basic_string<char, std::char_traits<char>, 
std::allocator<char> >::_M_construct<bool>(char const*, unsigned long)
+    # and wide char version
+    
_ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE12_M_constructILb[01]EEEvPK[cw]m;
 } GLIBCXX_3.4.33;
 
 # Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index e3b484d7a53f..86841cb2c5ed 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -341,6 +341,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       void
       _M_construct(size_type __req, _CharT __c);
 
+      // Construct using block of memory of known size.
+      // If _Terminated is true assume that source is already 0 terminated.
+      template<bool _Terminated>
+       _GLIBCXX20_CONSTEXPR
+       void
+       _M_construct(const _CharT *__c, size_type __n);
+
       _GLIBCXX20_CONSTEXPR
       allocator_type&
       _M_get_allocator()
@@ -561,8 +568,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       : _M_dataplus(_M_local_data(),
                    _Alloc_traits::_S_select_on_copy(__str._M_get_allocator()))
       {
-       _M_construct(__str._M_data(), __str._M_data() + __str.length(),
-                    std::forward_iterator_tag());
+       _M_construct<true>(__str._M_data(), __str.length());
       }
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
diff --git a/libstdc++-v3/include/bits/basic_string.tcc 
b/libstdc++-v3/include/bits/basic_string.tcc
index 7c44753a1516..a5df7cb1f4bc 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -276,6 +276,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_set_length(__n);
     }
 
+  // Length of string constructed is easier to propagate inter-procedurally
+  // than difference between iterators.
+  template<typename _CharT, typename _Traits, typename _Alloc>
+     template<bool _Terminated>
+    _GLIBCXX20_CONSTEXPR 
+    void
+    basic_string<_CharT, _Traits, _Alloc>::
+    _M_construct(const _CharT *__str, size_type __n)
+    {
+      if (__n > size_type(_S_local_capacity))
+       {
+         _M_data(_M_create(__n, size_type(0)));
+         _M_capacity(__n);
+       }
+      else
+       _M_init_local_buf();
+
+      if (__n || _Terminated)
+       this->_S_copy(_M_data(), __str, __n + _Terminated);
+
+      _M_length(__n);
+      if (!_Terminated)
+       traits_type::assign(_M_data()[__n], _CharT());
+    }
+
   template<typename _CharT, typename _Traits, typename _Alloc>
     _GLIBCXX20_CONSTEXPR
     void
diff --git a/libstdc++-v3/src/c++11/string-inst.cc 
b/libstdc++-v3/src/c++11/string-inst.cc
index a1602389a6d0..c4864794d40b 100644
--- a/libstdc++-v3/src/c++11/string-inst.cc
+++ b/libstdc++-v3/src/c++11/string-inst.cc
@@ -91,6 +91,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     void
     S::_M_construct(const C*, const C*, forward_iterator_tag);
 
+  template
+    void
+    S::_M_construct<false>(const C*, size_t);
+
+  template
+    void
+    S::_M_construct<true>(const C*, size_t);
+
 #else // !_GLIBCXX_USE_CXX11_ABI
 
   template

Reply via email to