BPU_CLEARS.EARLY 描述的事实表明,当 BPU 预测时发生此事件,纠正假设意味着前端有 3 个阶段。假设、预测和计算。我目前的猜测是,当预测被“接受”而不是不被接受时,早期清除正在刷新管道的阶段,这些阶段甚至在来自 L1 BTB 的预测已知的阶段之前。
BTB 集包含 4 条路,每 16 个字节最多有 4 个分支(其中集合中的所有路都使用相同的标签标记,指示特定的 16 字节对齐块)。每种方式都有一个偏移量,表示地址的 4 个 LSB,因此是 16 个字节内的字节位置。每个条目还具有推测位、有效位、pLRU 位、推测本地 BHR、真实本地 BHR,并且每个方式共享集合 BPT (PHT) 作为第二级预测。这可能与 GHR / 推测性 GHR 合金化。
我认为 BPU 为 uop 缓存和指令缓存提供了 64B 的预测块(以前是 32B,在 P6 上是 16B)。对于遗留路由,它需要提供一个 64(或 32/16)字节的预测块,它是一组 64 位掩码,用于标记预测的分支指令、预测方向以及哪个字节是分支目标。该信息将由 L1 BTB 在 64 字节线的获取过程中提供,这样从其中读取的完全没有使用位的 16 字节对齐(IFU 一直是 16B)块将不会被 L1 BTB 获取。指令预解码器(未使用是默认设置,因为在预测块小于行大小的架构上,BPU 可能只为行的 16 或 32B 提供位掩码)。因此,BPU 提供了进行预测的掩码,used/unused mask(在第一个预测块中第一次采取分支之后和第二个预测块中的分支目标之前将字节标记为未使用,其余使用),预测方向掩码; ILD 提供分支指令掩码。预测块中第一个使用的字节隐含地是分支目标或在重新引导或从 uop 缓存 (DSP) 切换到传统管道 (MITE) 之后指令流的开始。预测块中使用的字节组成一个预测窗口。
这是一个 P6 管道。以此为例,在第 3 个周期 (13) 中进行早期清除,此时进行预测(并读取目标和条目类型,因此现在已知无条件分支目标以及条件分支目标及其预测)。使用 16 字节块的集合中的第一个预测采取的分支目标。此时,在它之前的 2 个管道阶段已经被从下一个连续的 16 字节块中读取和开始查找填充,这意味着如果有任何已采取的预测,则需要刷新它们(否则不需要因为下一个连续的 16 字节块已经开始在它之前的管道阶段中查找),留下 2 个周期的间隙或气泡。缓存查找与 BTB 查找同时发生,因此 BTB 和缓存并行 2 管道阶段都必须刷新,而第 3 阶段不需要从缓存或 BTB 中刷新,因为 IP 已打开已确认的路径,并且是当前正在为下一个查找的 IP。事实上,在这个 P6 设计中,只有一个one cycle bubble 用于这个早期清除,因为新的 IP 可以被发送到第一阶段以在时钟的高边沿再次解码一组,而其他阶段正在刷新。
这种流水线比在开始查找下一个 IP 之前等待预测更有益。这意味着每隔一个周期进行一次查找。这将提供每 2 个周期 16 个字节的预测吞吐量,因此为 8B/c。在 P6 流水线场景中,吞吐量在正确假设下为每周期 16 字节,在错误假设下为 8B/c。显然更快。如果我们假设 2/3 的假设是正确的,因为 9 条指令中有 1 条指令是每块 4 条指令的分支,那么这给出了每 ((1*0.666)+2*0.333)) =1.332 个周期的 16B 吞吐量而不是 16B每 2 个周期。
如果这是真的,每个被占用的分支都会导致提前清除。然而,当我在我的 KBL 上使用该事件时,情况并非如此。希望该事件实际上是错误的,因为我的 KBL 不应该支持它,但确实显示了一个随机的低数字,所以希望它在计算其他东西。以下https://gist.github.com/mattgodbolt/4e2cbb1c9aa97e0c5478https://github.com/mattgodbolt/agner/blob/master/tests/branch.py 似乎也不支持这一点。鉴于 900k 指令和 100k 早期清除,如果您使用我对早期清除的定义然后查看他的代码,我看不出您如何获得奇数个早期清除。如果我们假设该 CPU 的窗口为 32B,那么如果您在该宏中的每个分支指令上使用 4 对齐,则每 8 条指令就会清除一次,因为 8 将适合 32B 对齐的窗口。
我不知道为什么Haswell and Ivy Bridge 有这样的早期和晚期清除值,但这些事件 (0xe8) disappear starting with SnB 恰好与 BTB 统一为一个结构时相吻合。看起来后期清除计数器现在正在计算早期清除事件,因为它与 Arrandale CPU 上的早期清除数相同,而早期清除事件现在什么也不计数。我也不确定为什么 Nehalem 有一个 2 周期的气泡用于早期清除,因为 L1 Nehalem BTB 的设计与 P6 BTB 的设计似乎没有太大变化,每组都有 512 个条目,每组 4 路。这可能是因为更高的时钟速度以及更长的 L1i 缓存延迟,它已被分解为更多阶段。
晚清(BPU_CLEARS.LATE)appears to happen at the ILD。在上图中,缓存查找只需要 2 个周期。在更新的处理器中,它显然需要 4 个周期。这允许插入另一个 L2 BTB 并在其中进行查找。 'MRU bypass' 和 'MRU conflicts' 可能只是意味着 MRU BTB 中的一个未命中,或者它也可能意味着 L2 中的预测与 L1 中的预测不同,如果它使用 different prediction algorithm and history file。在不支持任何一个事件的 KBL 上,ILD_STALL.MRU 总是得到 0,但 BPU_CLEARS.LATE 却没有。 3 周期气泡来自第 5 阶段(也是 ILD 阶段)的 BPU,在第 1 阶段的低边缘重新引导管道以及冲洗第 2、3 和 4 阶段(这与引用的 4 个周期的 L1i 延迟一致,因为 L1i 查找发生在第 1-4 阶段的命中 + ITLB 命中)。一旦做出预测,BTB 就会使用做出的预测更新条目的推测性本地 BHR 位。
例如,当 IQ 将预测的掩码与预解码器生成的分支指令掩码进行比较时,就会发生 BACLEAR,然后对于某些指令类型(如相对跳转),它会检查符号位以执行静态分支预测.我想静态预测一旦从预解码器进入 IQ 就会发生,因此立即进入解码器的指令包含静态预测。现在预测的分支在解码分支指令时会产生BACLEAR_FORCE_IQ,因为BAC计算相对条件分支指令的绝对地址时没有目标可以验证,需要验证何时预计拍摄。
解码器的 BAC 在计算指令本身的绝对地址并与它进行比较后,还确保相对分支和直接分支具有正确的分支目标预测,如果没有,则发出 BACLEAR。对于相对跳跃,BAC 中的静态预测使用跳跃位移的符号位来静态预测如果没有进行预测,则如果 BTB 不支持返回条目类型(它不在 P6 上并且不进行预测,而是 BAC 使用 BPU 的 RSB 机制,它是管道中确认返回指令的第一个点)并覆盖在 P6 上进行的所有寄存器间接分支预测(因为没有IBTB),因为它使用了更多分支的统计数据,而不是。 BAC 计算并将相对目标中的绝对目标插入到 uop 中,并将 IP delta 插入到 uop 中,并将下降通过 IP (NLIP) 插入到 BPU 的 BIT 中,该 BIT 可能被标记到 uop,或者更可能是 BIT条目在相应的循环队列上工作,如果没有足够的 BIT 条目,该循环队列将停止,并且将间接目标预测或已知目标插入到 uop 64 位立即字段中。 These fields in the uop are used by the allocator for allocation into the RS/ROB later on。 BAC 还通知 BTB 任何需要从 BTB 释放其条目的虚假预测(非分支指令)。在解码器处,在逻辑的早期检测到分支指令(当前缀被解码并检查指令以查看它是否可以被解码器解码时),并且 BAC 与其余部分并行访问。将已知或以其他方式预测的目标插入 uop 的 BAC 称为converting an auop into a duop。预测被编码到 uop 操作码中。
BAC 可能会指示 BTB 为检测到的分支指令的 IP 推测性地更新其 BTB。如果目标现在已知并且没有对其进行预测(意味着它不在缓存中) - 它仍然是推测性的,因为虽然分支目标是确定的,但它仍然可能在推测性路径上,所以是标有推测位——现在这将立即提供早期指导,特别是对于现在进入管道的无条件分支,但也适用于有条件的分支,具有空白历史,因此将预测下次不会采用,而不必等到退休)。
The IQ 上面包含一个位掩码字段,用于分支预测方向 (BTBP) 和进行分支预测/未进行预测 (BTBH)(以区分 BTBP 中的哪些 0 不被采用,而不是没有进行预测) IQ 行中的 8 个指令字节中的每一个以及分支指令的目标,这意味着每个 IQ 行只能有一个分支并且它结束了该行。该图没有显示由预解码器生成的分支指令掩码,该掩码显示了哪些指令实际上是分支,以便 IQ 知道它需要对哪些未做出的预测进行预测(以及哪些根本不是分支指令)。
IQ 是一个连续的指令字节块,ILD 填充 8 位位掩码,这些掩码标识每个宏指令的第一个操作码字节 (OpM) 和指令结束字节 (EBM),因为它将圆形字节包装到 IQ 中。它可能还提供指示它是复杂指令还是简单指令的位(正如许多 AMD 专利中的“预解码位”所建议的那样)。这些标记之间的间隙是以下指令的隐含前缀字节。我认为 IQ 的设计使其在 IDQ/ROB 中发出的微指令很少会超过 IQ,因此 IQ 中的头指针开始覆盖仍然标记在 IDQ 中等待分配的宏指令,当它确实如此时,有一个停顿,所以 IDQ 标记返回分配器访问的 IQ。我认为 ROB 也使用这个 uop 标签。如果 16 字节 * 40 个条目,则 SnB 上的 IQ 在最坏情况下包含 40 个宏操作,在平均情况下包含 320 个,在最佳情况下包含 640 个。这些产生的微指令的数量会更多,所以它很少会超过,当它超过时,我猜它会停止解码,直到更多的指令退出。尾指针包含ILD最近分配的标签,头指针包含下一条等待退出的宏指令指令,读指针是解码器要消耗的当前标签(向尾指针移动)。虽然,现在这变得很困难,因为路径中的一些(如果不是大多数)微指令来自自 SnB 以来的微指令缓存。如果 uop 没有用 IQ 条目标记(并且 IQ 中的字段直接插入到 uops 中),则可能允许 IQ 超过后端,这将被检测到,并且管道将从开始。
当分配器将分支微操作的物理目标 (Pdst) 分配到 ROB 中时,分配器将 Pdst 条目号提供给 BPU。 BPU 将此插入到由 BAC 分配的正确 BIT 条目中(这可能位于尚未分配 Pdst 的活动 BIT 条目的循环队列的头部)。分配器还从 uop 中提取字段并将数据分配到 RS。
RS 包含一个字段,该字段指示指令是分配器填充的 MSROM uop 还是常规 uop。分配器还将确认的绝对目标或预测的绝对目标插入到立即数据中,并作为源,重命名标志寄存器(or just a flag bit),在间接分支的情况下,还有包含地址的重命名寄存器作为另一个来源。 PRF 方案中的 Pdst 将是 ROB 条目,作为 Pdst 将是退休宏 RIP 或微 IP 寄存器。 JEU 将目标或失败写入该寄存器(如果预测正确,则可能不需要)。
当保留站向位于整数执行单元中的跳转执行单元分派分支微操作时,保留站将相应分支微操作的Pdst条目通知BTB。作为响应,BTB 访问 BIT 中的分支指令的相应条目,并读取下降直通 IP (NLIP),按 RS 中的 IP 增量递减,并解码以指向分支条目将是的集合更新/分配。
然后将重命名的标志寄存器源Pdst的结果与调度器中的操作码中的预测进行比较,以确定是否采用/不采用分支,此外,如果分支是间接的,则将BIT中的预测目标与源 Pdst 中的地址(在调度和调度之前计算并在 RS 中可用)进行比较,现在知道是否做出了正确的预测以及目标是否正确。
JEU 将异常代码传播到 ROB 并刷新管道(JEClear - 在分配阶段之前刷新整个管道,并暂停分配器)并在管道开始时使用重定向下一个 IP 逻辑失败(在 BIT 中)/适当的目标 IP(以及如果是微分支错误预测的微序列器;指向流水线开头的 RIP 在整个 MSROM 过程中将是相同的)。投机条目被解除分配,真正的 BHR 被复制到投机 BHR。如果 PRF 方案中存在 BOB,则 BOB 会为每个分支指令以及发生错误预测时拍摄 RAT 状态的快照。 JEU 将 RAT 状态回滚到该快照,并且分配器可以立即继续(这对于微分支错误预测特别有用,因为它更靠近分配器,因此气泡不会被管道很好地隐藏),而不是停止分配器并且必须等到退休才能知道退休RAT状态并使用它来恢复RAT然后清除ROB(ROClear,这会使分配器失速)。使用 BOB,分配器可以在陈旧的微指令继续执行时开始发出新指令,并且当分支准备退出时,ROClear 仅清除退出的错误预测和新微指令之间的微指令。如果是一个MSROM uop,因为它可能已经完成了,流水线的开始还是需要再次重定向到MSROM uop,但是这次会从重定向的microip开始(内联指令就是这种情况(而且它可能能够从 IQ 中重放它)。如果在 MSROM 异常中发生错误预测,则不需要重新引导管道,只需直接重定向即可,因为它已经接管了 IDQ 问题,直到程序结束-- 对于内联问题,问题可能已经结束。
响应 ROB 中的分支异常向量的 ROClear 实际上发生在 uop 退役时的第二个退役阶段 RET2(这实际上是典型退役管道的 3 个阶段中的第 3 个)。当 EOM uop(宏指令结束)标记退出时,宏指令仅退出,异常仅触发,宏指令 RIP 仅更新(使用新目标或增加 ROB 中的 IP 增量),即使非 EOM 指令写入它,它不像其他寄存器那样立即写入 RRF——无论如何,分支微指令很可能是解码器处理的典型分支宏指令中的最终微指令。如果这是一个 MSROM 过程中的微分支,它不会更新 BTB;它在退出时更新 uIP,并且 RIP 直到过程结束才更新。
如果在 MSROM 宏操作执行期间发生一般的非错误预测异常(即需要处理程序),一旦它被处理,导致异常的微 IP 由处理程序恢复到 uIP 寄存器(在事件调用时传递给处理程序),以及触发异常的宏指令的当前RIP,当异常处理结束时,在该RIP+uIP处恢复指令取指:重新取指并重新尝试宏指令在 MSROM 中,它从向它发送信号的 uIP 开始。复杂的非 MSROM 宏指令中先前 uop 的 RRF 写入(或 PRF 方案上的退休 RAT 更新)可能发生在 EOM uop 退休之前的周期,这意味着restart can happen at a certain uop within a regular complex macroop and not just a MSROM macroop,在这种情况下,指令流在 RIP 的 BPU 处重启,复杂解码器配置为valid / invalid bits on the PLA cuop outputs。用于配置复杂解码器有效位的这条常规复杂指令的 uIP 是一个介于 0-3 之间的值,我认为 ROB 在每个 EOM 设置为 0,并为每个退休的微操作递增,因此非 MSROM 复杂指令可以被寻址,对于 MSROM 复杂指令,MSROM 例程包含一个 uop,它告诉 ROB 该指令的 uIP。然而,体系结构 RIP 寄存器,仅当 EOM uop 退出时才由 IP delta 更新,但仍指向当前宏操作,因为 EOM uop 未能退出),这只发生在异常but not hardware interrupts, which can't interrupt MSROM procedures or complex instruction mid retirement (software interrupts are similar and trigger at the EOM -- the trap MSROM handler performs a macrojump to the RIP of the software trap handler once it has finished)。
BTB 读取和标签比较发生在 RET1 中,而分支单元写回结果,然后在下一个周期,可能也在 RET1 期间(或者这可能在 RET2 中完成),比较集合中的标签并然后,如果有命中,则计算新的历史 BHR;如果有未命中,则需要在该 IP 上为该目标分配一个条目。只有当 uop 按顺序(在 RET2 中)退出时,才能将结果放入真实历史记录中,并使用分支预测算法来更新需要更新的模式表。如果分支需要分配,则使用替换策略来决定分配分支的方式。如果命中,则目标对于所有直接和相关分支都已经正确,因此在没有 IBTB 的情况下不必进行比较。推测位现在从条目中删除(如果存在)。最后,在下一个周期,分支被 BTB 写控制逻辑写入 BTB 缓存中。 BTB 查找的第一部分可能能够在整个 RET1 中继续进行,然后可能会停止 BTB 写入流水线,直到 RET2 等待写入 BTB 的 ROB 条目的阶段退出时,否则,查找可以解耦并且第一部分完成并将数据写入例如 BIT,并且在 RET2 处,即将退休的相应条目仅写回 BTB(这意味着再次解码集合,再次比较标签,然后写入条目,所以可能不会)
如果 P6 有一个 uop 缓存,则管道将类似于:
- 1H:选择IP
- 1L:BTB 集解码 + 缓存集解码 (physical/virtual index) + ITLB 查找 + uop 缓存集解码
- 2H:缓存读取 + BTB 读取 + uop 缓存读取
- 2L:缓存标签比较+BTB标签比较+uop缓存标签比较;如果 uop 缓存命中,则停止直到 uop 缓存可以发出,然后时钟门传统解码管道
- 3H:预测,如果采取,冲洗 3H,2L,2H,1L
- 如果采用 3L,则以新 IP 开始 1L 以解码新集并继续执行分支指令所在的当前 16 字节块到 4L
至于 uop 缓存,因为它已经过了 BAC 的阶段,所以永远不会出现虚假分支或无条件分支的错误预测或非间接分支的错误目标。 uop 缓存将使用 BPU 中的已用/未使用掩码为从这些字节开始的指令发出 uops,并将使用预测方向掩码将宏分支 uop 更改为预测未采用/预测采用宏分支 uop(T/NT预测被插入到 uop 本身)。如果它被预测为被占用,那么它将停止为那个 64B 对齐的块(再次曾经是 32B,以前是 16B)发出微指令,并等待管道中紧随其后的下一个窗口。 uop 缓存将知道什么是 uop 是分支,并且可能静态预测不采取所有非预测,或者可能具有更高级的静态预测。来自 IBTB 的间接目标预测被插入到 uop 立即数字段中,然后如果该分支也被预测采用,它将等待下一个 BPU 预测块。我会想象 uop 缓存会创建 BIT 条目并更新 BTB 中的预测,以确保 uop 缓存和 MITE(旧版解码)uop 以正确的顺序更新历史记录。