【问题标题】:Why do some CPUs have different instructions to do signed and unsigned operations?为什么有些 CPU 有不同的指令来执行有符号和无符号操作?
【发布时间】:2020-05-31 23:19:37
【问题描述】:

假设我们有以下二进制数及其表示形式:

| bin | unsigned | signed   |
|:---:|----------|----------|
| 110 | 6        | -2       |
| 111 | 7        | -1       |

现在无论是签名还是未签名,111 + 110 = 1101, 现在我可以将结果 1101 解释为有符号或无符号,即:

| bin  | unsigned | signed   |
|:----:|----------|----------|
| 1101 | 13       | -3       |

与小数运算匹配的:

6+7 = 13
-1-2 = -3

signed additionunsigned addition 之间没有区别。那么为什么 CPU 会有不同的电路/指令来进行这种操作呢?

【问题讨论】:

  • 哪些CPU指令集有不同的有符号和无符号加法?一些指令可能具有立即参数的符号扩展模式,或者能够设置不同的标志,但是如果没有具体的例子就很难说。
  • @trentcl:大概只有​​一个补码机器有不同的add 指令。 (如果您不计算 MIPS addaddu 之类的东西;add 会在 2 的补码有符号溢出时陷入陷阱,所以编译器对所有有符号和无符号的东西都使用 addu。这不是真的 i> 有符号与无符号,它只是简单的添加,有/没有额外的有符号溢出陷阱。)我可以想象一些具有有限标志的机器有不同的添加,根据有符号溢出或无符号进位(又名溢出)设置“溢出”标志),取决于操作码,而不是同时设置不同的标志
  • @trentcl 所以在我的add 示例中,拥有2个差异(有符号和无符号)指令的唯一原因是查看溢出在哪里?当传递sign 位时(即最大位之前的1)发生符号字溢出的含义,在传递最大位时发生无符号世界溢出,对吗?

标签: binary cpu cpu-architecture signed instructions


【解决方案1】:

这取决于二进制表示。这是 2s 补码表示的一个要点——当使用 2s 补码时,固定宽度操作数的有符号和无符号加法、减法和乘法以及相同宽度的结果是相同的,因此您可以对两者使用相同的硬件指令。

如果您使用 1 的补码或符号幅度,则需要在有符号和无符号运算之间存在细微差别。

这里的划分不同,扩展操作也不同。

【讨论】:

    【解决方案2】:

    因为 2 的补码加/减与无符号加/减是相同的二进制运算。但是为了比较(以及除法和加宽乘法),将 MSB 解释为符号位与否并不重要。

    有些 CPU 只有一条 cmp 指令来设置所有标志,然后您的分支指令会检查特定标志条件(谓词)。其他没有标志/条件代码的 CPU(如 MIPS 和 RISC-V)在其比较寄存器指令中需要谓词。

    x86 / ARM 上的 SIMD 比较指令也是寄存器比较指令,不设置多个不同的标志,因此它们也将谓词作为比较指令的一部分(例如 cmpps 使用谓词的立即字节,或对于整数,有pcmpgtd / pcmpeqd。)

    【讨论】:

    • @Josh:除法不是,它通常在缩小。例如MIPS 具有特殊的 LO 和 HI 寄存器,用于除法的双宽度输入和乘法的双宽度输出。 In MIPS, what is HI and LO。 x86 的扩展又名全乘指令是 mulimul(单操作数形式),并执行 32 x 32 => 64 位乘法(或 64x64 => 128),将结果放入一对寄存器中。 Why is imul used for multiplying unsigned numbers? 显示“正常”与扩大版本:只有高一半关心符号解释
    • 此外,溢出行为通常是不同的。 MIPS 的无符号使用非信号环绕,而有符号溢出会产生异常。
    • @PaulA.Clayton:MIPS 助记符有点名不副实。 addu 是编译器用于所有内容的“正常”包装添加。只有当你想要捕获签名溢出时,你才使用add。这是唯一的区别,在有符号值上使用 addu 没有问题。我不认为adduadd 是无符号与有符号的,我认为add 是MIPS 公开有符号溢出检测的可选方式。 IIRC,甚至 MIPS 自己的 asm 手册都表明助记符具有误导性。
    • C 编程语言将有符号加法溢出定义为未定义(允许溢出异常 [或鼻恶魔])。环绕似乎主要用于地址计算(并促进范围内检查的单一比较);其他溢出通常是错误。由于溢出是根据有符号解释检查的(将最大正整数加一将溢出,即使进位到最高有效位将是无符号的正确表示)。
    • @PaulA.Clayton:但编译器希望能够将整数 + 视为关联。只有在创建源中不存在的不同临时对象不会引入新陷阱的情况下,您才能这样做。是的,MIPS 的设计似乎假设检查加法是正常情况,助记符天真地基于您可能想要的非优化 C 编译器。
    猜你喜欢
    • 2012-12-13
    • 2012-10-19
    • 2019-03-16
    • 1970-01-01
    • 2012-04-26
    • 2012-10-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    相关资源
    最近更新 更多