我正在尝试优化一个小的“ 4浮点数的矢量”包装器类,当然,我也想使其变得方便。例如:
typedef float v4f __attribute__ ((vector_size (16)));
struct V4 {
union {
v4f packed;
#if 1
struct { float r,g,b,a; };
#endif
#if 1
float data[4];
#endif
};
V4() = default;
V4(v4f v) : packed(v) {}
};
V4 AddV4(V4 a,V4 b) {
return a.packed + b.packed;
}
V4 MulV4(V4 a,V4 b) {
return a.packed * b.packed;
}
static_assert(sizeof(V4) == 16);
我知道联盟在理论上是未定义的行为,但实际上,它工作正常;-)
问题如下:我使用gcc和clang并通过命令行参数在godbolt中对此进行了测试(请参阅https://godbolt.org/z/fXbtre)
-O3 -fomit-frame-pointer -fno-rtti -fno-exceptions -mavx -ffast-math
如果我从联合中同时禁用了结构和数组(即都将其设置为#if 0),则会得到一个非常紧凑的AddV4和MulV4函数,例如:
AddV4(V4,V4):
vaddps xmm0,xmm0,xmm1
ret
但是,如果我启用这两个中的任何一个,我都会得到:
AddV4(V4,V4):
vmovq QWORD PTR [rsp-32],xmm1
vmovq QWORD PTR [rsp-40],xmm0
vmovaps xmm5,XMMWORD PTR [rsp-40]
vmovq QWORD PTR [rsp-24],xmm2
vmovq QWORD PTR [rsp-16],xmm3
vaddps xmm4,xmm5,XMMWORD PTR [rsp-24]
vmovaps XMMWORD PTR [rsp-40],xmm4
mov rax,QWORD PTR [rsp-32]
vmovq xmm0,QWORD PTR [rsp-40]
vmovq xmm1,rax
mov QWORD PTR [rsp-24],rax
ret
有人可以解释为什么吗?我可以使用gcc / clang的编译器标志来解决此问题吗?还是仅使用打包数据结构的唯一选择? (在那种情况下,我需要编写访问器方法x(),y(),z(),w(),这在我们的代码库中将是一个很大的变化,因此,我会优先选择其他方法。)