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)