将成员变量移动到本地变量可以减少循环中的写入次数,尽管存在__restrict关键字。这是在使用GCC -O3编译器的情况下。Clang和MSVC优化了两种情况下的写入操作。 [请注意,自发布此问题以来,我们发现将__restrict添加到调用函数也会导致GCC将存储移出循环。请参见下面的godbolt链接和注释]
class X
{
public:
void process(float * __restrict d, int size)
{
for (int i = 0; i < size; ++i)
{
d[i] = v * c + d[i];
v = d[i];
}
}
void processFaster(float * __restrict d, int size)
{
float lv = v;
for (int i = 0; i < size; ++i)
{
d[i] = lv * c + d[i];
lv = d[i];
}
v = lv;
}
float c{0.0f};
float v{0.0f};
};
使用gcc -O3编译后,第一个循环的内部代码如下:
.L3:
mulss xmm0, xmm1
add rdi, 4
addss xmm0, DWORD PTR [rdi-4]
movss DWORD PTR [rdi-4], xmm0
cmp rax, rdi
movss DWORD PTR x[rip+4], xmm0 ;<<< the extra store
jne .L3
.L1:
rep ret
这里的第二个:
.L8:
mulss xmm0, xmm1
add rdi, 4
addss xmm0, DWORD PTR [rdi-4]
movss DWORD PTR [rdi-4], xmm0
cmp rdi, rax
jne .L8
.L7:
movss DWORD PTR x[rip+4], xmm0
ret
请参阅https://godbolt.org/g/a9nCP2以查看完整代码。
为什么编译器在这里不执行lv优化?
我假设每个循环内的3次内存访问比2次更糟糕(假设size不是一个小数字),尽管我还没有测量过。
我的假设正确吗?
我认为在两种情况下,可观察的行为应该是相同的。