为什么在x86(-64)上,有符号和无符号乘法是不同的指令?

31

请参阅关于汇编语言中mul和imul指令理解问题的讨论,其中包括imul reg,r/m而不是单操作数扩展形式的不同乘法形式。还有无符号和有符号乘法的最低有效位相同数量是多少? - Peter Cordes
3个回答

41

加法和减法是相同的,乘法的低半部分也是相同的。但是完整的乘法不同。一个简单例子:

在32位二进制补码中,-1与无符号数2**32 - 1具有相同的表示方式。然而:

-1 * -1 = +1
(2**32 - 1) * (2**32 - 1) = (2**64 - 2**33 + 1)

(请注意,两个结果的低32位是相同的;这就是我所说的“乘法低半部分”相同的含义)。


9
不行,一旦超过原始长度,您就需要单独的指令。例如考虑“-11=-1”和“0xFFFFFFFF1=0xFFFFFFFF”。@JosephGarvin - Ilmari Karonen
3
由于C程序常常产生与操作数相同大小的结果且其低位部分相同,现代x86 CPU通常会对imul进行优化。imul有很多不同的形式(如:imul rs, rd1[, rd2]),而mul只有一种形式(mul rx)。 - phuclv
2
结果的高半部分在有符号和无符号版本中是不同的,但它们之间存在关系,因此可以从高有符号结果获得高无符号结果,反之亦然。 - phuclv
2
可能链接的答案意味着非完全乘法。 - plasmacel
2
@plasmacel:没错,你链接的那个答案(https://softwareengineering.stackexchange.com/a/358203/297215)假设了一个非扩展乘法,C语言中有这种标记。如果想要一个uint64_t的积,需要在输入值较小的情况下使用“a *(uint64_t)b”。但是这与汇编中使用扩展乘法指令的实际情况不符。 - Peter Cordes
显示剩余2条评论

8

两个16位数的乘积得到一个32位的结果。 即使其中一个数字是“1”,处理器也会将另一个数字有效地扩展到32位。 将数字扩展到更长的位长度是有符号和无符号值之间不同的操作之一(另一个重要操作是符号比较,这也是除法的重要部分)。


8

两个和三个操作数版本的结果相同,除了mul和imul指令在设置CF和OF标志(进位和溢出)方面有所不同。

以溢出为例,想象一下-1 * -1与0xFFFFFFFF * 0xFFFFFFFF的情况,你就能理解了。


1
mul 指令没有 2 或 3 操作数版本。唯一的区别 可能 是 FLAGS 设置,但这种情况很少出现,因此英特尔决定只提供更快的非扩展乘法 imul 操作码。相关:C unsigned long long 和 imulq 取决于这个决定:如果你想要一个溢出检查的无符号乘法,不幸的是你需要使用单操作数 mul 而不是尝试从 imul reg,reg 的 FLAGS 中做些什么。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接