diff mbox

optimize std::list move constructor

Message ID 20140807110008.GM6927@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Aug. 7, 2014, 11:01 a.m. UTC
While preparing the initial commit for the std::list ABI transition I
noticed the move constructor does unnecessary work, initializing the
object to an empty state, then calling _List_node_base::swap which
checks whether it's empty (but we already know it is) and then
initializes it again. The _List_node_base::swap function is a call
into libstdc++.so so can't be inlined or otherwise optimized.

This patch changes the move constructor to avoid unnecessary checking
and redundant initializations. The code size increases for -Os, but on
my laptop the following silly test goes from 8s to 4.5s with -O3, and
from 10.5s to 8.5s with -Os, so I think it's worthwhile:

  #include <list>

  int main()
  {
    std::list<int> l1;
    for (long i = 0; i < 1000000000; ++i)
    {
      std::list<int> l2 = std::move(l1);
      l1 = std::move(l2);
    }
  }

I intend to commit this to trunk later today.
diff mbox

Patch

commit f71c29dc7e025e8065f759cfc89bdeab5f3964f9
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Aug 7 10:59:47 2014 +0100

    	* include/bits/stl_list.h (_List_base::_List_base(_List_base&&)):
    	Optimize.
    	* testsuite/23_containers/list/requirements/dr438/assign_neg.cc:
    	Adjust dg-error line number.
    	* testsuite/23_containers/list/requirements/dr438/constructor_1_neg.cc:
    	Likewise.
    	* testsuite/23_containers/list/requirements/dr438/constructor_2_neg.cc:
    	Likewise.
    	* testsuite/23_containers/list/requirements/dr438/insert_neg.cc:
    	Likewise.

diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h
index e014fbc..dd9bba7 100644
--- a/libstdc++-v3/include/bits/stl_list.h
+++ b/libstdc++-v3/include/bits/stl_list.h
@@ -377,8 +377,17 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       _List_base(_List_base&& __x) noexcept
       : _M_impl(std::move(__x._M_get_Node_allocator()))
       {
-	_M_init();
-	__detail::_List_node_base::swap(_M_impl._M_node, __x._M_impl._M_node);
+	auto* const __xnode = std::__addressof(__x._M_impl._M_node);
+	if (__xnode->_M_next == __xnode)
+	  _M_init();
+	else
+	  {
+	    auto* const __node = std::__addressof(_M_impl._M_node);
+	    __node->_M_next = __xnode->_M_next;
+	    __node->_M_prev = __xnode->_M_prev;
+	    __node->_M_next->_M_prev = __node->_M_prev->_M_next = __node;
+	    __xnode->_M_next = __xnode->_M_prev = __xnode;
+	  }
       }
 #endif
 
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/assign_neg.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/assign_neg.cc
index 7c29a2d..885e753 100644
--- a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/assign_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/assign_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1656 }
+// { dg-error "no matching" "" { target *-*-* } 1665 }
 
 #include <list>
 
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_1_neg.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_1_neg.cc
index 382d985..ccd9d17 100644
--- a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_1_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_1_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1608 }
+// { dg-error "no matching" "" { target *-*-* } 1617 }
 
 #include <list>
 
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_2_neg.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_2_neg.cc
index 14585af..04966dc 100644
--- a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_2_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/constructor_2_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1608 }
+// { dg-error "no matching" "" { target *-*-* } 1617 }
 
 #include <list>
 #include <utility>
diff --git a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/insert_neg.cc b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/insert_neg.cc
index a9f9f30..759dad6 100644
--- a/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/insert_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/requirements/dr438/insert_neg.cc
@@ -18,7 +18,7 @@ 
 // <http://www.gnu.org/licenses/>.
 
 // { dg-do compile }
-// { dg-error "no matching" "" { target *-*-* } 1608 }
+// { dg-error "no matching" "" { target *-*-* } 1617 }
 
 #include <list>