4.15 加载使用冒险

定义

加载使用冒险(Load-Use Hazard)是指一条加载指令(mrmovq、popq)的结果被紧随其后的指令立即使用,而后一条指令在译码阶段就需要该结果。这是转发无法完全解决的场景。

为什么转发无法解决

加载指令的执行流程:

$mrmovq (%rdi), %rax    →$取指 $→$译码 $→$执行(地址计算$) →$访存(读内存$) →$写回
                                                           ↑
                                                          结果在这里才可用
$addq %rax, %rbx        →$取指 $→$译码(需要$%rax) → ...$
                                     ↑
                                    这里需要结果,但内存还没读完

关键问题:加载指令的结果在访存阶段末尾才从内存读取到 valM,而需要该结果的指令在译码阶段就需要它——一个时钟周期内,从访存阶段的输出无法及时转发到译码阶段的输入。

解决方案:暂停 + 转发

Y86-64 流水线处理加载使用冒险的策略是暂停一个周期 + 转发

  1. 暂停:检测到加载使用冒险后,将加载指令后的那条指令暂停一个周期(将其冻结在译码阶段)
  2. 转发:暂停的一个周期里,加载指令完成了访存阶段,valM 可用;在下一个周期通过转发路径将 valM 传递给需要它的指令
周期1: [取指 mrmovq] [译码] [执行] [访存] [写回]
周期2: [暂停]       [取指] [译码] [执行] [访存] (本条指令被冻结)
周期3: [下一指令]   [取指] [译码] [执行] [访存]
                                        ↑ 转发 valM

检测条件

加载使用冒险的检测条件:

(mrmovq或 popq在译码阶段 $→$流水线状态为 S)
&& (S_dstM == d_srcA 或 S_dstM == d_srcB)
&& (d_srcA 或 d_srcB != 0xF)

当条件满足时,流水线控制逻辑插入一个气泡并冻结译码阶段和取指阶段的寄存器。

性能影响

每个加载使用冒险导致流水线丧失一个周期的吞吐量。编译器优化中,通过重新排列指令顺序可以在一定程度上避免加载使用冒险(在加载指令和其他使用该加载结果的指令之间插入无关指令)。

相关笔记

链接到