[libcxx-commits] [PATCH] D77913: Make basic_string::operator=() tail call properly

Martijn Vels via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Apr 10 15:37:24 PDT 2020


mvels created this revision.
mvels added a reviewer: EricWF.
Herald added a project: libc++.
Herald added a subscriber: libcxx-commits.
Herald added a reviewer: libc++.

We discovered that the compiler may chose not to inline the operator=, which leads to an expensive extra stack frame. This change makes __assign_no_alias always tail called.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77913

Files:
  libcxx/include/__string
  libcxx/include/string


Index: libcxx/include/string
===================================================================
--- libcxx/include/string
+++ libcxx/include/string
@@ -1585,7 +1585,7 @@
     // have proof that the input does not alias the current instance.
     // For example, operator=(basic_string) performs a 'self' check.
     template <bool __is_short>
-    void __assign_no_alias(const value_type* __s, size_type __n);
+    basic_string& __assign_no_alias(const value_type* __s, size_type __n);
 
     _LIBCPP_INLINE_VISIBILITY
     void __erase_to_end(size_type __pos);
@@ -2253,7 +2253,8 @@
 
 template <class _CharT, class _Traits, class _Allocator>
 template <bool __is_short>
-void basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias(
+basic_string<_CharT, _Traits, _Allocator>&
+basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias(
     const value_type* __s, size_type __n) {
   size_type __cap = __is_short ? __min_cap : __get_long_cap();
   if (__n < __cap) {
@@ -2266,6 +2267,7 @@
     size_type __sz = __is_short ? __get_short_size() : __get_long_size();
     __grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s);
   }
+  return *this;
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -2340,10 +2342,10 @@
       if (!__str.__is_long()) {
         __r_.first().__r = __str.__r_.first().__r;
       } else {
-        __assign_no_alias<true>(__str.data(), __str.size());
+        return __assign_no_alias<true>(__str.data(), __str.size());
       }
     } else {
-      __assign_no_alias<false>(__str.data(), __str.size());
+      return __assign_no_alias<false>(__str.data(), __str.size());
     }
   }
   return *this;
Index: libcxx/include/__string
===================================================================
--- libcxx/include/__string
+++ libcxx/include/__string
@@ -164,8 +164,8 @@
   _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_last_of(value_type const*, size_type, size_type) const) \
   _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by(size_type, size_type, size_type, size_type, size_type, size_type)) \
   _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by_and_replace(size_type, size_type, size_type, size_type, size_type, size_type, value_type const*)) \
-  _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__assign_no_alias<false>(value_type const*, size_type)) \
-  _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__assign_no_alias<true>(value_type const*, size_type)) \
+  _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::__assign_no_alias<false>(value_type const*, size_type)) \
+  _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::__assign_no_alias<true>(value_type const*, size_type)) \
   _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::push_back(value_type)) \
   _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(size_type, value_type)) \
   _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::rfind(value_type, size_type) const) \


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D77913.256687.patch
Type: text/x-patch
Size: 3112 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20200410/d9411acd/attachment.bin>


More information about the libcxx-commits mailing list