[libcxx-commits] [PATCH] D68617: This change optimizes the copy constructor using partial inlining.- add __default_value_tag() to memory, to support default initialization- inline copy contructor: non SSO init delegated to instantiated __init_long() methodNote that this...

Martijn Vels via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 7 17:58:35 PDT 2019


mvels created this revision.
Herald added subscribers: libcxx-commits, christof.
Herald added a project: libc++.

...change does not consider existing value initialization ctors, most would likely benefit from default intialization.

Generated code given:

void StringCopyCtor(void* mem, const std::string& s) {

  std::string*p = new(mem) std::string{s};

}

asm:

  cmp     byte ptr [rsi + 23], 0
  js      .LBB0_2
  mov     rax, qword ptr [rsi + 16]
  mov     qword ptr [rdi + 16], rax
  movups  xmm0, xmmword ptr [rsi]
  movups  xmmword ptr [rdi], xmm0
  ret

.LBB0_2:

  jmp     std::basic_string::__init_long # TAILCALL

Benchmarks::
BM_StringCopy_Empty                                           5.18ns ± 7%             1.53ns ± 5%  -70.45%        (p=0.000 n=10+10)
BM_StringCopy_Small                                           5.18ns ± 7%             1.54ns ± 5%  -70.21%        (p=0.000 n=10+10)
BM_StringCopy_Large                                           19.0ns ± 1%             19.3ns ± 1%   +1.77%        (p=0.000 n=10+10)
BM_StringCopy_Huge                                             321ns ± 4%              310ns ± 1%     ~            (p=0.408 n=10+8)

Optimize copy constructor


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68617

Files:
  libcxx/include/memory
  libcxx/include/string


Index: libcxx/include/string
===================================================================
--- libcxx/include/string
+++ libcxx/include/string
@@ -1543,6 +1543,8 @@
     inline
     void __init(size_type __n, value_type __c);
 
+    void __init_long(const basic_string& __str);
+
     template <class _InputIterator>
     inline
     typename enable_if
@@ -1793,6 +1795,20 @@
     traits_type::assign(__p[__sz], value_type());
 }
 
+template <class _CharT, class _Traits, class _Allocator>
+void basic_string<_CharT, _Traits, _Allocator>::__init_long(
+    const basic_string& __str) {
+  const value_type* __s = _VSTD::__to_raw_pointer(__str.__get_long_pointer());
+  size_type __sz = __str.__get_long_size();
+  size_type __cap = __recommend(__sz);
+  pointer __p = __alloc_traits::allocate(__alloc(), __cap + 1);
+  __set_long_pointer(__p);
+  __set_long_cap(__cap + 1);
+  __set_long_size(__sz);
+  traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz);
+  traits_type::assign(__p[__sz], value_type());
+}
+
 template <class _CharT, class _Traits, class _Allocator>
 template <class>
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const _CharT* __s, const _Allocator& __a)
@@ -1830,12 +1846,12 @@
 
 template <class _CharT, class _Traits, class _Allocator>
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const basic_string& __str)
-    : __r_(__second_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc()))
+    : __r_(__default_value_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc()))
 {
     if (!__str.__is_long())
         __r_.first().__r = __str.__r_.first().__r;
     else
-        __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
+        __init_long(__str);
 #if _LIBCPP_DEBUG_LEVEL >= 2
     __get_db()->__insert_c(this);
 #endif
@@ -1844,12 +1860,12 @@
 template <class _CharT, class _Traits, class _Allocator>
 basic_string<_CharT, _Traits, _Allocator>::basic_string(
     const basic_string& __str, const allocator_type& __a)
-    : __r_(__second_tag(), __a)
+    : __r_(__default_value_tag(), __a)
 {
     if (!__str.__is_long())
         __r_.first().__r = __str.__r_.first().__r;
     else
-        __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
+        __init_long(__str);
 #if _LIBCPP_DEBUG_LEVEL >= 2
     __get_db()->__insert_c(this);
 #endif
Index: libcxx/include/memory
===================================================================
--- libcxx/include/memory
+++ libcxx/include/memory
@@ -2167,6 +2167,9 @@
 };
 #endif
 
+// Tag used to default initialize one or both of the pair's elements.
+struct __default_value_tag {};
+
 template <class _Tp, int _Idx,
           bool _CanBeEmptyBase =
               is_empty<_Tp>::value && !__libcpp_is_final<_Tp>::value>
@@ -2177,6 +2180,7 @@
 
 #ifndef _LIBCPP_CXX03_LANG
   _LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_() {}
+  _LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem(__default_value_tag) {}
 
   template <class _Up, class = typename enable_if<
       !is_same<__compressed_pair_elem, typename decay<_Up>::type>::value


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D68617.223710.patch
Type: text/x-patch
Size: 3200 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20191008/292582a6/attachment.bin>


More information about the libcxx-commits mailing list