3

我正在学习计算机算术。我使用的书(帕特森和轩尼诗)列出了以下问题。

编写 mips 代码对 64 位数据进行双精度整数减法。假设第一个操作数在寄存器 $t4(hi) 和 $t5(lo) 中,第二个在 $t6(hi) 和 $t7(lo) 中。

我对答案的解决方案是

sub  $t3, $t5, $t7   # Subtract lo parts of operands. t3 = t5 - t7
sltu $t2, $t5, $t7   # If the lo part of the 1st operand is less than the 2nd,
                     #   it means a borrow must be made from the hi part
add  $t6, $t6, $t2   # Simulate the borrow of the msb-of-low from lsb-of-high
sub  $t2, $t4, $t6   # Subtract the hi's. t2 = t4 - t6

但是作者针对此问题给出的解决方案如下

对于有符号双精度整数,

subu $t3, $t5, $t7   
sltu $t2, $t5, $t7  
add  $t6, $t6, $t2
sub  $t2, $t4, $t6

对于无符号双精度整数,

subu $t3, $t5, $t7   
sltu $t2, $t5, $t7  
addu $t6, $t6, $t2
subu $t2, $t4, $t6

我对sub/addand操作差异的理解subu/addu是溢出异常是在sub/add而不是在subu/addu. sub/add和 和subu/addu减/加操作数的位以及对有符号或无符号操作数的解释对结果没有影响,这与 in和slt指令sltu不同。

问题 1
我从作者给出的解决方案中推断出正在处理溢出检测,而我在我的解决方案中没有想到相同的解决方案。我对吗?还有什么我想念的吗?

问题 2假设我的上述推论是正确的,为什么在使用and
减去无符号双精度的情况下,作者提供的解决方案会关闭溢出检测?addusubu

4

1 回答 1

6

对于加法和减法,有符号和无符号操作数之间没有区别,除了溢出的概念。当结果的数值与您获得的位序列的解释不匹配时,就会发生溢出。

例如,考虑 8 位序列(MIPS 有 32 位寄存器,但在我的示例中 8 位更容易)。让我们假设无符号解释:8 位序列表示 0 到 255(含)之间的数值。如果我将 10010011(数值 147)添加到 01110110(数值 118),那么我得到 00001001(数值 9)。9 不等于 147+118。我得到这个结果是因为数学值是 265,它不适合 8 位。加法结果需要 9 位,但高位 9 位已被丢弃。

现在,想象一下带有签名解释的相同示例。10010011 现在的数值为 -109。01110110仍然有数值118,得到的结果(00001001)的值为9。-109和118的数学和为9,所以没有溢出。

这意味着溢出的概念取决于您如何解释这些值。有符号和无符号解释的加法机制是相同的(对于相同的位输入序列,您会得到相同的输出位序列——这是对负符号值使用二进制补码的全部意义),但溢出处理不同。

MIPS 体系结构提供了在溢出时触发异常的方法。从概念上讲,对 32 位字有三种可能的加法运算:

  • 默默忽略溢出的加法(结果被截断)
  • 发生有符号溢出时引发异常的加法(如果输入和输出序列被解释为有符号数字,则会出现溢出)
  • 发生无符号溢出时引发异常的加法(如果输入和输出序列被解释为无符号数,则存在溢出)

MIPS 实现了前两种加法,分别用adduadd操作码。在 MIPS 文档中,它们分别称为无符号和有符号算术。没有用于在无符号溢出时引发异常的操作码。在实践中,C 编译器仅使用addu,但它们可以add用于有符号类型(这是 C 标准允许的,但会破坏大量现有代码)。Ada 编译器使用addAda 是因为 Ada 强制进行溢出检查。

话虽如此...

Patterson 和 Hennessey 希望在 64 位整数上实现有符号和无符号运算。对于无符号算术,他们不希望有任何例外,因此他们使用adduand subu对于有符号算术,他们希望在数学结果不适合带符号解释的64 位序列时发生异常。他们不想因为在处理低 32 位一半时出现类似溢出的虚假情况而引发异常。这就是为什么他们将 asubu用于低部分。

您的解决方案是错误的,因为它可能会引发不应出现的异常。假设您想从 -2000000000(减去 20 亿)中减去 2000000000(20 亿)。数学结果是 4000000000(四十亿)。这两个操作数和结果肯定适合 64 位(可表示的范围是 -9223372036854775808 到 9223372036854775807)。因此,对于 64 位有符号算术,没有溢出:应该没有例外。但是,在这种情况下,您的第一个sub将报告溢出。这sub适用于 32 位值和带符号的 32 位算术。它的操作数将是 01110111001101011001010000000000 和 10001000110010100110110000000000。请注意,这些值都适合 32 位:这些值的 32 位带符号解释分别是正负二十亿。然而,减法结果是 40 亿,它不适合 32 位(作为有符号数)。因此,你sub提出了一个例外。

根据经验,溢出检测是关于做依赖于符号解释的事情,这会影响最高有效位的处理。对于大整数算术,除了最重要的单词之外的所有单词都应被视为无符号,因此addu/subu无处不在。作为第一步,如果您首先专注于无符号算术,事情会更容易理解,无一例外(然后您只使用adduand subu,并且从不 add使用or sub)。

于 2010-10-27T13:27:35.583 回答