[英]implement 64-bit arithmetic on a 32-bit machine
以下代碼計算x和y的乘積,並將結果存儲在內存中。 數據類型ll_t被定義為等於long long。
typedef long long ll_t;
void store_prod(ll_t *dest, int x, ll_t y) {
*dest = x*y;
}
gcc生成以下匯編代碼實現計算:dest at%ebp + 8,x at%ebp + 12,y at%ebp + 16
1 movl 16(%ebp), %esi
2 movl 12(%ebp), %eax
3 movl %eax, %edx
4 sarl $31, %edx
5 movl 20(%ebp), %ecx
6 imull %eax, %ecx
7 movl %edx, %ebx
8 imull %esi, %ebx
9 addl %ebx, %ecx
10 mull %esi
11 leal (%ecx,%edx), %edx
12 movl 8(%ebp), %ecx
13 movl %eax, (%ecx)
14 movl %edx, 4(%ecx)
此代碼使用三次乘法來實現在32位機器上實現64位算術所需的多精度算法。 描述用於計算產品的算法,並注釋匯編代碼以顯示它如何實現您的算法。
我不明白上面的匯編代碼中的第8行和第9行。 有人可以幫忙嗎?
我把它轉換成了intel語法。
mov esi, y_low
mov eax, x
mov edx, eax
sar edx, 31
mov ecx, y_high
imul ecx, eax ; ecx = y_high *{signed} x
mov ebx, edx
imul ebx, esi ; ebx = sign_extension(x) *{signed} y_low
add ecx, ebx ; ecx = y_high *{signed} x_low + x_high *{signed} y_low
mul esi ; edx:eax = x_low *{unsigned} y_low
lea edx, [ecx + edx] ; edx = high(x_low *{unsigned} y_low + y_high *{signed} x_low + x_high *{signed} y_low)
mov ecx, dest
mov [ecx], eax
mov [ecx + 4], edx
上面的代碼所做的是乘以2個64位有符號整數,它們保留了產品中最不重要的64位。
其他64位被乘數來自哪里? 它的x
符號從32位擴展到64. sar
指令用於將x's
符號位復制到edx
所有位。 我將此值稱為僅包含x's
符號x_high
。 x_low
是實際傳遞給例程的x
的值。
y_low
和y_high
是y
的最小和最重要的部分,就像x's
x_low
和x_high
一樣。
從這里開始很簡單:
product = y
* {signed} x
=
( y_high
* 2 32 + y_low
)* {signed}( x_high
* 2 32 + x_low
)=
y_high
* {signed} x_high
* 2 64 +
y_high
* {signed} x_low
* 2 32 +
y_low
* {signed} x_high
* 2 32 +
y_low
* {signed} x_low
y_high
* {signed} x_high
* 2 64未計算,因為它不會影響產品的最低64位。 如果我們對完整的128位產品感興趣(完整的96位產品用於挑剔),我們會計算它。
y_low
* {signed} x_low
使用無符號乘法計算。 這樣做是合法的,因為2的補碼有符號乘法給出了與無符號乘法相同的最低有效位。 例:
-1 * {signed} -1 = 1
0xFFFFFFFFFFFFFFFF * {unsigned} 0xFFFFFFFFFFFFFFFF = 0xFFFFFFFFFFFFFFFE0000000000000001(64個最低有效位相當於1)
考慮第8行和第9行的上下文。
此時, ESI
包含y
的下半部分, EBX
包含sgn(x)
。 所以第8行只是計算sgn(x) * (y % 2^32)
並將其存儲在EBX
。
第9行借鑒了這一結果。 到第9行發生時, ECX
包含乘法的部分上半部分,即x * (y >> 32)
。 因此, EBX+ECX
最終成為我們在最后一步中計算的內容加上我們在前一行中找到的部分上半部分。
完整的算法本身非常整潔;)
編輯:回應下面的評論......
第4行:考慮一下SAR EDX, 31
(或者你喜歡, sar $31, %edx
)真的意味着什么。 由於EDX
是一個32位寄存器,因此最終會得到兩個值中的一個。 哪兩個? 考慮它們在帶符號算術的上下文中的含義。
第7行:此時EDX
包含對以下操作非常有用的東西。 我只是把它移到需要去的地方。
imul的作用是將eax的內容與ecx相乘,並將ex中的低32位和edx中的高32位保存。
addl據我記得添加兩個寄存器並將其保存在第一個寄存器上,所以在本例中為ebx。 (我不確定它是否會做任何其他事情並且在addl代表之后l)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.