两个64位整数相乘得到的乘积需要128位来表示,x86-64指令集提供两个指令用于无符号乘法和有符号乘法,如下:
imulq S :R[%rdx] : R[%rax] <-- S * R[%rax]
mulq S :R[%rdx] : R[%rax] <-- S * R[%rax]
imulq用于实现有符号乘法,mulq用于实现无符号乘法,其余操作相同,将rax寄存器中保存的64位整数和给定操作数S相乘,得到一个128位的结果,其中高64位放在rdx寄存器中,低64位放在rax寄存器中,一个例子:
#include <inttypes.h>
typedef unsigned __int128 uint128_t;
void func(uint128_t *dest, uint64_t x, uint64_t y) {
*dest = x * (uint128_t)y;
}
这里inttypes.h提供了对uint64_t的支持,表示无关机器类型的64位无符号数,但是没有关于128位的扩展,因此这里使用的是gcc提供的128位整数支持,查看汇编指令如下:
func:
movq %rsi, %rax
mulq %rdx
movq %rax, (%rdi)
movq %rdx, 8(%rdi)
ret
这里先将x放到rax寄存器中,然后和rdx寄存器中保存的y相乘,mulq指令将低64位放在rax中,高64位放在rdx中,最后通过两个mov指令放在rdi寄存器中保存的地址开始的16位地址中
除法和乘法类型,指令为idivq,单操作数,将rdx的高64位和rax的低64作为一个128位的除数,从操作数中取被除数,得到商和余数,商放在rax中,余数放在rdx中。对于64位除数,rdx中的值看符号位,全0或者全1,x86-64指令集中有专门的指令用来扩展符号位,例子:
void func(long x, long y, long *qp, long *rp) {
long q = x / y ;
long r = x % y;
*qp = q;
*rp = r;
}
查看汇编指令如下:
func:
movq %rdx, %r8
movq %rdi, %rax
cqto
idivq %rsi
movq %rax, (%r8)
movq %rdx, (%rcx)
ret
这里第二行指令将x的值作为除数保存在rax寄存器中,第三行指令cqto扩展符号位rdx寄存器中,因此第一行先保存了rdx寄存器的值。第四行idivq指令y作为被除数执行除法指令,后续指令依次保存商和余数。
无符号除法指令divq,将rdx寄存器中值清零,其余操作同上