私はアルゴリズムのボトルネックである数千時間と呼ばれるループ内の命令のブロックを最適化しようとしています。
このコード ブロックは、N ベクトル 3 (iV 配列) に対する N 行列 3x3 (iA 配列) の乗算を計算し、N の結果を oV 配列に格納します。(N は固定ではなく、通常は 3000 から 15000 の間です)
行列とベクトルの各行は、SSE 最適化を利用するために 128 ビット (4 つの float) に揃えられます (4 番目の浮動値は無視されます)。
C++ コード:
__m128* ip = (__m128*)iV;
__m128* op = (__m128*)oV;
__m128* A = (__m128*)iA;
__m128 res1, res2, res3;
int i;
for (i=0; i<N; i++)
{
res1 = _mm_dp_ps(*A++, *ip, 0x71);
res2 = _mm_dp_ps(*A++, *ip, 0x72);
res3 = _mm_dp_ps(*A++, *ip++, 0x74);
*op++ = _mm_or_ps(res1, _mm_or_ps(res2, res3));
}
コンパイラは次の命令を生成します。
000007FEE7DD4FE0 movaps xmm2,xmmword ptr [rsi] //move "ip" in register
000007FEE7DD4FE3 movaps xmm1,xmmword ptr [rdi+10h] //move second line of A in register
000007FEE7DD4FE7 movaps xmm0,xmmword ptr [rdi+20h] //move third line of A in register
000007FEE7DD4FEB inc r11d //i++
000007FEE7DD4FEE add rbp,10h //op++
000007FEE7DD4FF2 add rsi,10h //ip++
000007FEE7DD4FF6 dpps xmm0,xmm2,74h //dot product of 3rd line of A against ip
000007FEE7DD4FFC dpps xmm1,xmm2,72h //dot product of 2nd line of A against ip
000007FEE7DD5002 orps xmm0,xmm1 //"merge" of the result of the two dot products
000007FEE7DD5005 movaps xmm3,xmmword ptr [rdi] //move first line of A in register
000007FEE7DD5008 add rdi,30h //A+=3
000007FEE7DD500C dpps xmm3,xmm2,71h //dot product of 1st line of A against ip
000007FEE7DD5012 orps xmm0,xmm3 //"merge" of the result
000007FEE7DD5015 movaps xmmword ptr [rbp-10h],xmm0 //move result in memory (op)
000007FEE7DD5019 cmp r11d,dword ptr [rbx+28h] //compare i
000007FEE7DD501D jl MyFunction+370h (7FEE7DD4FE0h) //loop
私は低レベルの最適化にあまり詳しくないので、質問は次のとおりです。アセンブリ コードを自分で書いた場合、可能な最適化がいくつか見られますか?
たとえば、次のように変更すると、より速く実行されますか?
add rbp,10h
movaps xmmword ptr [rbp-10h],xmm0
に
movaps xmmword ptr [rbp],xmm0
add rbp,10h
また、ADD命令はINCよりも高速であることも読みました...