1

你好,我对asm没有太多经验,我想在汇编中重写carmack的倒平方根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 例程

(生成的此代码远非最佳 i 事物 - 将 fpu 与整数运算混合,也许有意识的人重新编写会大大改善它)

如何优化?

编辑:

至于回答@harold

有一个改进:

  • 1.0/sqrt(100.0) 在我的旧机器上需要 140 个周期

  • InvSqrt - c 版本 - 需要 44 个周期(尽管准确度并不惊人)

  • asm 中的 ansver 与 c 版本相同,需要 29 个周期

(测量值可能有些近似,但 IMO 总体上似乎没问题,由 rtdsc 1000x for loop 完成,然后产生 140000/1000 = 140cycles 29000/1000 = 29cycles 等等)

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 回答