首页 > 解决方案 > 现代 CPU 是否需要花费大量资源来保持标志更新?

问题描述

据我了解,在现代无序 CPU 上,最昂贵的事情之一就是状态,因为必须在多个版本中跟踪该状态,在许多指令中保持最新等。

一些指令集(如 x86 和 ARM)广泛使用标志,这些标志是在成本模型与今天不同时引入的,并且标志只需要几个逻辑门。诸如每条算术指令设置标志以检测零,进位和溢出之类的东西。

这些在现代乱序实施中保持更新的成本是否特别昂贵?这样,例如 ADD 指令会更新进位标志,并且必须对其进行跟踪,因为尽管它可能永远不会被使用,但有可能其他指令可以在 N 条指令之后使用它,而 N 没有固定的上限?

在没有这些标志的 MIPS 等指令集架构上,整数运算(如加法和减法)是否更便宜?

标签: performanceassemblycpu-architecturemicro-optimizationeflags

解决方案


这方面的各个方面都不是很为人所知,所以我将尝试将肯定已知的事情与合理的猜测和猜想区分开来。

一种方法是使用操作生成的标志来扩展(物理)整数寄存器(无论它们采用物理寄存器文件的形式 [例如 P4 和 SandyBridge+] 还是 ROB 的结果 [例如 P3])这也产生了相关的整数结果。这只是关于算术标志(有时是 AFLAGS,不要与 EFLAGS 混淆),但我不认为“奇怪的标志”是这个问题的重点。有趣的是,有一项专利[1]暗示存储的不仅仅是 6 个 AFLAGS 本身,还会在其中放置一些“组合标志”,但谁知道这是否真的完成了 - 大多数消息来源说寄存器扩展了 6 位,但是我们(公众)真的不知道知道。例如,在本专利[2]中描述了将整数结果和相关标志集中在一起,这主要是关于防止标志可能意外不再由任何物理寄存器支持的特定情况。除了这些怪癖之外,在正常操作期间,它具有只需要为算术运算分配 1 个寄存器而不是单独的 main-result 和 flags-result 的良好效果,因此重命名通常不会因为存在而变得更糟标志。此外,寄存器别名表至少需要一个插槽来跟踪哪个整数寄存器包含最新标志,或者一个单独的标志重命名状态缓冲区跟踪最新的推测标志状态([2]建议英特尔选择将它们分开,这可能会简化主要的 RAT,但它们不会详细说明)。可以使用更多的插槽[3]来有效地执行只更新标志子集的指令(NetBurst™ 著名地缺乏这一点,导致现在过时的建议优先addinc)。类似地,非推测性架构状态(它是否会成为退休寄存器文件的一部分或是否是独立但相似的又不清楚)需要至少一个这样的插槽。

一个单独的问题是首先计算标志。[1]建议将标志生成与主 ALU 分开来简化设计。目前尚不清楚它们将被分离到何种程度:无论如何,主 ALU 必须计算 Adjust 和 Sign 标志,并且有一个加法器输出一个执行顶部的要求并不多(比从无到有重新计算它要少)。溢出标志只需要一个额外的 XOR 门来将最高位的进位与最高位的进位结合起来。零标志和奇偶标志不是免费的(它们取决于结果,而不是计算的结果),如果存在部分分离,则将它们分开计算是有意义的。也许它真的是分开的。在 NetBurst™ 中,标志计算需要额外的半个周期(ALU 是双泵和交错的)[4],但这是否意味着所有标志都是单独计算的,或者是它们的子集(或者甚至是作为[1]的超集)提示)不清楚 - 标志结果被视为单片,因此延迟测试无法区分标志是在第三个半周期由标志单元计算还是由 ALU 交给标志单元。在任何情况下,典型的 ALU 操作可以背靠背执行,即使依赖(意味着第一个操作的高半部分和第二个操作的低半部分并行运行),标志的延迟计算没有挡路。正如您所期望的那样,ADC并且SBB在 NetBurst 上效率不高,但也可能有其他原因(出于某种原因,涉及到很多微操作)。

总的来说,我会得出结论,算术标志的存在会花费大量工程资源来防止它们对性能产生重大影响,但这种努力也是有效的,因此避免了重大影响。


推荐阅读