一段时间以来,我一直在为这个问题挠头。我正在使用 GCC 4.4.4(我已经检查了 GCC 3.4.6、4.4.6 和 4.6.3。)并且在我正在做的一些数学运算中遇到了问题。我将示例煮成以下自包含程序:
#include <stdio.h>
int main()
{
float something[4] = { 1.0f, 2.0f, 3.0f, 4.0f };
asm volatile
(
"movups %0, %%xmm0 \n\t"
"movups %%xmm0, %0 \n\t"
: "=m" (*something)
:
: "memory", "xmm0"
);
printf("%.0f %.0f %.0f %.0f\n",
something[0], something[1], something[2], something[3]);
return 0;
}
编译简单
gcc -msse -O -o something something.c
它以某种方式破坏了第一个数组元素而失败(我尝试过的 GCC 3.4.6 除外......在那里,它工作正常)。在我的一生中,我不能在这里看到任何根本性的错误。
相反,如果我将有问题的 ASM 块更改为
_mm_storeu_ps(something, _mm_loadu_ps(something));
它工作正常。我检查了生成的汇编代码,发现带有 ASM 块的版本在 SSE 部分之前少了一个存储操作:
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $64, %esp
movl $0x40000000, 52(%esp)
movl $0x40400000, 56(%esp)
movl $0x40800000, 60(%esp)
与更正确的(使用内在函数的代码):
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $64, %esp
movl $0x3f800000, 48(%esp)
movl $0x40000000, 52(%esp)
movl $0x40400000, 56(%esp)
movl $0x40800000, 60(%esp)
WTF 是我还是 GCC 错了?
(注意,这是一个简化的、简洁的示例,显示了我追踪到的根本问题。ASM 块和 volatile 关键字是有原因的,所有这些似乎都没有真正解决我提出的主要问题转发到这里。)
最佳答案
您使用了错误的约束(顺便说一句,这是第二个 such problem asked here today )。=
表示输出,所以 gcc 认为你要分配 *something
这是第一个数组元素。所以它认为它可以省略初始化,因为无论如何你都会覆盖它。您应该使用 +
将操作数标记为输入输出的符号,如下所示:"+m" (*something)
."=m" (something)
通常意味着您将分配给指针,因此 gcc 可以决定省略所有初始化。请注意,对于数组,这甚至不应该编译,就像等效的 C 代码一样。它编译甚至工作只是一个幸运的意外(又名编译器错误)。
关于GCC ASM 优化问题还是隐形幽灵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14285353/