您應該在現代代碼中使用SSE/SSE2 for sqrt,而不是x87。用一條指令可以直接將gp寄存器中的整數轉換爲xmm寄存器中的double。
cvtsi2sd xmm0, ebx
sqrtsd xmm0, xmm0 ; sd means scalar double, as opposed to SIMD packed double
cvttsd2si ebx, xmm0 ; convert with truncation (C-style cast)
; cvtsd2si ecx, xmm0 ; rounded to nearest integer (or whatever the current rounding mode is)
這適用於64位整數,太(rbx
),但要注意double
只能完全代表整數高達約2^53(尾數大小)。如果你想檢查一個整數是否是一個完美的正方形,你可以使用float sqrt,然後對整數結果進行試乘。 ((a*a) == b
)
有關指南,教程和手冊的鏈接,請參閱x86。
需要注意的是,插入碼到C程序中的中間是完全錯誤的做法。 GNU C inline asm是實現asm最困難的方式,因爲您必須真正瞭解所有事情才能正確使用約束。讓他們錯誤可能會導致其他周圍的代碼以微妙而難以調試的方式破壞,而不僅僅是您在內聯asm錯誤時所做的事情。有關這方面的更多詳細信息,請參閱x86標記wiki。
如果你想int a = sqrt((int)b)
,那麼寫在你的代碼,讓編譯器爲你生成這三個指令。通過一切手段閱讀和理解編譯器的輸出,但不要盲目地在asm("")
的中間插入一個序列。
例如爲:
#include <math.h>
int isqrt(int a) { return sqrt(a); }
(GCC 5.3沒有-ffast-數學):
pxor xmm0, xmm0 # D.2569
cvtsi2sd xmm0, edi # D.2569, a
sqrtsd xmm1, xmm0 # tmp92, D.2569
ucomisd xmm1, xmm1 # tmp92, tmp92
jp .L7 #,
cvttsd2si eax, xmm1 # D.2570, tmp92
ret
.L7:
sub rsp, 8 #,
call sqrt #
add rsp, 8 #,
cvttsd2si eax, xmm0 # D.2570, tmp92
ret
我想sqrt()
必須設置errno在某些類型的錯誤。:/
隨着-fno-math-errno
:
pxor xmm0, xmm0 # D.2569
cvtsi2sd xmm0, edi # D.2569, a
sqrtsd xmm0, xmm0 # tmp92, D.2569
cvttsd2si eax, xmm0 # D.2570, tmp92
ret
的pxor
是打破XMM0以前的內容虛假的依賴,因爲cvtsi2sd
做出的奇怪的設計決定離開DEST載體的上半章修改。如果您想要將轉換結果插入現有向量中,這種方法纔有用,但已經有cvtdq2pd
來執行打包轉換。 (他們可能沒有考慮64位整數,因爲當Intel發佈SSE2時,AMD64仍然在繪圖板上)。
您不能從通用寄存器加載到FPU中。你需要經歷記憶。請參閱指令集參考。 '推ebx; fild dword [esp]; FSQRT; fistp dword [esp];流行ebx'。請注意,通常不需要組裝,並且gcc內聯彙編是一個複雜的野獸。 – Jester
請製作一個[mcve]而不是一個簡單的代碼片段。 – fuz
@Jester嘿我在一些網站看到這個方案,但不明白我應該插入什麼,而不是dword和esp? – user5618793