如何阻止 GCC 将此逐字节复制优化为 memcpy 调用?
How do I stop GCC from optimizing this byte-for-byte copy into a memcpy call?
我有 memcpy
的代码作为我实现标准 C 库的一部分,它将内存从 src
复制到 dest
一次一个字节:
void *memcpy(void *restrict dest, const void *restrict src, size_t len)
{
char *dp = (char *restrict)dest;
const char *sp = (const char *restrict)src;
while( len-- )
{
*dp++ = *sp++;
}
return dest;
}
加上gcc -O2
,生成的代码是合理的:
memcpy:
.LFB0:
movq %rdi, %rax
testq %rdx, %rdx
je .L2
xorl %ecx, %ecx
.L3:
movzbl (%rsi,%rcx), %r8d
movb %r8b, (%rax,%rcx)
addq , %rcx
cmpq %rdx, %rcx
jne .L3
.L2:
ret
.LFE0:
但是,在 gcc -O3
,GCC 将这个简单的逐字节复制优化为 memcpy
调用:
memcpy:
.LFB0:
testq %rdx, %rdx
je .L7
subq , %rsp
call memcpy
addq , %rsp
ret
.L7:
movq %rdi, %rax
ret
.LFE0:
这行不通(memcpy
无条件地调用自身),它会导致段错误。
我试过通过 -fno-builtin-memcpy
和 -fno-loop-optimizations
,但同样的事情发生了。
我正在使用 GCC 8.3.0 版:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-cros-linux-gnu/8.3.0/lto-wrapper
Target: x86_64-cros-linux-gnu
Configured with: ../configure --prefix=/usr/local --libdir=/usr/local/lib64 --build=x86_64-cros-linux-gnu --host=x86_64-cros-linux-gnu --target=x86_64-cros-linux-gnu --enable-checking=release --disable-multilib --enable-threads=posix --disable-bootstrap --disable-werror --disable-libmpx --enable-static --enable-shared --program-suffix=-8.3.0 --with-arch-64=x86-64
Thread model: posix
gcc version 8.3.0 (GCC)
如何禁用导致副本转换为 memcpy
调用的优化?
This won't work (memcpy unconditionally calls itself), and it causes a segfault.
.
How do I disable the optimization that causes the copy to be transformed into a memcpy call (preferably while still compiling with -O3)?
不要。最好的方法是修复您的代码:
在大多数情况下,您应该使用其他名称。
在极少数情况下,您确实在实现 C 库(如评论中所讨论),并且您确实想重新实现 memcpy
,那么您应该使用特定于编译器的选项实现这一目标。对于 GCC,请参阅 -fno-builtin*
and -ffreestanding
, as well as -nodefaultlibs
and -nostdlib
.
这里有一件事似乎就足够了:而不是使用 -fno-builtin-memcpy
use -fno-builtin
单独编译 memcpy
的翻译单元!
另一种方法是通过 -fno-tree-loop-distribute-patterns
;尽管这可能很脆弱,因为它禁止编译器首先重组循环代码 ,然后 将其中的一部分替换为对 mem*
函数的调用。
或者,由于您不能依赖 C 库中的任何内容,也许可以使用 -ffreestanding
。
我有 memcpy
的代码作为我实现标准 C 库的一部分,它将内存从 src
复制到 dest
一次一个字节:
void *memcpy(void *restrict dest, const void *restrict src, size_t len)
{
char *dp = (char *restrict)dest;
const char *sp = (const char *restrict)src;
while( len-- )
{
*dp++ = *sp++;
}
return dest;
}
加上gcc -O2
,生成的代码是合理的:
memcpy:
.LFB0:
movq %rdi, %rax
testq %rdx, %rdx
je .L2
xorl %ecx, %ecx
.L3:
movzbl (%rsi,%rcx), %r8d
movb %r8b, (%rax,%rcx)
addq , %rcx
cmpq %rdx, %rcx
jne .L3
.L2:
ret
.LFE0:
但是,在 gcc -O3
,GCC 将这个简单的逐字节复制优化为 memcpy
调用:
memcpy:
.LFB0:
testq %rdx, %rdx
je .L7
subq , %rsp
call memcpy
addq , %rsp
ret
.L7:
movq %rdi, %rax
ret
.LFE0:
这行不通(memcpy
无条件地调用自身),它会导致段错误。
我试过通过 -fno-builtin-memcpy
和 -fno-loop-optimizations
,但同样的事情发生了。
我正在使用 GCC 8.3.0 版:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-cros-linux-gnu/8.3.0/lto-wrapper
Target: x86_64-cros-linux-gnu
Configured with: ../configure --prefix=/usr/local --libdir=/usr/local/lib64 --build=x86_64-cros-linux-gnu --host=x86_64-cros-linux-gnu --target=x86_64-cros-linux-gnu --enable-checking=release --disable-multilib --enable-threads=posix --disable-bootstrap --disable-werror --disable-libmpx --enable-static --enable-shared --program-suffix=-8.3.0 --with-arch-64=x86-64
Thread model: posix
gcc version 8.3.0 (GCC)
如何禁用导致副本转换为 memcpy
调用的优化?
This won't work (memcpy unconditionally calls itself), and it causes a segfault.
How do I disable the optimization that causes the copy to be transformed into a memcpy call (preferably while still compiling with -O3)?
不要。最好的方法是修复您的代码:
在大多数情况下,您应该使用其他名称。
在极少数情况下,您确实在实现 C 库(如评论中所讨论),并且您确实想重新实现
memcpy
,那么您应该使用特定于编译器的选项实现这一目标。对于 GCC,请参阅-fno-builtin*
and-ffreestanding
, as well as-nodefaultlibs
and-nostdlib
.
这里有一件事似乎就足够了:而不是使用 -fno-builtin-memcpy
use -fno-builtin
单独编译 memcpy
的翻译单元!
另一种方法是通过 -fno-tree-loop-distribute-patterns
;尽管这可能很脆弱,因为它禁止编译器首先重组循环代码 ,然后 将其中的一部分替换为对 mem*
函数的调用。
或者,由于您不能依赖 C 库中的任何内容,也许可以使用 -ffreestanding
。