1

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サイクルなどになります)

4

1 に答える 1

3

これらのメモリへの移動/メモリからの移動の多くは、実際には必要ありません。ただし、これはおそらくそれほど改善されていません(特に、そもそもこれを行わず、SSEを使用する場合と比較して)。

未検証:

; i = 0x5f3759df - (reinterpret_cast<int32>(number) >> 1)
mov eax, dword ptr [ebp+8]
sar eax,1
mov edx, 0x5f3759df
sub edx, eax
mov dword ptr [ebp-4], edx
; y = reinterpret_cast<float>(i)
fld dword ptr [ebp-4]
; x2 = numer * 0.5f
fld dword ptr [ebp+8]
fmul dword ptr [half]
; (x2 * y) * y
fmul st(0), st(1)
fmul st(0), st(1)
; 1.5f - (stuff)
fld dword ptr [threehalfs]
fsubrp st(1), st(0)
; y * (stuff)
fmulp st(1), st(0)

従うのはそれほど難しいことではありませんが、必要に応じてスタック図を作成します。

于 2012-08-19T16:02:01.573 に答える