如何防止 gcc 优化破坏 rep movsb 代码?

Amm*_*izi 5 c optimization gcc x86-64 inline-assembly

我试图用rep movsb指令创建我的 memcpy 代码。当优化被禁用时,它适用于任何尺寸。但是,当我启用优化时,它没有按预期工作。

问题

  1. 如何防止 gcc 优化破坏 rep movsb 代码?
  2. 我的代码有问题所以导致未定义的行为吗?

创建我自己的 memcpy 的动机:

我从Intel® 64 and IA-32 Architectures Optimization Reference Manual section 3.7.6 中阅读了有关 memcpy 的增强 movsb 。我来到了 libc 源代码,我看到 libc 的默认 memcpy 使用 SSE 而不是movsb.

因此,我想比较memcpy 的SSE 指令rep movsb之间的性能。但是现在,我发现它有些不对劲。

重现问题的简单代码(test.c)

#include <stdio.h>
#include <string.h>

inline static void *my_memcpy(
  register void *dest,
  register const void *src,
  register size_t n
) {
  __asm__ volatile(
    "mov %0, %%rdi;"
    "mov %1, %%rsi;"
    "mov %2, %%rcx;"
    "rep movsb;"
    :
    : "r"(dest), "r"(src), "r"(n)
    : "rdi", "rsi", "rcx"
  );
  return dest;
}

#define to_boolean_str(A) ((A) ? "true" : "false")

int main()
{
  char src[32];
  char dst[32];

  memset(src, 'a', 32);
  memset(dst, 'b', 32);

  my_memcpy(dst, src, 1);
  printf("%s\n", to_boolean_str(!memcmp(dst, src, 1)));

  my_memcpy(dst, src, 2);
  printf("%s\n", to_boolean_str(!memcmp(dst, src, 2)));

  my_memcpy(dst, src, 3);
  printf("%s\n", to_boolean_str(!memcmp(dst, src, 3)));

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译并运行

ammarfaizi2@integral:~$ gcc --version
gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ammarfaizi2@integral:~$ gcc -O0 test.c -o test && ./test
true
true
true
ammarfaizi2@integral:~$ gcc -O1 test.c -o test && ./test
false
true
true
ammarfaizi2@integral:~$ gcc -O2 test.c -o test && ./test
false
true
true
ammarfaizi2@integral:~$ gcc -O3 test.c -o test && ./test
false
true
true
ammarfaizi2@integral:~$ 
Run Code Online (Sandbox Code Playgroud)

概括

my_memcpy(dst, src, 1); 如果启用优化,则会导致错误的行为。

R..*_*R.. 5

正如所写的那样,您的 asm 约束并不反映 asm 语句可以修改内存,因此编译器可以根据在dest或处读取或写入内存的操作自由地对其重新排序src。您需要添加"memory"到 clobber 列表中。

正如其他人所指出的,您还应该编辑约束以避免mov. 如果这样做,您还需要在约束中表示 asm 现在修改其参数的事实(例如,使它们全部为双输入/输出)并备份 的值,dest以便您可以返回它。所以你可以跳过这个改进,直到你让它开始工作,直到你了解约束是如何工作的。

  • [memcpy 的增强型 REP MOVSB](/sf/ask/3034026201/) 显示了一个仅包含 `rep movsb` 的工作内联 asm 语句。不过,它需要“易失性”,与 [Michael Petch 的版本](/sf/ask/4489892291/#comment113427225_64141318) https:/ /godbolt.org/z/54KfdT,它使用[如何指示可以使用内联 ASM 参数指向的内存?](https://stackoverflow.html) 中所示的转换为数组语法。 com/q/56432259) (2认同)