据我了解,在现代无序 CPU 上,最昂贵的东西之一是状态,因为必须在多个版本中跟踪该状态,在许多指令中保持最新状态等。
一些指令集(例如 x86 和 ARM)大量使用标志,这些标志是在成本模型不是现在的样子时引入的,并且标志只花费几个逻辑门。比如每个算术指令都会设置标志来检测零、进位和溢出。
在现代无序实施中保持更新是否特别昂贵?例如ADD 指令更新进位标志,必须跟踪这一点,因为尽管它会probably永远不会被使用,它是possible其他指令可以在 N 条指令之后使用它,而 N 没有固定的上限?
在没有这些标志的 MIPS 等指令集架构上,加法和减法等整数运算是否更便宜?
这件事的各个方面都不是很为公众所知,所以我会尝试将明确已知的事情与合理的猜测和猜想分开。
一种方法是使用操作生成的标志来扩展(物理)整数寄存器(无论它们采用物理寄存器文件的形式[例如P4和SandyBridge+]还是ROB结果[例如P3]的形式)这也产生了相关的整数结果。这只是关于算术标志(有时是 AFLAGS,不要与 EFLAGS 混淆),但我不认为“奇怪的标志”是这个问题的焦点。有趣的是,有一项专利[1]这暗示存储的不仅仅是 6 个 AFLAGS 本身,还在那里放置了一些“组合标志”,但谁知道这是否真的完成了 - 大多数消息来源都说寄存器扩展了 6 位,但据我所知,我们(公众)不really知道。例如,本专利描述了将整数结果和相关标志集中在一起[2],这主要是为了防止出现某种情况,即标志可能意外地不再受到任何物理寄存器的支持。除了这些怪癖之外,在正常操作期间,它的一个很好的效果是只需要为算术运算分配 1 个寄存器,而不是单独的主结果和标志结果,因此重命名通常不会因为存在旗帜。此外,寄存器别名表至少需要一个槽来跟踪哪个整数寄存器包含最新的标志,或者一个单独的标志重命名状态缓冲区跟踪最新的推测标志状态([2]建议英特尔选择将它们分开,这可能会简化主要的 RAT,但他们不会详细讨论这些细节)。可以使用更多插槽[3]有效地实现仅更新标志子集的指令(NetBurst™众所周知缺乏这一点,导致现在过时的建议值得青睐add over inc)。同样,非推测的架构状态(无论是part of退休寄存器文件或再次分离但相似尚不清楚)需要至少一个这样的插槽。
一个单独的问题是首先计算标志。[1]建议将标志生成与主 ALU 分开以简化设计。目前尚不清楚它们将被分离到何种程度:无论如何,主 ALU 必须计算调整和符号标志,并且让加法器输出进位顶部并没有什么要求(比从无到有重新计算要少)。溢出标志仅需要一个额外的异或门来将最高位的进位与最高位的进位组合起来。不过,零标志和奇偶校验标志并不是免费的(它们依赖于结果,不在计算结果的一部分),如果存在部分分离,那么单独计算它们是有意义的。也许一切真的都是分开的。在 NetBurst™ 中,标志计算需要额外的半周期(ALU 是双泵浦且交错的)[4],但这是否意味着all标志是单独计算的,或者是它们的子集(甚至是超集,如[1]提示)尚不清楚 - 标志结果被视为整体,因此延迟测试无法区分标志是由标志单元在第三个半周期中计算的还是仅由 ALU 交给标志单元。在任何情况下,典型的 ALU 操作都可以连续执行,即使是相关的(意味着第一个操作的高半部分和第二个操作的低半部分并行运行),标志的延迟计算也不会执行。阻碍这一点。正如你所预料的那样,ADC
and SBB
在 NetBurst 上效率不高,但也可能有其他原因(由于某种原因涉及大量 µop)。
总的来说,我得出的结论是,算术标志的存在花费了大量的工程资源来防止它们对性能产生重大影响,但这种努力也是有效的,因此避免了重大影响。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)