使用godbolt.org x86-64 gcc 11.2这个代码..。
typedef int v4i __attribute__ ((vector_size (16)));
typedef union {
v4i v;
} int4;
int4 mul(int4 l, int4 r)
{
return (int4){.v=l.v * r.v};
}...produces此程序集(当使用-O3 -mavx编译时).
mul:
vpmulld xmm0, xmm0, xmm1
ret但是这个密码..。
typedef int v4i __attribute__ ((vector_size (16)));
typedef union {
v4i v;
struct {int x,y,z,w;}; // this line is the change
int i[4]; // this one too
} int4;
int4 mul(int4 l, int4 r)
{
return (int4){.v=l.v * r.v};
}...produces此程序集(当也使用-O3 -mavx编译时).
mul:
mov QWORD PTR [rsp-40], rdi
mov QWORD PTR [rsp-32], rsi
vmovdqa xmm1, XMMWORD PTR [rsp-40]
mov QWORD PTR [rsp-24], rdx
mov QWORD PTR [rsp-16], rcx
vpmulld xmm0, xmm1, XMMWORD PTR [rsp-24]
vmovdqa XMMWORD PTR [rsp-40], xmm0
mov rax, QWORD PTR [rsp-40]
mov rdx, QWORD PTR [rsp-32]
retx86-64 clang 13.0.1也有类似的结果
所以我的问题是,我如何说服gcc (和/或clang)这两个代码块应该产生相同的输出?
我尝试过__attribute__ ((aligned)),移除int i[4];或struct,将__attribute__ ((packed))应用于struct,甚至给__attribute__ ((transparent_union))一次尝试。无论__attribute__ ((vector_size (16)))赋予什么神奇状态,都可以通过向union添加任何内容来打破它。
发布于 2022-03-17 06:01:03
我应该说,我从来没有亲自处理过这个属性,我刚才检查了gcc,但是从文件中我看到了一些我认为对你的问题有用的东西。
从您的代码中,我可以假设您希望使用union分别访问向量的每个int。但是,如果这是唯一的原因,就没有必要使用int[4]或struct {int x,y,z,w;};作为联合的一部分,因为向量可以像数组一样使用:
typedef int v4i __attribute__ ((vector_size (16)));
typedef union {
v4i v;
} int4;
int4 mul(int4 l, int4 r)
{
int4 ret = (int4){.v=l.v * r.v};
printf("%i %i %i %i", ret.v[0], ret.v[1], ret.v[2], ret.v[3]);
return ret;
}代码将根据您的喜好进行优化。此外,如果您需要字节级访问,union与另一个向量一起工作也可以:
typedef int v4i __attribute__ ((vector_size (16)));
typedef unsigned char v4b __attribute__ ((vector_size (16)));
struct i4s{int x,y,z,w;};
typedef union {
v4i v;
v4b v2;
} int4;
int4 mul(int4 l, int4 r)
{
return (int4){.v=l.v * r.v};
}在这种情况下,union似乎将使用类似于原语的类型。例如,甚至连__m128i也能工作。
发布于 2022-03-17 08:00:30
结果,他们是一样的。出于某种原因,第二种方法包括填充xmm?从堆栈中注册,但是如果添加一个主函数.
int main(int argc, char *argv[])
{
// volatile keyword added so they don't get optimised out
volatile int4 x = {.v={1,2,3,4}};
volatile int4 y = {.v={1,2,3,4}};
int4 z = mul(x, y);
return z.v[0];
}...then函数(在本例中为单个vpmulld指令)被内联,并插入不同的、适当的堆栈操作。
https://stackoverflow.com/questions/71507434
复制相似问题