混淆:关于ARM文档中的进位标志的疑惑

8
在ARM文档这里中提到:

如果减法的结果为正数或零,则会发生进位carry。

我从这个SO答案中了解到,在无符号数减法中,当被减数(减数)大于减数(被减数)时,会设置进位标志carry flag。

因此,考虑以下示例:

r1 = 5
r2 = 10
CMP r1, r2

Compare (CMP)指令进行减法运算,如此处所述,然后设置相应的标志位。在这种情况下,r1-r2 = 5-10 = -5。由于我们这里出现了无符号下溢(5 < 10),因此我们期望进位标志被设置。但根据ARM文档,结果(-5)既不是正数也不是零,因此不应设置进位标志。(假设我们以有符号方式查看结果;否则,根据文档,进位永远不会发生)。

ARM文档错了吗?我的理解有误吗?


无符号溢出是加法的最高有效位的进位。如果加法的最高有效位的进位和进位不同,则设置有符号溢出。逻辑使用加法来进行减法。二进制补码取反(-a)= -(a),第二个操作数被反转(一补数),并且进位被反转(为1)。一些体系结构会反转进位以指示无符号借位而不是无符号溢出。 - old_timer
你链接的Q&A是关于x86的,其中进位标志位在减法中作为借位标志。而ARM则相反。 - Peter Cordes
@PeterCordes 哦,哈哈;感谢澄清。(这让我困惑了,因为fuz的答案也有所澄清) - takanuva15
3个回答

10
ARM在借位(即减法)时使用反向进位标志。这就是为什么当没有借位时进位被设置,有借位时进位被清除。这个设计决策使得构建ALU稍微简单一些,这也是为什么一些CPU采用这种方法的原因。

有趣...所以对于其他汇编语言中未反转进位标志位的程序,我需要将CMP 5,10理解为“第一个参数是否比第二个参数小(无符号)”?(这可能一直让我感到困惑) - takanuva15
等等,从我第一个评论开始,因为CMP 5,10不设置进位标志,所以CC / LO标志将为true。这意味着我应该读取CMP 5,10(跟随CC检查)为“第一个参数是否小于第二个无符号参数”? - takanuva15
1
哦,抱歉,我误读了你的第一条评论。是的,CMP a,b后跟一个BCC,如果a < b无符号,则会分支。 - fuz
一些指令集将进位反转为借位,而有些则不会。我绝不会假设ARM是唯一这样做的。你必须逐个检查每个新的指令集。与x86相比,ARM的好处在于标志和条件行为得到了很好的记录,你可以从if V set和not N等等中准确地知道标志代表什么。 - old_timer
进行一个非常简单的测试,让一个操作数保持不变,比如说为5,另一个操作数分别取3、4、5、6、7,然后检查标志位,你可以看到当一个操作数大于等于另一个操作数时会发生什么,然后再小于另一个操作数时会发生什么。 - old_timer
显示剩余7条评论

2

我们不需要全部32位来显示减法的过程。

5 - 3

从小学我们就知道 5 - 3 = 5 +(-3)。这是逻辑运算中的计算方法。二进制补码的一个特点是,要得到-3,你需要将3取反并加1,所以

5 - 3

      1
   0101
 + 1100
=========

完成它

  11011
   0101
 + 1100
=========
   0010

通用地(不针对特定处理器),5 - 3 = 2。错位比特的进位和借位都是1,所以有符号溢出未设置,借位为1。但是某些架构会反转第二个操作数和进位(到lsbit),同时也反转借位并称其为borrow。而有些则不会。

在类似大于和小于的情况下,一些文档会记录进位比特的定义。

5 - 4

  11111
   0101
 + 1011
=========
   0001

5 - 5

  11111
   0101
 + 1010
=========
   0000

5 - 6

  00011
   0101
 + 1001
=========
   1111

5 - 7

  00011
   0101
 + 1000
=========
   1110

这段文字表明,如果查看原始进位输出,当操作数b等于操作数a时,它会切换;当b小于a时,设置该值;当b等于或大于a时,清除该值。因此,如果架构未被修改,则可以在无符号大于或小于(但不相等)的情况下使用进位位。在其中一个方向上,大于或等于由该标志定义,其方向取决于架构(如果将进位输出反转为借位)。在另一个方向上,您可以翻转操作数并使用一位,也可以使用N和C来确定某些内容是否大于或等于。
与其他一些文档不同,ARM文档会显示每个条件语句所表示的标志,并且根据上述内容或能够在简单测试中重复这些标志,您可以弄清楚它们是反转还是不反转。指令sbb是带借位减法,而不是带进位减法,这有点暗示了该指令集如何解释该位。

1

我对以下内容感到困惑:

  • ALU状态标志
    • 如果加法结果大于或等于232,则发生进位;如果减法结果为正数,则发生借位,或者在移动或逻辑指令中使用内联桶移位器操作时发生。

思路: 5 - 3 = 2 -> 正数结果 -> 应该是 C=1 吗?

最终找到了ARM官方有用的文档:进位标志

在A32/T32代码中,C可以通过以下方式设置:

  • 对于加法(包括比较指令CMN),如果加法产生了进位(即无符号溢出),则将C设置为1;否则,将其设置为0。
  • 对于减法(包括比较指令CMP),如果减法产生了借位(即无符号下溢),则将C设置为0;否则,将其设置为1。

需要知道的是:

  • 对于减法:5 - 10 = -5 -> 产生了借位 = 无符号下溢 = 负数结果 -> 应该是 C=0
    • 注意:不是 C=1

所以,根据以下内容:

  • 对于减法:5 - 3 = 2 -> 正数结果 -> 应该是 C=1

请注意,如果您将输入解释为“无符号”,并且讨论的是数学结果,而不是截断/包装的32位无符号或有符号结果,则此“正结果”陈述是正确的。进位标志是加法结果的第33位,或者是仿佛通过将第二个操作数取反并将进位输入取反来执行sub/sbc的进位输出。所以对于5-3,它是使用5~3以及进位输入为1进行的addc操作。(这就是实际发生的情况,只是它是一个低延迟的加法器,而不是串行进位,但结果是相同的。) - undefined

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