]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: optimize std::uninitialized_move{,_n}() to memcpy when possible [PR121789]
authorAvi Kivity <avi@scylladb.com>
Thu, 26 Feb 2026 17:59:41 +0000 (19:59 +0200)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 18 May 2026 15:42:16 +0000 (16:42 +0100)
std::uninitialized_move{,_n} delegates to the corresponding
std::uninitialized_copy() variant after wrapping with a move
iterator, but the std::uninitialized_copy() doesn't unwrap the
move iterator, therefore losing the memcpy optimization if the
iterators were just pointers.

Fix this by unwrapping the move iterator using  __miter_base().

We remove operator-() in testsuite_greedy_ops.h; otherwise it breaks
the range size computation.

libstdc++v3/Changelog:

PR libstdc++/121789
* include/bits/stl_uninitialized.h (uninitialized_copy):
Unwrap move iterators
* testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc:
New test.
* testsuite/util/testsuite_greedy_ops.h (greedy_ops): Comment
out operator-(T, T).

libstdc++-v3/include/bits/stl_uninitialized.h
libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc [new file with mode: 0644]
libstdc++-v3/testsuite/util/testsuite_greedy_ops.h

index ae4442f38581c970d53984cb5c12eeaa5f6cf874..a8791a66ae8fe1c4263d829467413e7c8355cade 100644 (file)
@@ -275,7 +275,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201103L
       using _Dest = decltype(std::__niter_base(__result));
-      using _Src = decltype(std::__niter_base(__first));
+      using _Src = decltype(std::__miter_base(std::__niter_base(__first)));
       using _ValT = typename iterator_traits<_ForwardIterator>::value_type;
 
 #if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26
@@ -292,7 +292,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            {
              using _ValT = typename remove_pointer<_Src>::type;
              __builtin_memcpy(std::__niter_base(__result),
-                              std::__niter_base(__first),
+                              std::__miter_base(std::__niter_base(__first)),
                               __n * sizeof(_ValT));
              __result += __n;
            }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc
new file mode 100644 (file)
index 0000000..8fc19f4
--- /dev/null
@@ -0,0 +1,20 @@
+// { dg-options "-O1 -fdump-tree-optimized" }
+// { dg-do compile { target c++17 } }
+// { dg-final { scan-tree-dump "memcpy" "optimized" } }
+
+// PR libstdc++/121789
+// std::uninitialized_move_n() and friends don't optimize to memcpy
+
+#include <memory>
+
+struct T { int x; };
+
+void f(T* src, T* dst, unsigned n)
+{
+  std::uninitialized_move(src, src + n, dst);
+}
+
+void g(T* src, T* dst, unsigned n)
+{
+  std::uninitialized_move_n(src, n, dst);
+}
index 053e36956b2f3e16613c35e3d960091d252c85fb..88d502663d84bb0e38074921c4a9b4e261f0c891 100644 (file)
@@ -46,10 +46,11 @@ namespace greedy_ops
   X operator>=(T, T)
   { return X(); }
 
+  /*
   template<typename T>
   X operator-(T, T)
   { return X(); }
-  /*
+
   template<typename T>
   T operator+(std::size_t, T)
   { return T(); }