4

一段时间以来,我一直在为这个问题挠头。我正在使用 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 关键字的原因似乎并没有真正解决我提出的主要问题在这里转发。)

4

1 回答 1

3

您使用了错误的约束(顺便说一下,这是今天在这里提出的第二个此类问题)。意思是=输出,所以 gcc 认为你要分配*something哪个是第一个数组元素。所以它认为它可以省略初始化,因为无论如何你都会覆盖它。您应该使用+符号将操作数标记为输入输出,如下所示:"+m" (*something).

"=m" (something)通常意味着您将分配给指针,因为这样 gcc 可以决定省略所有初始化。请注意,对于数组,这甚至不应该编译,就像等效的 C 代码一样。它编译甚至可以工作只是一个幸运的事故(又名编译器错误)。

于 2013-01-12T00:23:56.207 回答