MSROM 程序中的条件跳转指令?

Conditional jump instructions in MSROM procedures?

这与 this 问题有关

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

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

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

微代码分支显然是特殊的。

根据 Andy Glew 对原始 P6 () 的描述,Intel 的 P6 和 SnB 系列不支持微码分支的动态预测。鉴于 SnB 系列 rep-string 指令的相似性能,我假设这个 PPro 事实甚至适用于最新的 Skylake / CoffeeLake CPU1.

但是微码分支预测错误会有惩罚,所以它们是静态(?)预测的。 (这就是为什么 rep movsb ECX 中 low/medium/high 计数的启动成本以 5 个周期递增,以及对齐与未对齐的原因。)


一条微码指令在 uop 高速缓存中占据一整行。 当它到达 IDQ 的前端时,它接管 issue/rename 阶段,直到它完成发出微码 uops。(另请参阅 以获取更多详细信息,以及一些来自 perf 事件描述的证据,如 idq.dsb_uops 表明 IDQ 可以接受来自 uop 缓存的新 uops issue/rename 阶段正在从微码序列器读取。 )

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

我不知道当 issue/rename 切换到从 MS-ROM 而不是 IDQ 读取微指令时会发生什么的细节。

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

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

运行 一些关于 rep movsb 附近可能有多少 OoO exec 的实验会很有趣,例如有两条相关的 imul 指令链,看看它是否(部分)。我们希望不会,但要实现 ILP,稍后的 imul uops 必须在不等待后端耗尽的情况下发出。

我在 Skylake (i7-6700k) 上做了一些实验。初步结果:95 字节及以下的副本大小便宜且被 IMUL 链的延迟隐藏,但它们基本上完全重叠。 96 字节或更多字节的复制大小会耗尽 RS,序列化两个 IMUL 链。无论是 rep movsb 与 RCX=95 还是 96 或 rep movsd RCX=23 vs. 24。有关我的发现的更多摘要,请参阅评论中的讨论;如果我有时间,我会 post 更多详细信息。

"drains the RS" 行为的测量结果是 rs_events.empty_end:u 甚至变为每 rep movsb 1 个而不是 ~0.003。 other_assists.any:u 是零,所以它不是 "assist",或者至少不算作一个。

如果微码分支不支持通过 BoB 的快速恢复,也许涉及的任何 uop 仅在退休时检测到错误预测? 96 字节阈值可能是某些替代策略的界限。 RCX=0 也会耗尽 RS,大概是因为它也是一个特例。

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

Intel's 1994 Fast Strings patent描述了P6中的实现。它没有 IDQ(因此现代 CPU 在阶段之间有缓冲区和 uop 缓存会有一些变化是有道理的),但他们描述的避免分支的机制很简洁,可能仍用于现代 ERMSB: first n copy iterations 是后端的 predicated uops,所以它们可以无条件地发出。还有一个使后端将其 ECX 值发送到微代码定序器的 uop,微代码定序器使用该微代码定序器在此之后准确地输入正确数量的额外复制迭代。只是复制 uops(可能更新 ESI、EDI 和 ECX,或者可能只在中断或异常时这样做),而不是微代码分支 uops。

这个初始 n uops 与读取 RCX 后输入更多可能是我看到的 96 字节阈值;每个 rep movsb(从 4 到 5)有一个额外的 idq.ms_switches:u

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

The execution units can issue an assist or signal a fault by associating an event code with the result of a micro- op. When the micro-op is committed (§ 2.10), the event code causes the out-of-order scheduler to squash all the micro-ops that are in-flight in the ROB. The event code is forwarded to the microcode sequencer, which reads the micro-ops in the corresponding event handler"

这个和P6专利的区别在于,这个辅助请求可以在后面指令的一些非微码微指令已经发出之后发生,预期微指令只用第一批微指令就完成了.或者,如果它不是来自微代码的批次中的最后一个 uop,它可以像分支一样用于选择不同的策略。

