MSVC:无效的memcpy优化?

15

考虑以下代码:

void MemMove8(void* dst, void* src)
{
    char tmp[8];
    memcpy(tmp, src, 8);
    memcpy(dst, tmp, 8);
}

使用 /O2 选项编译的 MSVC(16.7.1 版)x86 架构生成该函数的以下汇编代码:

; _dst$ = ecx
; _src$ = edx
    mov eax, DWORD PTR [edx]
    mov DWORD PTR [ecx], eax
    mov eax, DWORD PTR [edx+4]
    mov DWORD PTR [ecx+4], eax

但是如果输入和输出缓冲区重叠,这种方法在某些情况下是无效的。

生成的代码对我来说似乎有问题;或者说这是一种有效的转换,而我可能忽略了什么?


2
是的,但这就是为什么该函数首先将src中的内容复制到临时缓冲区tmp中。然后再从tmp复制到dst中。临时缓冲区不会与srcdst重叠。 - Alex
你是使用 #include <cstring>using std::memcpy; 还是使用全局命名空间中的 ::memcpy(来自 <string.h>)?我无法访问针对 x86 目标的 MSVC 16.7.1。 - Eljay
2
我认为切换到 std::memmove 可以解决这个问题?(我希望 godbolt 有 MSVC 16.7.1 x86。)在我的平台上,::memcpystd::memcpy 的定义是不同的(但那不是 MSVC 16.7.1)。 - Eljay
1
MSVC只是将::memcpy函数导入std命名空间。因此,memcpystd::memcpy实际上是相同的。MemMove8函数之所以存在,是因为MSVC不会“内联”memmove(dst, src, 8)(调用库函数而不是生成一些mov指令),但它会“内联”std::memcpy(dst, src, 8)。这只是一种性能优化。 - Alex
2
嗯,看起来像是个 bug。但事实上,你甚至需要这种解决方法,这意味着是时候找一个更好的编译器(例如 clang)了,因为它可以在第一时间内联 memmove,并且在内联 memcpy 时,如果有足够的寄存器,则首先进行加载,然后进行存储: https://godbolt.org/z/GGTcsq。 - Peter Cordes
显示剩余6条评论
1个回答

5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接