首页 > 解决方案 > MSROM 程序中的条件跳转指令?

问题描述

这与这个问题有关

考虑到这一点,在现代英特尔 CPU 上,SEC 阶段是在微码中实现的,这意味着将进行检查,使用烧录的密钥来验证 PEI ACM 上的签名。如果不匹配,则需要做某事,如果匹配,则需要做其他事情。鉴于这是作为 MSROM 过程实现的,因此必须有一种分支方式,但鉴于 MSROM 指令没有 RIP。

通常,当一个分支错误预测为被采用时,当指令退出时,ROB 将检查异常代码,因此将指令长度添加到 ROB 行的 RIP 或仅使用下一个 ROB 条目的 IP,这将导致前端在分支预测更新中被重新引导到该地址。对于 BOB,此功能现在已借给跳转执行单元。显然,这不会发生在 MSROM 例程中,因为前端与它无关。

我的想法是,有一个特定的跳转指令,只有 MSROM 例程可以发出,它跳转到 MSROM 中的不同位置,并且可以配置为始终预测 MSROM 分支指令不会被执行,并且当分支执行单元遇到这个指令和分支被采用,它产生一个异常代码,并可能将特殊跳转目标连接到它,并且在退出时发生异常。或者,执行单元可以处理它并且它可以使用 BOB,但我的印象是 BOB 由分支指令 RIP 索引,然后还有一个事实是生成 MSROM 代码的异常通常在退休时处理;分支错误预测不需要我不认为的 MSROM,而是所有操作都是在内部执行的。

标签: x86intelcpu-architecturebranch-predictionmicro-architecture

解决方案


微码分支显然很特别。

英特尔的 P6 和 SnB 系列不支持微码分支的动态预测,根据 Andy Glew 对原始 P6 的描述(REP 做了什么设置?)。鉴于 SnB-family 字符串rep指令的类似性能,我假设这个 PPro 事实甚至适用于最新的 Skylake / CoffeeLake CPU 1

但是微码分支错误预测会受到惩罚,因此它们是静态(?)预测的。(这就是为什么rep movsb对于 ECX 中的低/中/高计数,启动成本以 5 个周期为增量,并且对齐与未对齐。)


微编码指令在 uop 高速缓存中占用一整行。 当它到达 IDQ 的前面时,它会接管发布/重命名阶段,直到完成发布微码 uops。 (另请参阅如何在指令周期内执行微代码?有关更多详细信息,以及来自 perf 事件描述idq.dsb_uops的一些证据表明 IDQ 可以从 uop 缓存中接受新的 uop ,而问题/重命名阶段正在从微码序列器读取.)

对于rep-string 指令,我认为循环的每次迭代都必须通过前端实际发出,而不仅仅是后端循环并重用这些微指令。因此,这涉及来自 OoO 后端的反馈,以了解指令何时完成执行。

我不知道当问题/重命名切换到从 MS-ROM 而不是 IDQ 读取 uops 时会发生什么的详细信息。

即使每个 uop 都没有自己的 RIP(作为单个微编码指令的一部分),我猜分支错误预测检测机制的工作方式与普通分支类似。

rep movs根据具体情况(小与大、对齐等),某些 CPU 上的设置时间似乎以 5 个周期为步长。如果这些来自微码分支错误预测,那似乎意味着错误预测惩罚是固定数量的周期,除非这只是rep movs. 可能是因为 OoO 后端跟不上前端?并且从 MS-ROM 读取比从 uop 缓存读取更能缩短路径,从而使未命中惩罚如此之低。

对 OoO exec 可能有多少进行一些实验会很有趣rep movsb,例如使用两条依赖指令链imul,看看它是否(部分)将它们序列化为lfence. 我们希望不会,但是为了实现 ILP,以后的imul微指令必须在不等待后端耗尽的情况下发布。

我在 Skylake (i7-6700k) 上做了一些实验。初步结果:95 字节及以下的副本大小便宜且被 IMUL 链的延迟隐藏,但它们基本上完全重叠。 96 字节或更大的复制大小会耗尽 RS,序列化两个 IMUL 链。 不管是rep movsbRCX=95 vs. 96 还是rep movsdRCX=23 vs. 24 如果我有时间我会发布更多细节。

“消耗 RS”行为的测量结果rs_events.empty_end:u甚至变为 1 perrep movsb而不是 ~0.003。 other_assists.any:u是零,所以它不是“助攻”,或者至少不算作一。

如果微码分支不支持通过 BoB 进行快速恢复,那么无论涉及什么 uop 都可能只会在达到退休时检测到错误预测?96 字节阈值可能是某些替代策略的截止值。RCX=0 也会耗尽 RS,大概是因为它也是一种特殊情况。

测试起来会很有趣rep scas(它不支持快速字符串,只是缓慢而愚蠢的微代码。)

英特尔 1994 年的 Fast Strings 专利描述了 P6 中的实现。它没有 IDQ(因此现代 CPU 在阶段之间有缓冲区和 uop 缓存会有一些变化是有道理的),但他们描述的避免分支的机制很简洁,可能仍然用于现代 ERMSB:第一个n副本迭代是后端的谓词微指令,因此可以无条件地发出它们。还有一个 uop 会导致后端将其 ECX 值发送到微码定序器,然后微码定序器使用它来提供正确数量的额外复制迭代。只是复制微指令(可能是 ESI、EDI 和 ECX 的更新,或者可能只在中断或异常时这样做),而不是微码分支微指令。

在阅读 RCX 后,最初n的 uops 与输入更多可能是我看到的 96 字节阈值;它带有额外的idq.ms_switches:urep movsb(从 4 到 5)。

https://eprint.iacr.org/2016/086.pdf建议微码在某些情况下可以触发辅助,这可能是较大副本大小的现代机制,并且可以解释耗尽 RS(显然是 ROB),因为它仅在 uop提交(退休)时触发,因此它就像一个没有快速恢复的分支。

执行单元可以通过将事件代码与微操作的结果相关联来发出帮助或发出故障信号。当微操作被提交(第 2.10 节)时,事件代码会导致乱序调度程序压缩 ROB 中所有正在运行的微操作。事件代码被转发到微码定序器,它读取相应事件处理程序中的微操作“

该专利与 P6 专利之间的区别在于,此辅助请求可能发生在来自后续指令的一些非微码微指令已经发出之后,因为预计微码指令仅在第一批微指令中完成。或者,如果它不是来自微码的批次中的最后一个微指令,它可以用作选择不同策略的分支。

但这就是为什么它必须刷新 ROB。

我对 P6 专利的印象是,对 MS 的反馈发生在稍后的指令发出微指令之前,如果需要,及时发布更多的微指令。如果我错了,那么也许它已经是 2016 年论文中描述的相同机制。


通常,当一个分支错误预测为被采用时,当指令退出时,

自从 Nehalem 以来,英特尔已经“快速恢复”,当错误预测的分支执行时开始恢复,而不是像例外那样等待它达到退休。

这就是在通常的 ROB 退休状态之上拥有一个分支顺序缓冲区的要点,它允许您在任何其他类型的意外事件变为非推测性时回滚。(当 Skylake CPU 错误预测分支时,究竟会发生什么?


脚注 1:IceLake 应该具有“快速短代表”功能,这可能是处理rep字符串的不同机制,而不是对微码的更改。例如,也许像安迪这样的硬件状态机提到他希望他首先设计。

我没有任何关于性能特征的信息,但是一旦我们知道了一些东西,我们就可以对新的实现做出一些猜测。


推荐阅读