Если я напишу этот код:
void loop1(int N, double* R, double* A, double* B) {
for (int i = 0; i < N; i += 1) {
R[i] = A[i] + B[i];
}
}
Clang (-O3
) генерирует следующий x64 ASM как часть развернутой версии цикла ( Проводник компилятора ):
.LBB0_14:
movupd xmm0, xmmword ptr [rdx + 8*rax]
movupd xmm1, xmmword ptr [rdx + 8*rax + 16]
movupd xmm2, xmmword ptr [rcx + 8*rax]
addpd xmm2, xmm0
movupd xmm0, xmmword ptr [rcx + 8*rax + 16]
addpd xmm0, xmm1
movupd xmmword ptr [rsi + 8*rax], xmm2
movupd xmmword ptr [rsi + 8*rax + 16], xmm0
rdx
и rcx
содержат мои входные указатели (A
/ B
), rsi
- это вывод (R
), а rax
- это счетчик смещения,Таким образом, он загружает две пары входов / выходов одновременно, добавляя их с помощью SIMD-инструкций и записывая их в вывод - пока все хорошо.
Если вместо этого я напишу следующее:
void loop2(int N, double* R, double* A, double* B) {
for (int i = 0; i < N; i += 2) {
R[i] = A[i] + B[i];
R[i + 1] = A[i + 1] + B[i + 1];
}
}
LLVM генерирует следующее ( Проводник компилятора ):
.LBB0_13:
movupd xmm0, xmmword ptr [rdx + 8*rdi]
movupd xmm1, xmmword ptr [rdx + 8*rdi + 16]
movupd xmm2, xmmword ptr [rcx + 8*rdi]
addpd xmm2, xmm0
movupd xmm0, xmmword ptr [rcx + 8*rdi + 16]
addpd xmm0, xmm1
movapd xmm1, xmm2
unpckhpd xmm1, xmm0 # xmm1 = xmm1[1],xmm0[1]
unpcklpd xmm2, xmm0 # xmm2 = xmm2[0],xmm0[0]
movapd xmm0, xmm2
unpcklpd xmm0, xmm1 # xmm0 = xmm0[0],xmm1[0]
unpckhpd xmm2, xmm1 # xmm2 = xmm2[1],xmm1[1]
movupd xmmword ptr [rsi + 8*rdi + 16], xmm2
movupd xmmword ptr [rsi + 8*rdi], xmm0
Для ясности добавлен интервал, потому что именно эта средняя часть с unpckhpd
и т. Д. Меня смущает.Насколько я вижу, общий эффект этих 6 инструкций состоит в том, чтобы просто поменять местами xmm0
и xmm2
, что кажется пустой тратой времени.
Есть идеи, почему он это делает?И есть ли способ остановить это?: p
РЕДАКТИРОВАТЬ : я отредактировал ASM для loop2()
, чтобы удалить все похожие блоки (и поменять местами регистры в последующих записях), и он, кажется, работает правильнои с той же скоростью, что и loop1()
(~ 40% быстрее)