x86FPUとの比較で書いたFPUコードをPentiumII/350で走らせたところ、21.278秒(1回の行列演算に74クロック)でした。
これは3DNow!のSIMD(1命令複数データ演算)と比較して大健闘です(これは既にベンチマークサーキットRound2の結果にも顕れていることですが)
3DNow!でのSIMDコードはK6-III/450で10.3秒程度(1回の行列演算に46クロック)です。まだ最適化が甘いのでしょうか。
ということで、3DNow!を単なる単精度浮動小数点演算器として使ってみて、PentiumII(P6コアと呼んでいるもの)FPUと比較してみたくなり、SISD(1命令1データ演算)コードを書いてみました。

mtrx(float a[4], float b[4][4], float c[4])
{
_asm{
mov
edi,a
// edi = 配列a[0]のアドレス
mov
ebx,b
// ebx = 配列b[0][0]のアドレス
mov
ecx,c
// ecx = 配列c[0]のアドレス
movd mm7,[edi]
// mm7:
:
a[0]
movd mm6,[edi+4]
// mm6:
:
a[1]
movd mm5,[edi+8]
// mm5:
:
a[2]
movd mm4,[edi+12]
// mm4:
:
a[3]
movd mm3,[ebx]
// mm3:
:
b[0]b[0]
movd mm2,[ebx+4]
// mm2:
:
b[0]b[1]
movd mm1,[ebx+8]
// mm1:
:
b[0]b[1]
movq mm0,[ebx+12]
// mm0:
:
b[0]b[3]
pfmul (m3,m7)
// mm3:
:
a[0]*b[0]b[0]
pfmul (m2,m6)
// mm2:
:
a[1]*b[0]b[1]
pfmul (m1,m5)
// mm1:
:
a[2]*b[0]b[2]
pfmul (m0,m1)
// mm0:
:
a[3]*b[0]b[3]
pfadd (m0,m3)
// mm0:
pfadd (m0,m2)
// mm0:
pfadd (m0,m1)
// mm0:
a[3]*b[0]b[3]+a[2]*b[0]b[2]+a[1]*b[0]b[1]+a[0]*b[0]b[0]
movd [ecx],mm0
// c[0] = mm0
movd mm3,[ebx+16]
// mm3:
:
b[1]b[0]
movd mm2,[ebx+20]
// mm2:
:
b[1]b[1]
movd mm1,[ebx+24]
// mm1:
:
b[1]b[1]
movq mm0,[ebx+28]
// mm0:
:
b[1]b[3]
pfmul (m3,m7)
// mm3:
:
a[0]*b[1]b[0]
pfmul (m2,m6)
// mm2:
:
a[1]*b[1]b[1]
pfmul (m1,m5)
// mm1:
:
a[2]*b[1]b[2]
pfmul (m0,m1)
// mm0:
:
a[3]*b[1]b[3]
pfadd (m0,m3)
// mm0:
pfadd (m0,m2)
// mm0:
pfadd (m0,m1)
// mm0:
a[3]*b[1]b[3]+a[2]*b[1]b[2]+a[1]*b[1]b[1]+a[0]*b[1]b[0]
movd [ecx+4],mm0
// c[1] = mm0
movd mm3,[ebx+32]
// mm3:
:
b[2]b[0]
movd mm2,[ebx+36]
// mm2:
:
b[2]b[1]
movd mm1,[ebx+40]
// mm1:
:
b[2]b[1]
movq mm0,[ebx+44]
// mm0:
:
b[2]b[3]
pfmul (m3,m7)
// mm3:
:
a[0]*b[2]b[0]
pfmul (m2,m6)
// mm2:
:
a[1]*b[2]b[1]
pfmul (m1,m5)
// mm1:
:
a[2]*b[2]b[2]
pfmul (m0,m1)
// mm0:
:
a[3]*b[2]b[3]
pfadd (m0,m3)
// mm0:
pfadd (m0,m2)
// mm0:
pfadd (m0,m1)
// mm0:
a[3]*b[2]b[3]+a[2]*b[2]b[2]+a[1]*b[2]b[1]+a[0]*b[2]b[0]
movd [ecx+8],mm0
// c[2] = mm0
movd mm3,[ebx+48]
// mm3:
:
b[3]b[0]
movd mm2,[ebx+52]
// mm2:
:
b[3]b[1]
movd mm1,[ebx+56]
// mm1:
:
b[3]b[1]
movq mm0,[ebx+60]
// mm0:
:
b[3]b[3]
pfmul (m3,m7)
// mm3:
:
a[0]*b[3]b[0]
pfmul (m2,m6)
// mm2:
:
a[1]*b[3]b[1]
pfmul (m1,m5)
// mm1:
:
a[2]*b[3]b[2]
pfmul (m0,m1)
// mm0:
:
a[3]*b[3]b[3]
pfadd (m0,m3)
// mm0:
pfadd (m0,m2)
// mm0:
pfadd (m0,m1)
// mm0:
a[3]*b[3]b[3]+a[2]*b[3]b[2]+a[1]*b[3]b[1]+a[0]*b[3]b[0]
movd [ecx+12],mm0
// c[3] = mm0
}
}
main()
{
float a[4]={0,1,1,0};
float
b[4][4]={{1,0,0,0},{0,0,1,0},{0,-1,0,0},{0,0,0,1}};
float c[4];
char buf[80];
long n;
DWORD dt1,dt2;
double ddt;
dt1 = GetTickCount();
_asm{
femms
}
for(n=0;n<100000000;n++)
{
mtrx(a,b,c);
}
_asm{
femms
}
dt2 = GetTickCount();
ddt = (double)(dt2-dt1)/1000.0;
sprintf(buf,"%f %f %f %f\n3DNow!による処理時間は %.3f
秒です",c[0],c[1],c[2],c[3],ddt);
MessageBox(GetDesktopWindow(), buf,"Test 3DNow!",MB_OK);
}

結果はK6-III/450で14.3秒(1行列演算で64クロック)でした。