https://gcc.gnu.org/g:79e29562907b454cdb867195b34cf63156d2d0cc

commit r17-570-g79e29562907b454cdb867195b34cf63156d2d0cc
Author: Avi Kivity <[email protected]>
Date:   Thu Feb 26 19:59:41 2026 +0200

    libstdc++: optimize std::uninitialized_move{,_n}() to memcpy when possible 
[PR121789]
    
    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).

Diff:
---
 libstdc++-v3/include/bits/stl_uninitialized.h        |  4 ++--
 .../uninitialized_move/121789.cc                     | 20 ++++++++++++++++++++
 libstdc++-v3/testsuite/util/testsuite_greedy_ops.h   |  3 ++-
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h 
b/libstdc++-v3/include/bits/stl_uninitialized.h
index ae4442f38581..a8791a66ae8f 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -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
index 000000000000..8fc19f40ade8
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc
@@ -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);
+}
diff --git a/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h 
b/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
index 053e36956b2f..88d502663d84 100644
--- a/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
+++ b/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
@@ -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(); }

Reply via email to