Hullo,我对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例程
(生成的代码远非最优化的东西 - 将fpu与整数混合 操作,也许有意识的人会进行一些改进会大大改善它。)
如何进行optymized?
编辑:
回答@harold
有一个改进:
1.0 / sqrt(100.0)在我的旧机器上需要140个周期
InvSqrt - c版本 - 需要44个周期(虽然准确度并不令人惊叹)
在asm下面的ansver与c版本相同,需要29个周期
(测量可能有些近似但是看起来很好IMO, 由rtdsc 1000x for循环完成,然后产生140000/1000 = 140个循环 29000/1000 = 29周期等等)
答案 0 :(得分: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)
它不应该太难以遵循,但如果你需要它我会制作一些堆栈图。