GCC ASM 优化问题还是隐形幽灵?

标签 gcc assembly x86 sse inline-assembly

一段时间以来,我一直在为这个问题挠头。我正在使用 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/

相关文章:

模板类中模板函数的显式特化的 C++ 语法?

assembly - 缓冲输入如何工作

multithreading - x86 中非读和非写指令重新排序有关系吗?

c++ - 如何用C++给定的地址覆盖汇编程序栈的返回地址?

c - 列出 C 常量/宏

python - #通过pip安装scikit-bio时报错 “SSE2 instruction set not enabled”

assembly - 如何为6502 CPU(C64)设置CMake交叉汇编工具链?

c - 如何从 gdb 读取 fread 值

c - 使用时间戳计数器测量内存延迟

c - GCC 的 __builtin_expect 在 if else 语句中的优势是什么?