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(); }
