https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121789
Bug ID: 121789 Summary: std:uninitialized_move_n() and friends don't optimize to memcpy Product: gcc Version: 15.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: avi at scylladb dot com Target Milestone: --- Consider ``` #include <memory> struct a { int x; }; void f(const a* a1, a* a2, size_t n) { std::uninitialized_copy_n(a1, n, a2); } void g(const a* a1, a* a2, size_t n) { std::uninitialized_move_n(a1, n, a2); } ``` f() and g() are practically identical, since a is trivially-everything. Yet f() compiles to memcpy(), and g() does not: ``` f(a const*, a*, unsigned long): salq $2, %rdx movq %rdi, %rax movq %rsi, %rdi testq %rdx, %rdx jle .L1 movq %rax, %rsi jmp memcpy .L1: ret g(a const*, a*, unsigned long): salq $2, %rdx je .L4 xorl %eax, %eax .L6: movl (%rdi,%rax), %ecx movl %ecx, (%rsi,%rax) addq $4, %rax cmpq %rax, %rdx jne .L6 .L4: ret ``` Likely the memcpyable detection web gets confused by the move_iterator attached by std::uninitialized_move_n(). godbolt: https://godbolt.org/z/sYfEK3cz3 (btw: the testq/jle sequence in f() can be replaced with jne, since the flags aren't touched and having a negative memory size is undefined behavior; I'm also not sure we aren't better off delegating the check to memcpy itself)