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

Jos*_*vin 23 x86 assembly x86-64 twos-complement

我认为2的补码的重点是对于有符号和无符号数字的操作可以采用相同的方式.维基百科甚至特别列出了多重作为其中一项有益的操作.那么为什么x86对每个都有单独的指令,mul并且imul?x86-64仍然如此吗?

Ste*_*non 32

加法和减法是相同的,乘法的低半部分也是如此.然而,完全相乘则不是.简单的例子:

在32位二进制补码中,-1与无符号数量2**32 - 1具有相同的表示形式.但是:

-1 * -1 = +1
(2**32 - 1) * (2**32 - 1) = (2**64 - 2**33 + 1)
Run Code Online (Sandbox Code Playgroud)

(注意两个结果的低32位是相同的;当我说"乘法的低半部分"是相同的时候,这就是我的意思).

  • @JosephGarvin:不,只要你超过原来的长度,就需要单独的指令.考虑例如`-1*1 = -1`对比`0xFFFFFFFF*1 = 0xFFFFFFFF`. (7认同)
  • 因为结果的低半部分是相同的而且C程序经常产生与操作数大小相同的结果,所以现代x86 CPU通常[针对imul进行了优化](http://stackoverflow.com/a/4040834/995714)和它有更多的形式(`imul rs,rd1 [,rd2]`)而mul只有1种形式`mul rx` (2认同)
  • 结果的高半部分在有符号和无符号版本中是不同的,但它们[确实有关系](http://stackoverflow.com/a/28827013/995714),因此可以从高符号结果获得高无符号结果反之亦然 (2认同)
  • 也许链接的答案意味着非完全乘法。 (2认同)
  • @plasmacel:正确,[您链接的答案](https://softwareengineering.stackexchange.com/a/358203/297215)假设一个像C中那样的非扩展乘法,该问题被标记为C。在 C 中,如果您想要 uint64_t 产品,并且输入较窄,则需要 `a * (uint64_t)b`。它与具有扩展乘法指令的汇编的实际情况不符。 (2认同)

Sco*_*ger 6

对于2和3操作数版本,结果将是相同的,除了mul和imul指令在设置CF和OF标志(进位和溢出)的方式上有所不同.

想想这两种情况:溢出方面的-1*-1与0xFFFFFFFF*0xFFFFFFFF,你会得到这个想法.


sup*_*cat 5

两个16位数的乘法产生32位结果.即使其中一个数字为"1",处理器也会有效地将另一个数字扩展到32位.将数字扩展到更长的比特长度的过程是对有符号和无符号值不同的操作之一(符号重要的另一个重要操作是幅度比较,这也是除法的必要部分).


归档时间:

查看次数:

12054 次

最近记录:

11 年,7 月 前