CS152 · 第 13 课

Out-of-order Execution II:多发射重命名与访存乱序

这一课把第 12 课的重命名机制从"每周期一条指令"扩展到"每周期多条指令",然后转向乱序执行里最容易被忽视、却往往是继控制冒险之后第二大瓶颈的问题:访存指令能不能也乱序执行?

授课:Sophia Shao 预计用时:55 分钟 难度:较难

超标量寄存器重命名:同一周期内的指令也可能互相依赖

把重命名逻辑扩展到每周期重命名 N 条指令,只需要给重命名表和空闲寄存器列表增加额外的读写端口——但这样"能直接工作吗"?答案是:还必须额外检查同一周期内发射的指令之间的 RAW 冒险——例如第 2 条指令的源寄存器恰好是第 1 条指令要写的目的寄存器。解决办法是用"=?"比较器与重命名表查找并行进行:如果匹配,就用旁路多路选择器把第 1 条指令刚分配的标签直接转发给第 2 条指令,而不是让它去查(此时还未更新的)重命名表。真实例子:MIPS R10K 每周期可以重命名 4 条彼此存在 RAW 依赖的指令。


Load-Store Queue:访存乱序的核心结构

课程明确指出:继控制冒险之后,访存数据冒险是限制超标量性能的第二大瓶颈。现代超标量处理器普遍采用精细的 load/store 重排序机制,通过推测性地提前发射 load 来降低有效访存延迟。

推测性存储缓冲区(Speculative Store Buffer):store 在提交之前绝不能真正修改内存;一个推测性存储缓冲区持有尚未提交的 store 地址/数据(字段 V、S[推测位]、Tag、Data);store 被拆成"store address"和"store data"两个微操作(地址微操作写 Tag 字段,数据微操作写 Data 字段)。Store 提交的条件是:它是程序顺序中最旧的未提交指令,且地址和数据都已就绪——此时清除推测位,数据最终写入 L1 数据缓存。Store 中止(分支预测错误或异常回滚时)只需清除该缓冲区条目的有效位。

Load 如何从推测性存储缓冲区"旁路"取数:两个具体设计问题都有明确答案——如果同一个地址的数据同时存在于存储缓冲区和数据缓存中,应该使用存储缓冲区里的值(而不是缓存里可能过时的旧值);如果存储缓冲区里对同一地址有多个待处理的 store,应该使用程序顺序上最年轻、但仍然早于该 load 的那一个 store。


Load 什么时候可以安全执行?三种递进策略

以 sd x1,(x2) 之后紧跟 ld x3,(x4) 为例:

内存依赖预测(真实例子:Alpha 21264):在地址推测出错之后,把那条具体的(静态)load 指令标记为"store-wait";此后这条指令的每一次动态执行都会保守地等待所有更早的 store 完成;这个标记会被周期性清除,以便在冒险只是暂时性的情况下重新尝试推测。


常见误区


知识检查

问题 1:"保守式乱序 load 执行"和"地址推测"这两种策略的关键区别是什么?

问题 2:如果同一个地址的数据同时存在于推测性存储缓冲区和数据缓存中,load 应该使用哪一份数据?

问题 3:Alpha 21264 的"store-wait"位机制具体解决了什么问题?


本课要点

超标量重命名

需要额外检查同一周期内指令之间的 RAW 依赖

推测性存储缓冲区

store 拆成地址/数据两个微操作,最旧且就绪才提交

Load 执行的三种策略

顺序队列 → 保守乱序(地址已知不等)→ 地址推测(赌一把)

内存依赖预测

Alpha 21264 的 store-wait 位,从错误中学习


参考资料与延伸阅读