Перемещение переменной-члена в локальную переменную уменьшает количество записей в этом цикле, несмотря на наличие ключевого слова __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 (при условии, что размер не является небольшим числом), хотя я еще не измерил это.
Я прав, чтобы сделать это предположение?
Я думаю, что наблюдаемое поведение должно быть одинаковым в обоих случаях.