在大多数指令集中,分支指令是根据状态寄存器上的标志执行的。
在更高级语言中,布尔值是一种数据类型,可以通过评估表达式(通常为==,!=,<,>,> =,< =和其他变体)创建并存储在变量
为什么程序集选择分支状态标志而不是将指令存储在寄存器中?
考虑到允许将测试结果存储在变量中的语言数量,我认为指令集会随之发展,从而可能创建更高效的程序。
这种将测试结果存储到状态寄存器中然后在标志上分支仅仅是传统的惯例还是有理由建议基于标志的方法比能够直接存储和测试通用寄存器更有效? / p>
答案 0 :(得分:3)
如果您想“将布尔结果存储在寄存器中”,则需要单独指示<
,<=
,>
,>=
等。您还需要一组用于签名比较,另一组用于无符号比较。
在x86指令集中,有一条指令用于所有这些,cmp
(设置一组标志),然后使用适当的jxx
或setxx
指令查看您感兴趣的标志(例如,对于条件跳转,您使用jb
,jbe
/ jna
,ja
,jae
/ {{1对于无符号(“低于”/“高于”),jnb
,jl
/ jle
,jng
,jg
/ jge
签名(“少”/“更大”))。
这种方法的另一个特点是,您可以在执行变异操作后实际检查标记,例如进行添加或借用减法。示例(假设jnl
指向一个128位数字,该数字被添加到esi
指向的另一个128位数量中:
edi
这只是5个指令(好吧,假设;实际上,x86指令不能将两个操作数都作为地址,一个必须是寄存器,这意味着加载该寄存器将需要更多指令)。使用“寄存器中的布尔结果”方法听起来更复杂(但我猜的不是很多,如果你使用的是允许三向加法的指令集)。
答案 1 :(得分:1)
克里斯的回答是正确的。我只想补充一点,除了不想为了保持比较结果而占用大寄存器之外,标志位自然地落在算术寄存器操作之外,并且特别指定的标志寄存器对它们来说是个好地方。
每当在两个寄存器之间执行加法运算时,进位位可能会溢出,而减法只是加法的变化。
如果数字是二进制补码,则寄存器的高位是符号位。
此外,在每次加/减之后,某些特殊硬件会检测结果是否全为零,这是标志中的另一个位。
所有算术比较归结为这些的组合,因此它们可以很容易地用于条件分支,长整数数学等。
我最喜欢的基础硬件示例是Harry Porters's Relay Computer。在那里,您可以看到标志寄存器如何真正有助于最小化硬件并简化指令集。
答案 2 :(得分:-1)
首先,您认为布尔答案和标志之间的区别是什么?真/假与真/假?彼此彼此。更高级别的语言在变量中浪费了大量的位,因此基本上其中一个位保存了布尔结果。实际情况是,只有非常低效的编译器实际生成并浪费寄存器中的所有这些位。通常使用单个或一系列比较和条件分支,并且不消耗gprs以实现该高级语言。其他时候取决于布尔值的复杂性,然后肯定使用gpr并且使用布尔alu操作和其他gprs来计算该布尔结果,然后如果为零则进行最终比较,如果为零则进行分支以完成任务(如果你不打算比较它并根据比较做一些事情,为什么你会计算一个布尔值?否则优化器会删除所有代码。
典型的方法是四个标志,这些标志通常不属于alu操作,零,负,进位(a.k.a。无符号溢出,a.k.a。借用)和有符号溢出。 NZCV。然后是条件指令上的分支清单。您可以在任何alu操作上计算条件的效率。即使您不关心该输出,大多数alu操作也会刻录寄存器输出。但是,对于大多数条件而言,通常比较指令(减去而不保存结果)就足够了。有时如果你很幸运,你会得到一个测试指令(AND而不保存结果)。大多数情况下,你知道比较进入,它只是一个比较一个条件分支。有时您可以设置一次标志,然后连续执行两个或多个条件分支,而不必重新计算条件标志,它们通过失败的分支保留。这是例外而不是规则。作为免费赠品的旗帜可能是这种流行方法的原因。
拥有比较指令的清单是合理的,如果a == b则设置标志,如果a = b则设置标志。 b,如果a&lt; = 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。无一个标志(比较并跳转一条指令)一个标志或多个标志。自己动手做对比很多比较和很少的分支与很多分支和免费比较都有其优点和缺点。我认为四旗的方法是最受欢迎的,因为旗帜是一个alu免费赠品,而且,因为我们习惯性地这样做了很长时间。