但这就是它必须刷新 ROB 的原因。

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


Usually, when a branch mispredicts as being taken then when the instruction retires,

英特尔因为 Nehalem 已经 "fast recovery",当一个错误预测的分支 执行 时开始恢复,而不是等待它到达像例外一样退休。

这就是在通常的 ROB 退役状态之上有一个 Branch-Order-Buffer 的意义所在,它可以让您在任何其他类型的意外事件变得非推测性时回滚。 ()


脚注 1:IceLake 应该具有 "fast short rep" 功能,这可能是处理 rep 字符串的不同机制,而不是更改微码。例如也许像 Andy 这样的 HW 状态机提到他希望他首先设计。

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

英特尔已为微码的一些非常类似于汇编的功能申请了专利,其中包括:

从 L1、L2 或 L3 执行(!!!!!!!!!!!!!!!!!!!!!!!!)。哎呀,他们申请了从大容量存储 加载 "big" 微码更新 到 L3 中然后从那里更新的专利...... - 请注意 "patented" 和 "implemented" 是不同的,我不知道他们目前是否实施了除从 L1 执行以外的任何其他措施。

MCU 包中的 Opcode 和 Ucode(!) 部分(统一微处理器更新)——我们称之为 "microcode update" 但实际上 has/can 里面有各种各样的东西,包括 PMU 固件更新, MCROM 补丁, uncore 参数更改, PWC 固件等, 执行 before/after 处理器 firmware/ucode 更新程序.

Ucode 上的类似子程序的行为包括参数。条件分支,或者至少是条件循环,他们已经有一段时间了。

微码的压缩和解压缩(未知是否可以直接从压缩状态"run",但专利似乎暗示它至少会用于优化MCU封装)。

和 WRMSR/RDMSR 确实更像是 Ucode 中的 RPC,而不是现在的任何其他东西,我想当他们发现他们需要一个新的 MSR 时,真的 很有帮助,或者对架构 MSR 行为进行复杂的更改(例如 LAPIC 基址寄存器,它必须 "gatekeeped" 才能解决几年前成为新闻的 LAPIC 内存坑 SMM 安全漏洞)。

因此,只需将其视为实现 "public" 指令架构的硬件加速图灵完备 RISC 机器即可。

我现在所知道的是,分支是由 MSROM 静态预测的,它在下一个微代码行的下一个 IP 逻辑中使用该预测。这些预测可能已经在存储在 MSROM 中的 uops 中提供。

对于更小和更频繁的 MSROM 例程,复杂的解码器可以在将控制权传递给 MSROM 以完成解码之前发出 1–4 微指令。否则,它会延迟将控制权交给 MSROM。

In the preferred embodiment, some of the more frequently-used macroinstructions are decoded by the XLAT PLAs 510-516 into one, two, three, or four of the first Cuops in the micro-operation sequence, which provides high performance at the cost of additional minterms in the XLAT PLAs 510-516. Alternately, for some less frequently-used macroinstructions, the four XLAT PLAs 510-516 issue no Cuops, but simply allow the MS unit 534 to issue all Cuops. This second alternative has a disadvantage of lower performance (i.e., a loss of at least one clock cycle), but can save minterms (entries) in the XLAT PLAs 510-516, which is a design trade-off that reduces die space at the expense of lower performance. This trade-off can be useful for less frequently used instructions or for long microcode flows where the significance of one additional clock is lessened.

The opcodes from the macroinstruction 502 are supplied to the entry point PLA 530 that decodes the opcodes to generate an entry point address into microcode ROM. The generated entry point address is supplied to the MS unit 534 that, responsive to the entry point, generates a series of Cuops. The MS unit 534 includes a microcode ROM ("UROM") that includes microcode routines to supply UROM Cuops for long instructions flows, which in some examples may require over a hundred UROM Cuops. The UROM also includes assist handling routines and other microcode.

剩下的在这里回答: