首页 > 解决方案 > 如何阻止 GCC 将此逐字节复制优化为 memcpy 调用?

问题描述

我将这段代码memcpy作为标准 C 库实现的一部分,它一次将内存从一个字节复制srcdest一个字节:

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    $1, %rcx
        cmpq    %rdx, %rcx
        jne     .L3
.L2:
        ret
.LFE0:

但是,在 处gcc -O3,GCC 将这种简单的逐字节复制优化为memcpy调用:

memcpy:
.LFB0:
        testq   %rdx, %rdx
        je      .L7
        subq    $8, %rsp
        call    memcpy
        addq    $8, %rsp
        ret
.L7:
        movq    %rdi, %rax
        ret
.LFE0:

这不起作用(memcpy无条件调用自身),并且会导致段错误。

我试过通过-fno-builtin-memcpyand -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调用的优化?

标签: cgcccompiler-optimization

解决方案


一件事在这里似乎就足够了:而不是使用-fno-builtin-memcpyuse-fno-builtin来编译memcpy单独的翻译单元!

另一种方法是通过-fno-tree-loop-distribute-patterns;尽管这可能很脆弱,因为它禁止编译器首先重新组织循环代码,然后mem*函数调用替换其中的一部分。

或者,由于您不能依赖 C 库中的任何内容,因此-ffreestanding可能需要按顺序使用。


推荐阅读