如何防止 gcc 优化破坏 rep movsb 代码?
How to prevent gcc optimization breaking rep movsb code?
我尝试使用 rep movsb
指令创建我的 memcpy 代码。当禁用优化时,它可以完美地处理任何尺寸。但是,当我启用优化时,它并没有按预期工作。
问题
- 如何防止 gcc 优化破坏 rep movsb 代码?
- 我的代码是否有问题导致未定义的行为?
创建我自己的 memcpy 的动机:
我从 Intel® 64 and IA-32 Architectures Optimization Reference Manual 3.7.6 节 中读到关于 memcpy 的增强 movsb。我来到 libc 源代码,我看到 libc 的默认 memcpy 使用 SSE 而不是 movsb
.
因此,我想比较 SSE 指令 和 rep movsb 对 memcpy 的性能。但是现在,我发现它有问题。
重现问题的简单代码 (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;
}
编译并运行
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:~$
总结
如果启用优化,my_memcpy(dst, src, 1);
会导致错误行为。
正如所写,您的 asm 约束并未反映出 asm 语句可以修改内存,因此编译器可以根据在 dest
或 [=11= 处读取或写入内存的操作自由地重新排序它].您需要将 "memory"
添加到 clobber 列表中。
正如其他人指出的那样,您还应该编辑约束以避免 mov
。如果你这样做,你还需要在约束中表示 asm 现在修改它的参数(例如,使它们都是双重的 input/output)并备份 dest
的值,这样你就可以 return它。因此,您可以跳过此改进,直到您开始使用它并了解约束的工作原理。
我尝试使用 rep movsb
指令创建我的 memcpy 代码。当禁用优化时,它可以完美地处理任何尺寸。但是,当我启用优化时,它并没有按预期工作。
问题
- 如何防止 gcc 优化破坏 rep movsb 代码?
- 我的代码是否有问题导致未定义的行为?
创建我自己的 memcpy 的动机:
我从 Intel® 64 and IA-32 Architectures Optimization Reference Manual 3.7.6 节 中读到关于 memcpy 的增强 movsb。我来到 libc 源代码,我看到 libc 的默认 memcpy 使用 SSE 而不是 movsb
.
因此,我想比较 SSE 指令 和 rep movsb 对 memcpy 的性能。但是现在,我发现它有问题。
重现问题的简单代码 (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;
}
编译并运行
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:~$
总结
如果启用优化,my_memcpy(dst, src, 1);
会导致错误行为。
正如所写,您的 asm 约束并未反映出 asm 语句可以修改内存,因此编译器可以根据在 dest
或 [=11= 处读取或写入内存的操作自由地重新排序它].您需要将 "memory"
添加到 clobber 列表中。
正如其他人指出的那样,您还应该编辑约束以避免 mov
。如果你这样做,你还需要在约束中表示 asm 现在修改它的参数(例如,使它们都是双重的 input/output)并备份 dest
的值,这样你就可以 return它。因此,您可以跳过此改进,直到您开始使用它并了解约束的工作原理。