我正在通过优化对下面的代码进行编译,并且看起来仍然存在使用底层硬件的SIMD功能执行这两个求和的更有效方法。对于GCC生成会成对加载操作数并在一条指令中执行两个加法的程序集的标志,正确的标志混合方式是什么?
#include <iostream>
struct foo {
float val[2];
foo(float a, float b)
{
val[0] = a;
val[1] = b;
}
foo& operator+=(
const foo &rhs)
{
val[0] += rhs.val[0];
val[1] += rhs.val[1];
return *this;
}
};
int main(void)
{
volatile float values[] = { 2.0, 3.0, 4.0, 7.0 };
foo first(values[0], values[1]);
foo second(values[2], values[3]);
second += first;
std::cout << "(" << second.val[0] << ","
<< second.val[1] << ")" << std::endl;
return 1;
}
生成的汇编代码看起来像这样(仅对于operator +()而言),似乎很明显所有操作数都被单独对待。
400712: c5 fa 10 4c 24 14 vmovss 0x14(%rsp),%xmm1
400718: c5 fa 10 5c 24 10 vmovss 0x10(%rsp),%xmm3
foo second(values[2], values[3]);
40071e: c5 fa 10 44 24 1c vmovss 0x1c(%rsp),%xmm0
400724: c5 fa 10 54 24 18 vmovss 0x18(%rsp),%xmm2
val[1] += rhs.val[1];
40072a: c5 f2 58 e8 vaddss %xmm0,%xmm1,%xmm5
val[0] += rhs.val[0];
40072e: c5 e2 58 e2 vaddss %xmm2,%xmm3,%xmm4
val[1] += rhs.val[1];
400732: c5 fa 11 6c 24 0c vmovss %xmm5,0xc(%rsp)
val[0] += rhs.val[0];
400738: c5 fa 11 64 24 08 vmovss %xmm4,0x8(%rsp)
我使用此命令进行编译(但是删除-mavx2不会对结果产生太大影响):
g++ -O3 -mavx2 -g -std=c++11 main.cpp -o run
万一重要,那就是GCC 6.3(并且实际上没有升级的自由)。