为什么有些算术指令有有符号/无符号变体,而有些则没有

问题描述

假设我们有:

a = 0b11111001;
b = 0b11110011;

如果我们用手在纸上做 AdditionMultiplication,我们会得到这个结果,我们不在乎它是否签名:

a + b = 111101100
a * b = 1110110001011011

我知道乘法将宽度加倍,加法可能会溢出:

Why is imul used for multiplying unsigned numbers?

Why do some CPUs have different instructions to do signed and unsigned operations?

我的问题是,为什么像 Add 这样的指令通常没有签名/未签名版本,而 MultiplyDivide 有?

为什么我们不能有一个通用的 unsigned multiply,像我上面做的那样做数学运算,如果它被烧毁,就截断结果,就像 Add 一样。

或者另一个,为什么 Add 不能有签名/未签名版本。我检查了一些架构,情况似乎是这样。

解决方法

我认为您选择的示例误导了您认为可以通过将 8x8 => 16 位无符号产品截断为 8 位来获得有符号产品。事实并非如此。

(249-256) * (243-256) = 0x005b,一个小的正结果恰好适合完整结果的下半部分。但是完整的有符号结果并不总是无符号乘积的操作数大小截断。

例如,-128 * 127-16256,或者作为 16 位 2 的补码,0xc080

但是 0x80 * 0x7f+ 16256,即 0x3f80。相同的下半部,不同的上半部。

或者另一个例子,参见Why are signed and unsigned multiplication different instructions on x86(-64)?


扩大有符号乘法不涉及任何截断。有符号和无符号乘法的低半部分是相同的,这就是为什么例如 x86 只有立即数和 2 操作数形式的 imul,而不是 mul。只有扩大乘法需要一个单独的形式。 (或者,如果您想要 FLAGS set according to unsigned overflow of the low half,instead of signed overflow. - 因此,如果您想检测完整的未签名结果何时不适合,则无法轻松使用非扩展 imul。)