0

在大多数指令集中,分支指令是根据状态寄存器上的标志执行的。

在高级语言中,布尔值是一种数据类型,可以通过评估表达式(通常为 ==、!=、<、>、>=、<= 和其他变体)创建并存储在变量中。

为什么该程序集选择在状态标志上进行分支,而不是让指令将布尔结果存储在寄存器中?

鉴于允许将测试结果存储在变量中的语言数量众多,我原以为指令集会随之发展,从而可能创建更高效​​的程序。

这种将测试结果存储到状态寄存器然后在标志上分支的惯例仅仅是传统还是有理由表明基于标志的方法比能够直接从通用寄存器存储和测试更有效?

4

3 回答 3

3

如果您想“将布尔结果存储在寄存器中”,则需要单独的指令来<, <=, >,>=等。您还需要一组用于有符号比较,另一组用于无符号比较。

在 x86 指令集中,所有这些都有一条指令cmp(设置一堆标志),然后您使用适当的or指令查看您感兴趣的标志(例如,对于条件跳转,您使用, / , , /表示无符号(“低于”/“高于”),而, / , , /表示有符号(“更少”/“更大”))。jxxsetxxjbjbejnajajaejnbjljlejngjgjgejnl

这种方法的另一个特点是,您可以在执行变异操作后实际检查标志,例如进行加法或借用减法。示例(假设esi指向一个 128 位数字,该数字被添加到另一个edi指向的 128 位数量):

add [edi], [esi]
adc [edi+4], [esi+4]
adc [edi+8], [esi+8]
adc [edi+12], [esi+12]
jc overflow

那只是 5 条指令(好吧,假设;实际上,x86 指令不能让两个操作数都是地址,一个必须是寄存器,这意味着加载该寄存器将需要更多指令)。使用“寄存器中的布尔结果”方法听起来会更复杂(但我猜不会太多,如果您使用的是允许三向加法的指令集)。

于 2013-09-06T00:27:09.850 回答
1

克里斯的回答是正确的。我只想补充一点,除了不想为了保存比较结果而占用一个大寄存器之外,标志位自然会脱离算术寄存器操作,而专门指定的标志寄存器是它们的好地方。

每当在两个寄存器之间执行加法时,进位位可能会溢出,而减法只是加法的一种变体。

如果数字是二进制补码,则寄存器的高位是符号位。

此外,在每次加法/减法之后,一些特殊的硬件会检测结果是否全为零,这是标志中的另一位。

所有的算术比较都归结为这些的组合,因此它们可以很容易地用于条件分支、长整数数学等。

我最喜欢的基本硬件示例是Harry Porters 的中继计算机。在那里,您可以看到标志寄存器如何真正有助于最小化硬件和简化指令集。

于 2013-09-06T00:49:21.800 回答
-1

那么首先你认为布尔答案和标志之间的区别是什么?真/假与真/假?彼此彼此。高级语言在变量中浪费了一大堆位,因此这些位中的一个基本上保存了布尔结果。现实情况是,只有效率非常低的编译器才会真正生成并浪费寄存器中的所有这些位。经常使用单个或一系列比较和条件分支,并且不消耗 gprs 以实现该高级语言。其他时间取决于布尔值的复杂性,然后肯定会使用 gpr,并且会消耗布尔 alu 操作和其他 gpr 来计算该布尔结果,

典型的方法是在 alu 操作中很容易掉出的四个标志,零、负、进位(又名无符号溢出、又名借位)和有符号溢出。新西兰简历。然后是条件指令的分支清单。您可以在任何 alu 操作上计算条件的效率。即使您不关心该输出,大多数 alu 操作也会烧录寄存器输出。但通常比较指令(减去而不保存结果)对于大多数条件是足够的并且存在。有时如果你很幸运,你会得到一个测试指令(并且没有保存结果)。大多数情况下,您知道进行比较,并且它只是一个比较一个条件分支。有时您可以设置一次标志,然后连续执行两个或多个条件分支,不必重新计算条件标志,它们通过失败的分支保留。那是例外而不是规则。作为免费赠品的标志可能是这是流行方法的原因。

有一个比较指令的洗衣清单是很合理的,如果 a == b 设置标志,如果 a < b 设置标志,如果 a<=b 设置标志等等。然后你只有一个分支,如果标志设置和分支如果标志清除指令在后端。我知道有一个处理器就是这样做的。您不想浪费整个 gpr 来存储那个标志位,但出于各种原因这样做可能是合理的,我正在考虑的那个并没有这样做。

我知道 psr 是 gpr,这意味着它真的不是 gpr,因为它很特殊,但它的使用/访问就像 gpr。因此,您的 alu 输出会在 gpr 中删除这些标志,没有条件分支的清单,而是我认为有两个,如果设置了寄存器 Y 中的位 X 则分支,或者如果未设置寄存器 Y 中的位 X,则分支。(如果设置了 y 中的位 x 可能比 SKIP 更糟糕,或者如果未设置 y 中的位 x 则跳过)并且您必须将一个或多个连续组合起来用于更复杂的分支(如果相等,则分支或更大等)。

我知道有一个没有任何标志,它基本上有一个比较和如果相等则跳转,如果不相等则比较和跳转。基于注册。您必须综合所有其他条件,有符号或无符号溢出,n 位等。同时烧毁 gprs 和指令周期,效率非常低。我可以看到其中的美丽,同时讨厌必须烧录寄存器和如此多的循环所带来的痛苦。我假设目标是避免必须将处理器状态标志从一条指令传送到另一条指令,并让管道处理它(权衡是更多的管道危险,因为合成 alu 标志所涉及的所有数学的中间结果)。

几乎任何处理器都可以使用 gprs 和 alu 操作完成所有布尔工作,从而导致寄存器为零或不为零,然后您可以根据处理器执行最后一条或两条指令以跳转,如果该寄存器是零。如果你不想,你不必在比较时使用分支的洗衣清单。

底线是将单个位结果存储在 gprs 中是一种巨大的浪费。我希望你能理解这是低效的,所以你的论点一直提到使用 gprs 是 IMO 有缺陷的。某种标志之所以有效,仅仅是因为它们不使用 gprs。无论是没有标志(比较并在一条指令中跳转)一个标志,还是多个标志。自己动手与大量比较、少数分支与大量分支和免费比较都有其优点和缺点。我认为四旗方法是最受欢迎的,因为旗是免费赠品,而且我们长期以来一直习惯这样做。

于 2013-09-06T04:48:23.337 回答