【发布时间】:2014-04-21 09:00:51
【问题描述】:
所以我偶然发现了一些我想了解的东西,因为它让我很头疼。我有以下代码:
#include <stdio.h>
#include <smmintrin.h>
typedef union {
struct { float x, y, z, w; } v;
__m128 m;
} vec;
vec __attribute__((noinline)) square(vec a)
{
vec x = { .m = _mm_mul_ps(a.m, a.m) };
return x;
}
int main(int argc, char *argv[])
{
float f = 4.9;
vec a = (vec){f, f, f, f};
vec res = square(a); // ?
printf("%f %f %f %f\n", res.v.x, res.v.y, res.v.z, res.v.w);
return 0;
}
现在,在我看来,在main 中对square 的调用应该将a 的值放入xmm0 中,以便square 函数可以执行mulps xmm0, xmm0 并完成它。
这不是我使用 clang 或 gcc 编译时发生的情况。相反,a 的前 8 个字节放在 xmm0 中,接下来的 8 个字节放在 xmm1 中,这使得 square 函数更加复杂,因为它需要修补一些东西。
知道为什么吗?
注意:这是使用 -O3 优化。
经过进一步研究,似乎与联合类型有关。如果函数采用直接 __m128,则生成的代码将期望单个寄存器 (xmm0) 中的值。但是考虑到它们都应该适合 xmm0,我不明白为什么在使用 vec 类型时它被分成两个半使用的寄存器..
【问题讨论】:
-
你玩过其他命令行选项吗?总是值得尝试打开/关闭一些东西,看看它如何影响生成的代码。
-
我会试试的,有什么建议吗?有这么多开关..
-
我不熟悉
clang,但是在GCC 上有一堆x86特定的options,很多都与SSE 有关。另外,优化和调试标志呢? -
老实说,我很惊讶它没有使用四个寄存器,因为它会通过四个浮点数。由于您使用的是 gcc,我建议您使用 vector extensions 而不是具有四个浮点数的结构。
-
对我来说,它看起来根本不像是在 xmm0 中传递参数。如果您使用直接的 __m128 或什至包含单个 __m128 的结构,那么它将按照 ABI 在 xmm0 中传递它。但我认为 ABI 坚持要求联合在堆栈上传递(尽管我很可能错了)。