Hullo、私はasmの経験があまりないので、アセンブリでカーマックの逆平方根cルーチンを書き直したいと思います。
; float InvSqrt (float x){
;
@173:
push ebp
mov ebp,esp
add esp,-8
;
; float xhalf = 0.5f*x;
;
fld dword ptr [@174]
fmul dword ptr [ebp+8]
fstp dword ptr [ebp-4]
;
; int i = *(int*)&x;
;
mov eax,dword ptr [ebp+8]
mov dword ptr [ebp-8],eax
;
; i = 0x5f3759df - (i>>1);
;
mov edx,dword ptr [ebp-8]
sar edx,1
mov ecx,1597463007
sub ecx,edx
mov dword ptr [ebp-8],ecx
;
; x = *(float*)&i;
;
mov eax,dword ptr [ebp-8]
mov dword ptr [ebp+8],eax
;
; x = x*(1.5f - xhalf*x*x);
;
fld dword ptr [ebp-4]
fmul dword ptr [ebp+8]
fmul dword ptr [ebp+8]
fsubr dword ptr [@174+4]
fmul dword ptr [ebp+8]
fstp dword ptr [ebp+8]
;
; return x;
;
fld dword ptr [ebp+8]
;
; }
;
@176:
@175:
pop ecx
pop ecx
pop ebp
ret
これがコンパイラが生成したものですが、それを最適化してasmルーチンに書き直したいと思います
(生成されたこのコードは、最適なものとはほど遠いです-fpuと整数演算を混合すると、意識のある人によるいくつかのレブライトがそれを大幅に改善する可能性があります)
どのようにそれを最適化することができますか?
編集:
@haroldに答えるように
改善点があります:
1.0 / sqrt(100.0)は私の古いマシンで140サイクルかかります
InvSqrt-cバージョン-は44サイクルかかります(精度は驚くべきものではありませんが)
以下のasmのansverはcバージョンと同じように機能し、29サイクルかかります
(測定値は多少概算かもしれませんが、一般的には大丈夫なIMOのようです。rtdsc1000xforループによって実行され、結果として140000/1000=140サイクル29000/1000=29サイクルなどになります)